import { AsyncCall } from 'async-call-rpc'; import type { RendererToHelper } from '../shared/type'; import { events, handlers } from './exposed'; import { logger } from './logger'; function setupRendererConnection(rendererPort: Electron.MessagePortMain) { const flattenedHandlers = Object.entries(handlers).flatMap( ([namespace, namespaceHandlers]) => { return Object.entries(namespaceHandlers).map(([name, handler]) => { const handlerWithLog = async (...args: any[]) => { try { const start = performance.now(); const result = await handler(...args); logger.debug( '[async-api]', `${namespace}.${name}`, args.filter( arg => typeof arg !== 'function' && typeof arg !== 'object' ), '-', (performance.now() - start).toFixed(2), 'ms' ); return result; } catch (error) { logger.error('[async-api]', `${namespace}.${name}`, error); } }; return [`${namespace}:${name}`, handlerWithLog]; }); } ); const rpc = AsyncCall( Object.fromEntries(flattenedHandlers), { channel: { on(listener) { const f = (e: Electron.MessageEvent) => { listener(e.data); }; rendererPort.on('message', f); // MUST start the connection to receive messages rendererPort.start(); return () => { rendererPort.off('message', f); }; }, send(data) { rendererPort.postMessage(data); }, }, log: false, } ); for (const [namespace, namespaceEvents] of Object.entries(events)) { for (const [key, eventRegister] of Object.entries(namespaceEvents)) { const unsub = eventRegister((...args: any[]) => { const chan = `${namespace}:${key}`; rpc.postEvent(chan, ...args).catch(err => { console.error(err); }); }); process.on('exit', () => { unsub(); }); } } } function main() { process.parentPort.on('message', e => { if (e.data.channel === 'renderer-connect' && e.ports.length === 1) { const rendererPort = e.ports[0]; setupRendererConnection(rendererPort); logger.info('[helper] renderer connected'); } }); } main();