diff --git a/src/api/network.js b/src/api/network.js index ce619668..091f5fe4 100644 --- a/src/api/network.js +++ b/src/api/network.js @@ -4,19 +4,23 @@ import { GET_CALLS_RETRY, GET_CALLS_TIMEOUT } from 'config/constants' import { userFriendlyError } from 'api/Ledger' import { retry } from 'helpers/promise' -const doRequest = axios // TODO later introduce a way to run it in renderer based on a env, we will diverge this implementation - -export default (arg: Object) => { +let implementation = (arg: Object) => { let promise if (arg.method === 'GET') { if (!('timeout' in arg)) { arg.timeout = GET_CALLS_TIMEOUT } - promise = retry(() => doRequest(arg), { + promise = retry(() => axios(arg), { maxRetry: GET_CALLS_RETRY, }) } else { - promise = doRequest(arg) + promise = axios(arg) } return userFriendlyError(promise) } + +export const setImplementation = (impl: *) => { + implementation = impl +} + +export default (arg: Object) => implementation(arg) diff --git a/src/helpers/ipc.js b/src/helpers/ipc.js index 38abb40b..dac143ec 100644 --- a/src/helpers/ipc.js +++ b/src/helpers/ipc.js @@ -28,7 +28,7 @@ export class Command { } type Msg = { - type: 'NEXT' | 'COMPLETE' | 'ERROR', + type: 'cmd.NEXT' | 'cmd.COMPLETE' | 'cmd.ERROR', requestId: string, data?: A, } @@ -48,20 +48,20 @@ function ipcRendererSendCommand(id: string, data: In): Observable { function handleCommandEvent(e, msg: Msg) { if (requestId !== msg.requestId) return switch (msg.type) { - case 'NEXT': + case 'cmd.NEXT': logger.log(`● CMD ${id}`, msg.data) if (msg.data) { o.next(msg.data) } break - case 'COMPLETE': + case 'cmd.COMPLETE': logger.log(`✔ CMD ${id} finished in ${(Date.now() - startTime).toFixed(0)}ms`) o.complete() ipcRenderer.removeListener('command-event', handleCommandEvent) break - case 'ERROR': + case 'cmd.ERROR': logger.warn(`✖ CMD ${id} error`, msg.data) o.error(msg.data) ipcRenderer.removeListener('command-event', handleCommandEvent) diff --git a/src/internals/index.js b/src/internals/index.js index 4c53b555..94601aaa 100644 --- a/src/internals/index.js +++ b/src/internals/index.js @@ -1,12 +1,39 @@ // @flow import commands from 'commands' import logger from 'logger' +import uuid from 'uuid/v4' +import { setImplementation } from 'api/network' require('../env') require('../init-sentry') process.title = 'Internal' +const defers = {} + +if (process.env.DEBUG_NETWORK) { + setImplementation(networkArg => { + const id = uuid() + return new Promise((resolve, reject) => { + process.send({ + type: 'executeHttpQueryOnRenderer', + networkArg, + id, + }) + defers[id] = { + resolve: r => { + resolve(r) + delete defers[id] + }, + reject: e => { + reject(e) + delete defers[id] + }, + } + }) + }) +} + const subscriptions = {} process.on('message', m => { @@ -20,7 +47,7 @@ process.on('message', m => { subscriptions[requestId] = cmd.impl(data).subscribe({ next: data => { process.send({ - type: 'NEXT', + type: 'cmd.NEXT', requestId, data, }) @@ -28,7 +55,7 @@ process.on('message', m => { complete: () => { delete subscriptions[requestId] process.send({ - type: 'COMPLETE', + type: 'cmd.COMPLETE', requestId, }) }, @@ -36,7 +63,7 @@ process.on('message', m => { logger.warn('Command error:', error) delete subscriptions[requestId] process.send({ - type: 'ERROR', + type: 'cmd.ERROR', requestId, data: { ...error, @@ -53,6 +80,18 @@ process.on('message', m => { sub.unsubscribe() delete subscriptions[requestId] } + } else if (m.type === 'executeHttpQueryPayload') { + const { payload } = m + const defer = defers[payload.id] + if (!defer) { + logger.warn('executeHttpQueryPayload: no defer found') + return + } + if (payload.type === 'success') { + defer.resolve(payload.result) + } else { + defer.reject(payload.error) + } } }) diff --git a/src/main/app.js b/src/main/app.js index 7367ab42..6c6c9e71 100644 --- a/src/main/app.js +++ b/src/main/app.js @@ -9,6 +9,8 @@ import db from 'helpers/db' // necessary to prevent win from being garbage collected let mainWindow = null +export const getMainWindow = () => mainWindow + let forceClose = false const { UPGRADE_EXTENSIONS, ELECTRON_WEBPACK_WDS_PORT, DEV_TOOLS, DEV_TOOLS_MODE } = process.env diff --git a/src/main/bridge.js b/src/main/bridge.js index 54acd85b..ff9af1ab 100644 --- a/src/main/bridge.js +++ b/src/main/bridge.js @@ -10,6 +10,8 @@ import logger from 'logger' import setupAutoUpdater, { quitAndInstall } from './autoUpdate' +import { getMainWindow } from './app' + // sqlite files will be located in the app local data folder const LEDGER_LIVE_SQLITE_PATH = path.resolve(app.getPath('userData'), 'sqlite') @@ -30,6 +32,7 @@ const bootInternalProcess = () => { internalProcess = fork(forkBundlePath, { env: { ...process.env, LEDGER_LIVE_SQLITE_PATH }, }) + internalProcess.on('message', handleGlobalInternalMessage) internalProcess.on('exit', code => { logger.warn(`Internal process ended with code ${code}`) internalProcess = null @@ -58,7 +61,7 @@ ipcMainListenReceiveCommands({ p.removeListener('message', handleMessage) p.removeListener('exit', handleExit) notifyCommandEvent({ - type: 'ERROR', + type: 'cmd.ERROR', requestId: command.requestId, data: { message: `Internal process error (${code})`, name: 'InternalError' }, }) @@ -67,7 +70,7 @@ ipcMainListenReceiveCommands({ const handleMessage = payload => { if (payload.requestId !== command.requestId) return notifyCommandEvent(payload) - if (payload.type === 'ERROR' || payload.type === 'COMPLETE') { + if (payload.type === 'cmd.ERROR' || payload.type === 'cmd.COMPLETE') { p.removeListener('message', handleMessage) p.removeListener('exit', handleExit) } @@ -79,6 +82,26 @@ ipcMainListenReceiveCommands({ }, }) +function handleGlobalInternalMessage(payload) { + if (payload.type === 'executeHttpQueryOnRenderer') { + const win = getMainWindow && getMainWindow() + if (!win) { + logger.warn("can't executeHttpQueryOnRenderer because no renderer") + return + } + win.webContents.send('executeHttpQuery', { + id: payload.id, + networkArg: payload.networkArg, + }) + } +} + +ipcMain.on('executeHttpQueryPayload', (event, payload) => { + const p = internalProcess + if (!p) return + p.send({ type: 'executeHttpQueryPayload', payload }) +}) + // TODO move this to "command" pattern ipcMain.on('updater', (event, { type, data }) => { const handler = { diff --git a/src/renderer/events.js b/src/renderer/events.js index 22f68282..e28f9387 100644 --- a/src/renderer/events.js +++ b/src/renderer/events.js @@ -10,6 +10,7 @@ import 'commands' import logger from 'logger' +import network from 'api/network' import { ipcRenderer } from 'electron' import debug from 'debug' @@ -79,6 +80,17 @@ export default ({ store }: { store: Object, locked: boolean }) => { syncDevices() + ipcRenderer.on('executeHttpQuery', (event: any, { networkArg, id }) => { + network(networkArg).then( + result => { + ipcRenderer.send('executeHttpQueryPayload', { type: 'success', id, result }) + }, + error => { + ipcRenderer.send('executeHttpQueryPayload', { type: 'error', id, error }) + }, + ) + }) + if (__PROD__) { // TODO move this to "command" pattern const updaterHandlers = {