diff --git a/packages/suite-desktop-core/src/app.ts b/packages/suite-desktop-core/src/app.ts index 6a609ed0b50..49009a7d19c 100644 --- a/packages/suite-desktop-core/src/app.ts +++ b/packages/suite-desktop-core/src/app.ts @@ -18,7 +18,7 @@ import { clearAppCache, initUserData } from './libs/user-data'; import { initSentry } from './libs/sentry'; import { initModules, mainThreadEmitter } from './modules'; import { init as initTorModule } from './modules/tor'; -import { init as initBridgeModule } from './modules/bridge'; +import { init as initBridgeModule, initUi as initBridgeUi } from './modules/bridge'; import { createInterceptor } from './libs/request-interceptor'; import { hangDetect } from './hang-detect'; import { Logger } from './libs/logger'; @@ -186,6 +186,13 @@ const initUi = async ({ interceptor, mainThreadEmitter, }); + // TODO: each module probably should have 2 exports - one to be initiated in the main layer and one to be initiated in UI layer? + initBridgeUi({ + mainWindowProxy, + store, + interceptor, + mainThreadEmitter, + }); app.on('second-instance', () => { // Someone tried to run a second instance, we should focus our window. diff --git a/packages/suite-desktop-core/src/modules/bridge.ts b/packages/suite-desktop-core/src/modules/bridge.ts index 0ee9b362f4b..196b2394a9a 100644 --- a/packages/suite-desktop-core/src/modules/bridge.ts +++ b/packages/suite-desktop-core/src/modules/bridge.ts @@ -59,24 +59,16 @@ class TrezordNodeProcess implements BridgeInterface { } status() { + if (!this.proxy.running) { + return Promise.resolve({ service: false, process: false }); + } + return this.proxy .request('status', []) .catch(() => ({ service: false, process: this.proxy.running })); } } -const handleBridgeStatus = async (bridge: BridgeInterface) => { - const { logger } = global; - - logger.info('bridge', `Getting status`); - const status = await bridge.status(); - logger.info('bridge', `Toggling bridge. Status: ${JSON.stringify(status)}`); - - ipcMain.emit('bridge/status', status); - - return status; -}; - const start = async (bridge: BridgeInterface) => { if (bridgeLegacy) { await bridge.start(); @@ -112,66 +104,16 @@ const shouldUseLegacyBridge = (store: Dependencies['store']) => { return legacyBridgeReasonRollout; }; -const load = async (bridge: BridgeInterface, store: Dependencies['store']) => { - const { logger } = global; - - ipcMain.handle('bridge/toggle', async ipcEvent => { - validateIpcMessage(ipcEvent); - - const status = await handleBridgeStatus(bridge); - try { - if (status.service) { - await bridge.stop(); - } else { - await start(bridge); - } - - return { success: true }; - } catch (error) { - return { success: false, error }; - } finally { - handleBridgeStatus(bridge); - } - }); - - ipcMain.handle('bridge/get-status', async ipcEvent => { - validateIpcMessage(ipcEvent); - - try { - const status = await bridge.status(); - - return { success: true, payload: status }; - } catch (error) { - return { success: false, error }; - } - }); - - ipcMain.handle( - 'bridge/change-settings', - (ipcEvent, payload: { doNotStartOnStartup: boolean; legacy?: boolean }) => { - validateIpcMessage(ipcEvent); - - try { - store.setBridgeSettings(payload); +let bridge: BridgeInterface; +let legacyBridge: BridgeInterface; +let nodeBridge: BridgeInterface; - return { success: true }; - } catch (error) { - return { success: false, error }; - } finally { - ipcMain.emit('bridge/settings', store.getBridgeSettings()); - } - }, - ); - - ipcMain.handle('bridge/get-settings', ipcEvent => { - validateIpcMessage(ipcEvent); +const loadBridge = async (store: Dependencies['store']) => { + const { logger } = global; + legacyBridge = new BridgeProcess(); + nodeBridge = new TrezordNodeProcess(); - try { - return { success: true, payload: store.getBridgeSettings() }; - } catch (error) { - return { success: false, error }; - } - }); + bridge = shouldUseLegacyBridge(store) ? legacyBridge : nodeBridge; if (store.getBridgeSettings().doNotStartOnStartup) { return; @@ -183,7 +125,6 @@ const load = async (bridge: BridgeInterface, store: Dependencies['store']) => { `Starting (Legacy: ${b2t(bridgeLegacy)}, Test: ${b2t(bridgeTest)}, Dev: ${b2t(bridgeDev)})`, ); await start(bridge); - handleBridgeStatus(bridge); } catch (err) { bridge.stop(); logger.error(SERVICE_NAME, `Start failed: ${err.message}`); @@ -197,15 +138,12 @@ type BridgeModule = ({ store }: Pick) => { export const init: BridgeModule = ({ store }) => { let loaded = false; - let bridge: BridgeInterface; const onLoad = () => { if (loaded) return; loaded = true; - bridge = shouldUseLegacyBridge(store) ? new BridgeProcess() : new TrezordNodeProcess(); - - return scheduleAction(() => load(bridge, store), { timeout: 3000 }).catch(err => { + return scheduleAction(() => loadBridge(store), { timeout: 3000 }).catch(err => { // Error ignored, user will see transport error afterwards logger.error(SERVICE_NAME, `Failed to load: ${err.message}`); }); @@ -217,3 +155,90 @@ export const init: BridgeModule = ({ store }) => { return { onLoad, onQuit }; }; + +export const initUi = ({ store, mainWindowProxy }: Dependencies) => { + ipcMain.handle( + 'bridge/change-settings', + async (ipcEvent, payload: { doNotStartOnStartup: boolean; legacy?: boolean }) => { + validateIpcMessage(ipcEvent); + + const oldSettings = store.getBridgeSettings(); + + try { + store.setBridgeSettings(payload); + + return { success: true }; + } catch (error) { + return { success: false, error }; + } finally { + const newSettings = store.getBridgeSettings(); + + if (oldSettings.legacy !== payload.legacy) { + const wasBridgeRunning = await bridge.status(); + if (wasBridgeRunning.service) { + await bridge.stop(); + } + bridge = shouldUseLegacyBridge(store) ? legacyBridge : nodeBridge; + if (wasBridgeRunning.service) { + await start(bridge); + } + } + + mainWindowProxy?.getInstance()?.webContents.send('bridge/settings', newSettings); + } + }, + ); + + ipcMain.handle('bridge/get-settings', ipcEvent => { + validateIpcMessage(ipcEvent); + + try { + return { success: true, payload: store.getBridgeSettings() }; + } catch (error) { + return { success: false, error }; + } + }); + + const handleBridgeStatus = async () => { + const { logger } = global; + + logger.info('bridge', `Getting status`); + const status = await bridge.status(); + logger.info('bridge', `Toggling bridge. Status: ${JSON.stringify(status)}`); + + mainWindowProxy.getInstance()?.webContents.send('bridge/status', status); + + return status; + }; + + ipcMain.handle('bridge/toggle', async ipcEvent => { + validateIpcMessage(ipcEvent); + + const status = await handleBridgeStatus(); + try { + if (status.service) { + await bridge.stop(); + } else { + await start(bridge); + } + + return { success: true }; + } catch (error) { + return { success: false, error }; + } finally { + handleBridgeStatus(); + } + }); + + ipcMain.handle('bridge/get-status', async ipcEvent => { + validateIpcMessage(ipcEvent); + + try { + const status = await bridge.status(); + + return { success: true, payload: status }; + } catch (error) { + return { success: false, error }; + } + }); +}; diff --git a/packages/suite/src/views/settings/SettingsDebug/TransportBackends.tsx b/packages/suite/src/views/settings/SettingsDebug/TransportBackends.tsx index b2dac0e2adb..cd26f4ad841 100644 --- a/packages/suite/src/views/settings/SettingsDebug/TransportBackends.tsx +++ b/packages/suite/src/views/settings/SettingsDebug/TransportBackends.tsx @@ -18,6 +18,7 @@ const NEW_BRIDGE_ROLLOUT_THRESHOLD = 0; export const TransportBackends = () => { const allowPrerelease = useSelector(state => state.desktopUpdate.allowPrerelease); + const transport = useSelector(state => state.suite.transport); const [bridgeProcess, setBridgeProcess] = useState({ service: false, process: false }); const [bridgeSettings, setBridgeSettings] = useState(null); const [error, setError] = useState(null); @@ -68,10 +69,15 @@ export const TransportBackends = () => { /> - + { desktopApi.toggleBridge(); }} @@ -80,7 +86,7 @@ export const TransportBackends = () => { @@ -96,7 +102,10 @@ export const TransportBackends = () => { - +