store.ts
1 import { bindActionCreators } from 'redux'; 2 3 import { shepherdProvider, getShepherdPending, getShepherdOffline } from 'libs/nodes'; 4 import { setOffline, setOnline, getOffline } from 'features/config'; 5 import { notificationsActions } from 'features/notifications'; 6 import handleMetaMaskPolling, { METAMASK_POLLING_INTERVAL } from './handleMetaMaskPolling'; 7 import configureStore from './configureStore'; 8 9 const store = configureStore(); 10 11 window.addEventListener('load', () => { 12 const getShepherdStatus = () => ({ 13 pending: getShepherdPending(), 14 isOnline: !getShepherdOffline() 15 }); 16 17 const { online, offline, lostNetworkNotif, offlineNotif, restoreNotif } = bindActionCreators( 18 { 19 offline: setOffline, 20 online: setOnline, 21 restoreNotif: () => 22 notificationsActions.showNotification( 23 'success', 24 'Your connection to the network has been restored!', 25 3000 26 ), 27 lostNetworkNotif: () => 28 notificationsActions.showNotification( 29 'danger', 30 `You’ve lost your connection to the network, check your internet 31 connection or try changing networks from the dropdown at the 32 top right of the page.`, 33 Infinity 34 ), 35 36 offlineNotif: () => 37 notificationsActions.showNotification( 38 'info', 39 'You are currently offline. Some features will be unavailable.', 40 5000 41 ) 42 }, 43 store.dispatch 44 ); 45 46 const getAppOnline = () => !getOffline(store.getState()); 47 48 /** 49 * @description Repeatedly polls itself to check for online state conflict occurs, implemented in recursive style for flexible polling times 50 * as network requests take a variable amount of time. 51 * 52 * Whenever an app online state conflict occurs, it resolves the conflict with the following priority: 53 * * If shepherd is online but app is offline -> do a ping request via shepherd provider, with the result of the ping being the set app state 54 * * If shepherd is offline but app is online -> set app to offline as it wont be able to make requests anyway 55 */ 56 async function detectOnlineStateConflict() { 57 const shepherdStatus = getShepherdStatus(); 58 const appOffline = getAppOnline(); 59 const onlineStateConflict = shepherdStatus.isOnline !== appOffline; 60 61 if (shepherdStatus.pending || !onlineStateConflict) { 62 return setTimeout(detectOnlineStateConflict, 1000); 63 } 64 65 // if app reports online but shepherd offline, then set app offline 66 if (appOffline && !shepherdStatus.isOnline) { 67 lostNetworkNotif(); 68 offline(); 69 } else if (!appOffline && shepherdStatus.isOnline) { 70 // if app reports offline but shepherd reports online 71 // send a request to shepherd provider to see if we can still send out requests 72 const success = await shepherdProvider.ping().catch(() => false); 73 if (success) { 74 restoreNotif(); 75 online(); 76 } 77 } 78 detectOnlineStateConflict(); 79 } 80 detectOnlineStateConflict(); 81 82 window.addEventListener('offline', () => { 83 const previouslyOnline = getAppOnline(); 84 85 // if browser reports as offline and we were previously online 86 // then set offline without checking balancer state 87 if (!navigator.onLine && previouslyOnline) { 88 offlineNotif(); 89 offline(); 90 } 91 }); 92 }); 93 94 /** @desc When MetaMask is loaded as an extension, watch for network changes. */ 95 if ((window as any).web3) { 96 setInterval(handleMetaMaskPolling.bind(null, store), METAMASK_POLLING_INTERVAL); 97 } 98 99 export default store;