From 539650e47581f1ca02fe2412ed9c11c6f011ae60 Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Tue, 17 Sep 2024 16:45:28 +0200 Subject: [PATCH] Add Metered connection and usability check --- locales/en/messages.json | 4 ++++ src/js/Sponsor.js | 5 +++-- src/js/serial_backend.js | 3 ++- src/js/tabs/cli.js | 3 ++- src/js/tabs/firmware_flasher.js | 7 ++++--- src/js/tabs/gps.js | 7 ++++--- src/js/tabs/options.js | 12 ++++++++++- src/js/tabs/setup.js | 5 +++-- src/js/utils/connection.js | 35 +++++++++++++++++++++++++++++++++ src/tabs/options.html | 6 ++++++ 10 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 src/js/utils/connection.js diff --git a/locales/en/messages.json b/locales/en/messages.json index e6b9710981a..5f201d1888e 100755 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -138,6 +138,10 @@ "rememberLastTab": { "message": "Reopen last tab on connect" }, + "meteredConnection": { + "message": "Metered connection (has data limits or can incur charges)", + "description": "Text for the option to enable or disable metered connection" + }, "analyticsOptOut": { "message": "Opt out of the anonymised collection of statistics data" }, diff --git a/src/js/Sponsor.js b/src/js/Sponsor.js index 99b2e5ef36d..8f8cc0a34ee 100644 --- a/src/js/Sponsor.js +++ b/src/js/Sponsor.js @@ -1,15 +1,16 @@ import BuildApi from './BuildApi'; import DarkTheme from './DarkTheme'; +import { ispConnected } from './utils/connection'; export default class Sponsor { constructor () { this._api = new BuildApi(); - this._timer = setInterval(() => { this.Refresh(); }, 30000); + this._timer = ispConnected() ? setInterval(() => { this.Refresh(); }, 30000) : null; } Refresh() { - if (!navigator.onLine) { + if (!ispConnected()) { return; } diff --git a/src/js/serial_backend.js b/src/js/serial_backend.js index ca672ec6dbe..e2e749a9c3a 100644 --- a/src/js/serial_backend.js +++ b/src/js/serial_backend.js @@ -25,6 +25,7 @@ import BuildApi from "./BuildApi"; import { serialShim } from "./serial_shim.js"; import { EventBus } from "../components/eventBus"; +import { ispConnected } from "./utils/connection"; let serial = serialShim(); @@ -491,7 +492,7 @@ async function processBuildOptions() { // firmware 1_45 or higher is required to support cloud build options // firmware 1_46 or higher retrieves build options from the flight controller - if (supported && FC.CONFIG.buildKey.length === 32 && navigator.onLine) { + if (supported && FC.CONFIG.buildKey.length === 32 && ispConnected()) { const buildApi = new BuildApi(); function onLoadCloudBuild(options) { diff --git a/src/js/tabs/cli.js b/src/js/tabs/cli.js index 205c38e2fad..a161c5e5e9c 100644 --- a/src/js/tabs/cli.js +++ b/src/js/tabs/cli.js @@ -12,6 +12,7 @@ import jBox from "jbox"; import $ from 'jquery'; import { serialShim } from "../serial_shim"; import FileSystem from "../FileSystem"; +import { ispConnected } from "../utils/connection"; const serial = serialShim(); @@ -229,7 +230,7 @@ cli.initialize = function (callback) { }); $('a.support') - .toggle(navigator.onLine) + .toggle(ispConnected()) .on('click', function() { function submitSupportData(data) { diff --git a/src/js/tabs/firmware_flasher.js b/src/js/tabs/firmware_flasher.js index 16b2815bb12..2a0f444fc71 100644 --- a/src/js/tabs/firmware_flasher.js +++ b/src/js/tabs/firmware_flasher.js @@ -18,6 +18,7 @@ import DFU from '../protocols/webusbdfu'; import AutoBackup from '../utils/AutoBackup.js'; import AutoDetect from '../utils/AutoDetect.js'; import { EventBus } from "../../components/eventBus"; +import { ispConnected } from '../utils/connection.js'; const firmware_flasher = { targets: null, @@ -147,7 +148,7 @@ firmware_flasher.initialize = function (callback) { } function loadTargetList(targets) { - if (!targets || !navigator.onLine) { + if (!targets || !ispConnected()) { $('select[name="board"]').empty().append(''); $('select[name="firmware_version"]').empty().append(''); @@ -214,7 +215,7 @@ firmware_flasher.initialize = function (callback) { } function buildOptions(data) { - if (!navigator.onLine) { + if (!ispConnected()) { return; } @@ -1142,7 +1143,7 @@ firmware_flasher.initialize = function (callback) { firmware_flasher.validateBuildKey = function() { - return this.cloudBuildKey?.length === 32 && navigator.onLine; + return this.cloudBuildKey?.length === 32 && ispConnected(); }; firmware_flasher.cleanup = function (callback) { diff --git a/src/js/tabs/gps.js b/src/js/tabs/gps.js index 3ab9cfbdc4e..3a56c6b6776 100644 --- a/src/js/tabs/gps.js +++ b/src/js/tabs/gps.js @@ -11,6 +11,7 @@ import { mspHelper } from '../msp/MSPHelper'; import { updateTabList } from '../utils/updateTabList'; import { initMap } from './map'; import { fromLonLat } from "ol/proj"; +import { ispConnected } from "../utils/connection"; const gps = {}; @@ -352,7 +353,7 @@ gps.initialize = async function (callback) { let gpsFoundPosition = false; - if (navigator.onLine) { + if (ispConnected()) { $('#connect').hide(); gpsFoundPosition = !!(lon && lat); @@ -382,7 +383,7 @@ gps.initialize = async function (callback) { }, 75, true); //check for internet connection on load - if (navigator.onLine) { + if (ispConnected()) { console.log('Online'); set_online(); } else { @@ -391,7 +392,7 @@ gps.initialize = async function (callback) { } $("#check").on('click',function(){ - if (navigator.onLine) { + if (ispConnected()) { console.log('Online'); set_online(); } else { diff --git a/src/js/tabs/options.js b/src/js/tabs/options.js index 67f1800020a..7579379118a 100644 --- a/src/js/tabs/options.js +++ b/src/js/tabs/options.js @@ -7,7 +7,6 @@ import DarkTheme, { setDarkTheme } from '../DarkTheme'; import { checkForConfiguratorUpdates } from '../utils/checkForConfiguratorUpdates'; import { checkSetupAnalytics } from '../Analytics'; import $ from 'jquery'; -import CONFIGURATOR from '../data_storage'; const options = {}; options.initialize = function (callback) { @@ -30,6 +29,7 @@ options.initialize = function (callback) { TABS.options.initShowDevToolsOnStartup(); TABS.options.initShowNotifications(); TABS.options.initShowWarnings(); + TABS.options.initMeteredConnection(); GUI.content_ready(callback); }); @@ -192,6 +192,16 @@ options.initShowNotifications = function () { .change(); }; +options.initMeteredConnection = function () { + const result = getConfig("meteredConnection"); + $("div.meteredConnection input") + .prop("checked", !!result.meteredConnection) + .change(function () { + setConfig({ meteredConnection: $(this).is(":checked") }); + }) + .change(); +}; + // TODO: remove when modules are in place TABS.options = options; export { options }; diff --git a/src/js/tabs/setup.js b/src/js/tabs/setup.js index b0fd9c4faa8..af22b018603 100644 --- a/src/js/tabs/setup.js +++ b/src/js/tabs/setup.js @@ -11,6 +11,7 @@ import MSPCodes from '../msp/MSPCodes'; import { API_VERSION_1_45, API_VERSION_1_46 } from '../data_storage'; import { gui_log } from '../gui_log'; import $ from 'jquery'; +import { ispConnected } from '../utils/connection'; const setup = { yaw_fix: 0.0, @@ -411,7 +412,7 @@ setup.initialize = function (callback) { const showBuildInfo = function() { const supported = FC.CONFIG.buildKey.length === 32; - if (supported && navigator.onLine) { + if (supported && ispConnected()) { const buildRoot = `https://build.betaflight.com/api/builds/${FC.CONFIG.buildKey}`; const buildConfig = ` ${i18n.getMessage('initialSetupInfoBuildConfig')}`; @@ -426,7 +427,7 @@ setup.initialize = function (callback) { }; const showBuildOptions = function() { - const supported = (semver.eq(FC.CONFIG.apiVersion, API_VERSION_1_45) && navigator.onLine || semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_46)) && FC.CONFIG.buildOptions.length; + const supported = (semver.eq(FC.CONFIG.apiVersion, API_VERSION_1_45) && ispConnected() || semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_46)) && FC.CONFIG.buildOptions.length; if (supported) { let buildOptionList = `
`; diff --git a/src/js/utils/connection.js b/src/js/utils/connection.js new file mode 100644 index 00000000000..72f39a0b14f --- /dev/null +++ b/src/js/utils/connection.js @@ -0,0 +1,35 @@ +import { get as getConfig } from "../ConfigStorage"; + +export function ispConnected() { + + const isMetered = getConfig('meteredConnection').meteredConnection; + const connected = navigator.onLine; + const type = navigator.connection.effectiveType; + const downlink = navigator.connection.downlink; + const rtt = navigator.connection.rtt; + const logHead = '[ISP] '; + + if (navigator.connection) { + console.log(`${logHead}Effective network type: ${navigator.connection.effectiveType}`); + console.log(`${logHead}Downlink Speed: ${navigator.connection.downlink}Mb/s`); + console.log(`${logHead}Round Trip Time: ${navigator.connection.rtt}ms`); + } else { + console.log(`${logHead}Navigator Connection API not supported`); + } + + if (isMetered) { + console.log(`${logHead}Metered connection is enabled`); + return false; + } + + if (type === 'slow-2g' || type === '2g' || downlink < 0.115 || rtt > 1000) { + console.log(`${logHead}Slow network detected`); + return false; + } + + if (connected) { + console.log(`${logHead}Connected to the internet`); + return true; + } +} + diff --git a/src/tabs/options.html b/src/tabs/options.html index fc967ef8fa7..3dfa502cee6 100644 --- a/src/tabs/options.html +++ b/src/tabs/options.html @@ -17,6 +17,12 @@
+
+
+ +
+ +