Skip to content

Commit

Permalink
fix(suite-desktop): fix bridge controls in debug menu
Browse files Browse the repository at this point in the history
  • Loading branch information
mroz22 committed Sep 27, 2024
1 parent 3a930fd commit b88e96f
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 80 deletions.
9 changes: 8 additions & 1 deletion packages/suite-desktop-core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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.
Expand Down
175 changes: 100 additions & 75 deletions packages/suite-desktop-core/src/modules/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand All @@ -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}`);
Expand All @@ -197,15 +138,12 @@ type BridgeModule = ({ store }: Pick<Dependencies, 'store'>) => {

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}`);
});
Expand All @@ -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 };
}
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -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<Process>({ service: false, process: false });
const [bridgeSettings, setBridgeSettings] = useState<BridgeSettings | null>(null);
const [error, setError] = useState<string | null>(null);
Expand Down Expand Up @@ -68,10 +69,15 @@ export const TransportBackends = () => {
/>
</SectionItem>
<SectionItem data-testid="@settings/debug/processes/Bridge">
<TextColumn title="Bridge running" />
<TextColumn
title="Bridge server"
description={
transport?.version ? `version: ${transport.version}` : 'not running'
}
/>
<ActionColumn>
<Checkbox
isChecked={bridgeProcess.process === true}
isChecked={bridgeProcess.process}
onClick={() => {
desktopApi.toggleBridge();
}}
Expand All @@ -80,7 +86,7 @@ export const TransportBackends = () => {
</SectionItem>
<SectionItem data-testid="@settings/debug/processes/bridgeLegacy">
<TextColumn
title="Use legacy bridge"
title="Use legacy Bridge"
description="Legacy trezord-go will be spawned as a subprocess"
/>
<ActionColumn>
Expand All @@ -96,7 +102,10 @@ export const TransportBackends = () => {
</ActionColumn>
</SectionItem>
<SectionItem data-testid="@settings/debug/processes/runOnStartUp">
<TextColumn title="Run on startup" />
<TextColumn
title="Run on startup"
description="This is useful for testing of other Transport clients"
/>
<ActionColumn>
<Checkbox
isChecked={!bridgeSettings.doNotStartOnStartup}
Expand Down

0 comments on commit b88e96f

Please sign in to comment.