From 6b1bf7db20cb292482193d3cd6f8c8df6d0cfb6a Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 5 Oct 2020 10:47:43 -0700 Subject: [PATCH 1/8] move reconnect logic into Connection namespace --- src/lib/API.js | 49 +++---------------------- src/lib/Activity/index.js | 7 ---- src/lib/Activity/index.native.js | 22 ------------ src/lib/Network.js | 58 ------------------------------ src/lib/actions/PersonalDetails.js | 3 +- src/lib/actions/Report.js | 3 +- src/lib/actions/SignInRedirect.js | 2 ++ src/page/home/HomePage.js | 2 ++ 8 files changed, 13 insertions(+), 133 deletions(-) delete mode 100644 src/lib/Activity/index.js delete mode 100644 src/lib/Activity/index.native.js delete mode 100644 src/lib/Network.js diff --git a/src/lib/API.js b/src/lib/API.js index 881628585124b..d39c36ebaa61b 100644 --- a/src/lib/API.js +++ b/src/lib/API.js @@ -1,17 +1,14 @@ import _ from 'underscore'; import Ion from './Ion'; import IONKEYS from '../IONKEYS'; -import {xhr, setOfflineStatus} from './Network'; +import xhr from './xhr'; +import Connection from './Connection'; import CONFIG from '../CONFIG'; import * as Pusher from './Pusher/pusher'; import ROUTES from '../ROUTES'; import Str from './Str'; import Guid from './Guid'; import redirectToSignIn from './actions/SignInRedirect'; -import Activity from './Activity'; - -// Holds all of the callbacks that need to be triggered when the network reconnects -const reconnectionCallbacks = []; // Queue for network requests so we don't lose actions done by the user while offline let networkRequestQueue = []; @@ -27,37 +24,12 @@ Ion.connect({ callback: val => authToken = val ? val.authToken : null, }); -/** - * Loop over all reconnection callbacks and fire each one - */ -function triggerReconnectionCallbacks() { - _.each(reconnectionCallbacks, callback => callback()); -} - // We subscribe to changes to the online/offline status of the network to determine when we should fire off API calls -// vs queueing them for later. When reconnecting, ie, going from offline to online, all the reconnection callbacks -// are triggered (this is usually Actions that need to re-download data from the server) +// vs queueing them for later. let isOffline; Ion.connect({ key: IONKEYS.NETWORK, - callback: (val) => { - if (isOffline && !val.isOffline) { - triggerReconnectionCallbacks(); - } - isOffline = val && val.isOffline; - } -}); - -// When the app is in the background Pusher can still receive realtime updates -// for a few minutes, but eventually disconnects causing a delay when the app -// returns from the background. So, if we are returning from the background -// and we are online we should trigger our reconnection callbacks. -Activity.registerOnAppBecameActiveCallback(() => { - if (isOffline) { - return; - } - - triggerReconnectionCallbacks(); + callback: val => isOffline = val ? val.isOffline : null, }); // When the user authenticates for the first time we create a login and store credentials in Ion. @@ -251,7 +223,7 @@ function processNetworkRequestQueue() { // Make a simple request every second to see if the API is online again xhr('Get', {doNotRetry: true}) - .then(() => setOfflineStatus(false)); + .then(() => Connection.setOfflineStatus(false)); return; } @@ -327,16 +299,6 @@ Pusher.registerSocketEventCallback((eventName) => { } }); -/** - * Register a callback function to be called when the network reconnects - * - * @public - * @param {function} cb - */ -function onReconnect(cb) { - reconnectionCallbacks.push(cb); -} - /** * Get the authToken that the network uses * @returns {string} @@ -480,6 +442,5 @@ export { getAuthToken, getPersonalDetails, getReportHistory, - onReconnect, setLastReadActionID, }; diff --git a/src/lib/Activity/index.js b/src/lib/Activity/index.js deleted file mode 100644 index 7667948125b97..0000000000000 --- a/src/lib/Activity/index.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * On web/desktop we don't really care if the app becomes - * active or inactive as long as Pusher is always connected - */ -export default { - registerOnAppBecameActiveCallback: () => {}, -}; diff --git a/src/lib/Activity/index.native.js b/src/lib/Activity/index.native.js deleted file mode 100644 index 6d5505089c545..0000000000000 --- a/src/lib/Activity/index.native.js +++ /dev/null @@ -1,22 +0,0 @@ -import {AppState} from 'react-native'; - -let onAppBecameActiveCallback; - -AppState.addEventListener('change', (state) => { - if (state === 'active') { - onAppBecameActiveCallback(); - } -}); - -/** - * Register active state change callback - * - * @param {Function} callback - */ -function registerOnAppBecameActiveCallback(callback) { - onAppBecameActiveCallback = callback; -} - -export default { - registerOnAppBecameActiveCallback, -}; diff --git a/src/lib/Network.js b/src/lib/Network.js deleted file mode 100644 index 01ba8544da007..0000000000000 --- a/src/lib/Network.js +++ /dev/null @@ -1,58 +0,0 @@ -import _ from 'underscore'; -import NetInfo from '@react-native-community/netinfo'; -import Ion from './Ion'; -import CONFIG from '../CONFIG'; -import IONKEYS from '../IONKEYS'; - -/** - * Called when the offline status of the app changes and if the network is "reconnecting" (going from offline to online) - * then all of the reconnection callbacks are triggered - * - * @param {boolean} isCurrentlyOffline - */ -function setOfflineStatus(isCurrentlyOffline) { - Ion.merge(IONKEYS.NETWORK, {isOffline: isCurrentlyOffline}); -} - -// Subscribe to the state change event via NetInfo so we can update -// whether a user has internet connectivity or not. This is more reliable -// than the Pusher `disconnected` event which takes about 10-15 seconds to emit -NetInfo.addEventListener((state) => { - setOfflineStatus(!state.isConnected); -}); - -/** - * Makes XHR request - * @param {String} command the name of the API command - * @param {Object} data parameters for the API command - * @param {String} type HTTP request type (get/post) - * @returns {Promise} - */ -function xhr(command, data, type = 'post') { - const formData = new FormData(); - _.each(data, (val, key) => formData.append(key, val)); - - return fetch(`${CONFIG.EXPENSIFY.API_ROOT}command=${command}`, { - method: type, - body: formData, - }) - .then(response => response.json()) - - // This will catch any HTTP network errors (like 404s and such), not to be confused with jsonCode which this - // does NOT catch - .catch(() => { - setOfflineStatus(true); - - // Set an error state and signify we are done loading - Ion.merge(IONKEYS.SESSION, {loading: false, error: 'Cannot connect to server'}); - - // Throw a new error to prevent any other `then()` in the promise chain from being triggered (until another - // catch() happens - throw new Error('API is offline'); - }); -} - -export { - xhr, - setOfflineStatus, -}; diff --git a/src/lib/actions/PersonalDetails.js b/src/lib/actions/PersonalDetails.js index f22c00c873f81..c664f4b26d56e 100644 --- a/src/lib/actions/PersonalDetails.js +++ b/src/lib/actions/PersonalDetails.js @@ -5,6 +5,7 @@ import * as API from '../API'; import IONKEYS from '../../IONKEYS'; import md5 from '../md5'; import CONST from '../../CONST'; +import Connection from '../Connection'; let currentUserEmail; Ion.connect({ @@ -138,7 +139,7 @@ function getForEmails(emailList) { } // When the app reconnects from being offline, fetch all of the personal details -API.onReconnect(fetch); +Connection.onReconnect(fetch); export { fetch, diff --git a/src/lib/actions/Report.js b/src/lib/actions/Report.js index 08149e09e8325..784946fee81c0 100644 --- a/src/lib/actions/Report.js +++ b/src/lib/actions/Report.js @@ -13,6 +13,7 @@ import * as PersonalDetails from './PersonalDetails'; import {redirect} from './App'; import * as ActiveClientManager from '../ActiveClientManager'; import Visibility from '../Visibility'; +import Connection from '../Connection'; let currentUserEmail; let currentUserAccountID; @@ -499,7 +500,7 @@ Ion.connect({ }); // When the app reconnects from being offline, fetch all of the reports and their actions -API.onReconnect(() => { +Connection.onReconnect(() => { fetchAll(false, true); }); diff --git a/src/lib/actions/SignInRedirect.js b/src/lib/actions/SignInRedirect.js index 3acce8dfc1e45..b68d9a20e2a0c 100644 --- a/src/lib/actions/SignInRedirect.js +++ b/src/lib/actions/SignInRedirect.js @@ -3,6 +3,7 @@ import IONKEYS from '../../IONKEYS'; import ROUTES from '../../ROUTES'; import {redirect} from './App'; import * as Pusher from '../Pusher/pusher'; +import Connection from '../Connection'; let currentURL; Ion.connect({ @@ -17,6 +18,7 @@ Ion.connect({ * @param {String} [errorMessage] error message to be displayed on the sign in page */ function redirectToSignIn(errorMessage) { + Connection.destroy(); Pusher.disconnect(); Ion.clear() .then(() => { diff --git a/src/page/home/HomePage.js b/src/page/home/HomePage.js index 999e67f5f2f3a..8e790b525d528 100644 --- a/src/page/home/HomePage.js +++ b/src/page/home/HomePage.js @@ -15,6 +15,7 @@ import Main from './MainView'; import {subscribeToReportCommentEvents, fetchAll as fetchAllReports} from '../../lib/actions/Report'; import {fetch as fetchPersonalDetails} from '../../lib/actions/PersonalDetails'; import * as Pusher from '../../lib/Pusher/pusher'; +import Connection from '../../lib/Connection'; const windowSize = Dimensions.get('window'); const widthBreakPoint = 1000; @@ -36,6 +37,7 @@ export default class App extends React.Component { } componentDidMount() { + Connection.init(); Pusher.init().then(subscribeToReportCommentEvents); // Fetch all the personal details From 92720b6de7c41e07810b49d2b371a438cd9011a8 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 5 Oct 2020 10:48:00 -0700 Subject: [PATCH 2/8] add xhr and Connection files --- src/lib/Connection.js | 93 +++++++++++++++++++++++++++++++++++++++++++ src/lib/xhr.js | 38 ++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/lib/Connection.js create mode 100644 src/lib/xhr.js diff --git a/src/lib/Connection.js b/src/lib/Connection.js new file mode 100644 index 0000000000000..5a51002b728d4 --- /dev/null +++ b/src/lib/Connection.js @@ -0,0 +1,93 @@ +import _ from 'underscore'; +import {AppState} from 'react-native'; +import NetInfo from '@react-native-community/netinfo'; +import Ion from './Ion'; +import IONKEYS from '../IONKEYS'; + +let unsubscribeFromNetInfo; +let isActive = false; +let isOffline = false; + +// Holds all of the callbacks that need to be triggered when the network reconnects +const reconnectionCallbacks = []; + +/** + * Loop over all reconnection callbacks and fire each one + */ +function triggerReconnectionCallbacks() { + _.each(reconnectionCallbacks, callback => callback()); +} + +/** + * Called when the offline status of the app changes and if the network is "reconnecting" (going from offline to online) + * then all of the reconnection callbacks are triggered + * + * @param {boolean} isCurrentlyOffline + */ +function setOfflineStatus(isCurrentlyOffline) { + Ion.merge(IONKEYS.NETWORK, {isOffline: isCurrentlyOffline}); + + // When reconnecting, ie, going from offline to online, all the reconnection callbacks + // are triggered (this is usually Actions that need to re-download data from the server) + if (isOffline && !isCurrentlyOffline) { + triggerReconnectionCallbacks(); + } + + isOffline = isCurrentlyOffline; +} + +/** + * Set up the event listener for NetInfo to tell whether the user has + * internet connectivity or not. This is more reliable than the Pusher + * `disconnected` event which takes about 10-15 seconds to emit. We + * are setting this up in a way where we can tear it down again as + * we only care about connectivity if the user is logged in. + */ +function init() { + // Subscribe to the state change event via NetInfo so we can update + // whether a user has internet connectivity or not. + unsubscribeFromNetInfo = NetInfo.addEventListener((state) => { + setOfflineStatus(!state.isConnected); + }); + + // When the app is in the background Pusher can still receive realtime updates + // for a few minutes, but eventually disconnects causing a delay when the app + // returns from the background. So, if we are returning from the background + // and we are online we should trigger our reconnection callbacks. + AppState.addEventListener('change', (state) => { + const nextStateIsActive = state === 'active'; + + // We are moving from not active to active and we are online so fire callbacks + if (!isOffline && nextStateIsActive && !isActive) { + triggerReconnectionCallbacks(); + } + + isActive = nextStateIsActive; + }); +} + +/** + * Tear down the event listeners when we are finished with them. + */ +function destroy() { + if (unsubscribeFromNetInfo) { + unsubscribeFromNetInfo(); + } + AppState.removeEventListener('change', () => {}); +} + +/** + * Register callback to fire when we reconnect + * + * @param {Function} callback + */ +function onReconnect(callback) { + reconnectionCallbacks.push(callback); +} + +export default { + setOfflineStatus, + init, + destroy, + onReconnect, +}; diff --git a/src/lib/xhr.js b/src/lib/xhr.js new file mode 100644 index 0000000000000..dcf706e2b4863 --- /dev/null +++ b/src/lib/xhr.js @@ -0,0 +1,38 @@ +import _ from 'underscore'; +import Ion from './Ion'; +import CONFIG from '../CONFIG'; +import IONKEYS from '../IONKEYS'; +import Connection from './Connection'; + +/** + * Makes XHR request + * @param {String} command the name of the API command + * @param {Object} data parameters for the API command + * @param {String} type HTTP request type (get/post) + * @returns {Promise} + */ +function xhr(command, data, type = 'post') { + const formData = new FormData(); + _.each(data, (val, key) => formData.append(key, val)); + + return fetch(`${CONFIG.EXPENSIFY.API_ROOT}command=${command}`, { + method: type, + body: formData, + }) + .then(response => response.json()) + + // This will catch any HTTP network errors (like 404s and such), not to be confused with jsonCode which this + // does NOT catch + .catch(() => { + Connection.setOfflineStatus(true); + + // Set an error state and signify we are done loading + Ion.merge(IONKEYS.SESSION, {loading: false, error: 'Cannot connect to server'}); + + // Throw a new error to prevent any other `then()` in the promise chain from being triggered (until another + // catch() happens + throw new Error('API is offline'); + }); +} + +export default xhr; From 17072ff3de67cb5a77ca9444ca5b0b8a8c1428d1 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 5 Oct 2020 11:01:16 -0700 Subject: [PATCH 3/8] add some more logs --- src/lib/Connection.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/Connection.js b/src/lib/Connection.js index 5a51002b728d4..d4d86c6cc4aa0 100644 --- a/src/lib/Connection.js +++ b/src/lib/Connection.js @@ -47,6 +47,7 @@ function init() { // Subscribe to the state change event via NetInfo so we can update // whether a user has internet connectivity or not. unsubscribeFromNetInfo = NetInfo.addEventListener((state) => { + console.debug('[NetInfo] isConnected:', state && state.isConnected); setOfflineStatus(!state.isConnected); }); @@ -55,6 +56,7 @@ function init() { // returns from the background. So, if we are returning from the background // and we are online we should trigger our reconnection callbacks. AppState.addEventListener('change', (state) => { + console.debug('[AppState] state changed:', state); const nextStateIsActive = state === 'active'; // We are moving from not active to active and we are online so fire callbacks From 00826b70ec9159aea618eb8c6df9ccce9c5eb963 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 5 Oct 2020 14:07:56 -0700 Subject: [PATCH 4/8] Rename to NetworkConnection --- src/lib/API.js | 4 ++-- src/lib/{Connection.js => NetworkConnection.js} | 14 +++++++------- src/lib/actions/PersonalDetails.js | 4 ++-- src/lib/actions/Report.js | 4 ++-- src/lib/actions/SignInRedirect.js | 4 ++-- src/lib/xhr.js | 4 ++-- src/page/home/HomePage.js | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) rename src/lib/{Connection.js => NetworkConnection.js} (90%) diff --git a/src/lib/API.js b/src/lib/API.js index d39c36ebaa61b..b2af76ea9b3b2 100644 --- a/src/lib/API.js +++ b/src/lib/API.js @@ -2,7 +2,7 @@ import _ from 'underscore'; import Ion from './Ion'; import IONKEYS from '../IONKEYS'; import xhr from './xhr'; -import Connection from './Connection'; +import NetworkConnection from './NetworkConnection'; import CONFIG from '../CONFIG'; import * as Pusher from './Pusher/pusher'; import ROUTES from '../ROUTES'; @@ -223,7 +223,7 @@ function processNetworkRequestQueue() { // Make a simple request every second to see if the API is online again xhr('Get', {doNotRetry: true}) - .then(() => Connection.setOfflineStatus(false)); + .then(() => NetworkConnection.setOfflineStatus(false)); return; } diff --git a/src/lib/Connection.js b/src/lib/NetworkConnection.js similarity index 90% rename from src/lib/Connection.js rename to src/lib/NetworkConnection.js index d4d86c6cc4aa0..8cc28f163eea0 100644 --- a/src/lib/Connection.js +++ b/src/lib/NetworkConnection.js @@ -4,6 +4,8 @@ import NetInfo from '@react-native-community/netinfo'; import Ion from './Ion'; import IONKEYS from '../IONKEYS'; +// NetInfo.addEventListener() returns a function used to unsubscribe the +// listener so we must create a reference to it and call it in stopListeningForReconnect() let unsubscribeFromNetInfo; let isActive = false; let isOffline = false; @@ -39,11 +41,9 @@ function setOfflineStatus(isCurrentlyOffline) { /** * Set up the event listener for NetInfo to tell whether the user has * internet connectivity or not. This is more reliable than the Pusher - * `disconnected` event which takes about 10-15 seconds to emit. We - * are setting this up in a way where we can tear it down again as - * we only care about connectivity if the user is logged in. + * `disconnected` event which takes about 10-15 seconds to emit. */ -function init() { +function listenForReconnect() { // Subscribe to the state change event via NetInfo so we can update // whether a user has internet connectivity or not. unsubscribeFromNetInfo = NetInfo.addEventListener((state) => { @@ -71,7 +71,7 @@ function init() { /** * Tear down the event listeners when we are finished with them. */ -function destroy() { +function stopListeningForReconnect() { if (unsubscribeFromNetInfo) { unsubscribeFromNetInfo(); } @@ -89,7 +89,7 @@ function onReconnect(callback) { export default { setOfflineStatus, - init, - destroy, + listenForReconnect, + stopListeningForReconnect, onReconnect, }; diff --git a/src/lib/actions/PersonalDetails.js b/src/lib/actions/PersonalDetails.js index c664f4b26d56e..a89b2030e8716 100644 --- a/src/lib/actions/PersonalDetails.js +++ b/src/lib/actions/PersonalDetails.js @@ -5,7 +5,7 @@ import * as API from '../API'; import IONKEYS from '../../IONKEYS'; import md5 from '../md5'; import CONST from '../../CONST'; -import Connection from '../Connection'; +import Connection from '../NetworkConnection'; let currentUserEmail; Ion.connect({ @@ -139,7 +139,7 @@ function getForEmails(emailList) { } // When the app reconnects from being offline, fetch all of the personal details -Connection.onReconnect(fetch); +NetworkConnection.onReconnect(fetch); export { fetch, diff --git a/src/lib/actions/Report.js b/src/lib/actions/Report.js index 784946fee81c0..f9608a3d73401 100644 --- a/src/lib/actions/Report.js +++ b/src/lib/actions/Report.js @@ -13,7 +13,7 @@ import * as PersonalDetails from './PersonalDetails'; import {redirect} from './App'; import * as ActiveClientManager from '../ActiveClientManager'; import Visibility from '../Visibility'; -import Connection from '../Connection'; +import NetworkConnection from '../NetworkConnection'; let currentUserEmail; let currentUserAccountID; @@ -500,7 +500,7 @@ Ion.connect({ }); // When the app reconnects from being offline, fetch all of the reports and their actions -Connection.onReconnect(() => { +NetworkConnection.onReconnect(() => { fetchAll(false, true); }); diff --git a/src/lib/actions/SignInRedirect.js b/src/lib/actions/SignInRedirect.js index b68d9a20e2a0c..8eef125029a1c 100644 --- a/src/lib/actions/SignInRedirect.js +++ b/src/lib/actions/SignInRedirect.js @@ -3,7 +3,7 @@ import IONKEYS from '../../IONKEYS'; import ROUTES from '../../ROUTES'; import {redirect} from './App'; import * as Pusher from '../Pusher/pusher'; -import Connection from '../Connection'; +import NetworkConnection from '../NetworkConnection'; let currentURL; Ion.connect({ @@ -18,7 +18,7 @@ Ion.connect({ * @param {String} [errorMessage] error message to be displayed on the sign in page */ function redirectToSignIn(errorMessage) { - Connection.destroy(); + NetworkConnection.stopListeningForReconnect(); Pusher.disconnect(); Ion.clear() .then(() => { diff --git a/src/lib/xhr.js b/src/lib/xhr.js index dcf706e2b4863..1fdb73b932da7 100644 --- a/src/lib/xhr.js +++ b/src/lib/xhr.js @@ -2,7 +2,7 @@ import _ from 'underscore'; import Ion from './Ion'; import CONFIG from '../CONFIG'; import IONKEYS from '../IONKEYS'; -import Connection from './Connection'; +import NetworkConnection from './NetworkConnection'; /** * Makes XHR request @@ -24,7 +24,7 @@ function xhr(command, data, type = 'post') { // This will catch any HTTP network errors (like 404s and such), not to be confused with jsonCode which this // does NOT catch .catch(() => { - Connection.setOfflineStatus(true); + NetworkConnection.setOfflineStatus(true); // Set an error state and signify we are done loading Ion.merge(IONKEYS.SESSION, {loading: false, error: 'Cannot connect to server'}); diff --git a/src/page/home/HomePage.js b/src/page/home/HomePage.js index 8e790b525d528..015f04b86205a 100644 --- a/src/page/home/HomePage.js +++ b/src/page/home/HomePage.js @@ -15,7 +15,7 @@ import Main from './MainView'; import {subscribeToReportCommentEvents, fetchAll as fetchAllReports} from '../../lib/actions/Report'; import {fetch as fetchPersonalDetails} from '../../lib/actions/PersonalDetails'; import * as Pusher from '../../lib/Pusher/pusher'; -import Connection from '../../lib/Connection'; +import NetworkConnection from '../../lib/NetworkConnection'; const windowSize = Dimensions.get('window'); const widthBreakPoint = 1000; @@ -37,7 +37,7 @@ export default class App extends React.Component { } componentDidMount() { - Connection.init(); + NetworkConnection.listenForReconnect(); Pusher.init().then(subscribeToReportCommentEvents); // Fetch all the personal details From d7187d86f1faa1b61f3b823bd2c4913e698900b2 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 5 Oct 2020 14:14:10 -0700 Subject: [PATCH 5/8] add sleep timer to cover case of laptop closing --- src/lib/NetworkConnection.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/lib/NetworkConnection.js b/src/lib/NetworkConnection.js index 8cc28f163eea0..2620f5e8f6b68 100644 --- a/src/lib/NetworkConnection.js +++ b/src/lib/NetworkConnection.js @@ -7,6 +7,8 @@ import IONKEYS from '../IONKEYS'; // NetInfo.addEventListener() returns a function used to unsubscribe the // listener so we must create a reference to it and call it in stopListeningForReconnect() let unsubscribeFromNetInfo; +let sleepTimer; +let lastTime; let isActive = false; let isOffline = false; @@ -66,12 +68,26 @@ function listenForReconnect() { isActive = nextStateIsActive; }); + + // When a device is put to sleep, NetInfo is not always able to detect + // when connectivity has been lost. As a failsafe we will capture the time + // every two seconds and if the last time recorded is greater than 5 seconds + // we know that the computer has been asleep. + lastTime = (new Date()).getTime(); + sleepTimer = setInterval(() => { + const currentTime = (new Date()).getTime(); + if (currentTime > (lastTime + 5000)) { + triggerReconnectionCallbacks(); + } + lastTime = currentTime; + }, 2000); } /** * Tear down the event listeners when we are finished with them. */ function stopListeningForReconnect() { + clearInterval(sleepTimer); if (unsubscribeFromNetInfo) { unsubscribeFromNetInfo(); } From 8536b979370d2a873c783612e4d7a88abc7fa903 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 5 Oct 2020 14:19:24 -0700 Subject: [PATCH 6/8] fix bad name --- src/lib/actions/PersonalDetails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/actions/PersonalDetails.js b/src/lib/actions/PersonalDetails.js index a89b2030e8716..c1829f768b26a 100644 --- a/src/lib/actions/PersonalDetails.js +++ b/src/lib/actions/PersonalDetails.js @@ -5,7 +5,7 @@ import * as API from '../API'; import IONKEYS from '../../IONKEYS'; import md5 from '../md5'; import CONST from '../../CONST'; -import Connection from '../NetworkConnection'; +import NetworkConnection from '../NetworkConnection'; let currentUserEmail; Ion.connect({ From 53c2471cfcc8a863e42774198292cbba8e248580 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 5 Oct 2020 15:17:55 -0700 Subject: [PATCH 7/8] throttle reconnection callbacks in case they are triggered by multiple sources --- src/lib/NetworkConnection.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/NetworkConnection.js b/src/lib/NetworkConnection.js index 2620f5e8f6b68..44db9a6728c65 100644 --- a/src/lib/NetworkConnection.js +++ b/src/lib/NetworkConnection.js @@ -18,9 +18,9 @@ const reconnectionCallbacks = []; /** * Loop over all reconnection callbacks and fire each one */ -function triggerReconnectionCallbacks() { +const triggerReconnectionCallbacks = _.throttle(() => { _.each(reconnectionCallbacks, callback => callback()); -} +}, 2000); /** * Called when the offline status of the app changes and if the network is "reconnecting" (going from offline to online) From 6087cc4cd14b38b4d9dca7035e9f5b5d5a08f86a Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 5 Oct 2020 15:30:20 -0700 Subject: [PATCH 8/8] only call with leading edge --- src/lib/NetworkConnection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/NetworkConnection.js b/src/lib/NetworkConnection.js index 44db9a6728c65..0e20f2f76a756 100644 --- a/src/lib/NetworkConnection.js +++ b/src/lib/NetworkConnection.js @@ -20,7 +20,7 @@ const reconnectionCallbacks = []; */ const triggerReconnectionCallbacks = _.throttle(() => { _.each(reconnectionCallbacks, callback => callback()); -}, 2000); +}, 5000, {trailing: false}); /** * Called when the offline status of the app changes and if the network is "reconnecting" (going from offline to online)