diff --git a/app/infra/eventsService/eventsService.ts b/app/infra/eventsService/eventsService.ts index c5791148b..c08e58fda 100644 --- a/app/infra/eventsService/eventsService.ts +++ b/app/infra/eventsService/eventsService.ts @@ -247,6 +247,8 @@ class EventsService { /** ************************************** MISC ***************************************** */ + static exportNetInfo = () => ipcRenderer.invoke(ipcConsts.EXPORT_NET_INFO); + static print = ({ content }: { content: string }) => ipcRenderer.send(ipcConsts.PRINT, { content }); diff --git a/app/screens/settings/Settings.tsx b/app/screens/settings/Settings.tsx index b45d9b072..c0180249c 100644 --- a/app/screens/settings/Settings.tsx +++ b/app/screens/settings/Settings.tsx @@ -491,6 +491,17 @@ class Settings extends Component { ))} + + } + rowName="" + /> + new Promise((resolve, reject) => { + if (!this.service) { + reject(new Error('Service is not started yet')); + return; + } + + const result: PeerInfo__Output[] = []; + const stream = this.service?.PeerInfoStream({}); + if (!stream) { + resolve([]); + return; + } + stream.on('data', (d) => result.push(d)); + stream.on('close', () => resolve(result)); + }); } export default AdminService; diff --git a/desktop/DebugService.ts b/desktop/DebugService.ts new file mode 100644 index 000000000..8cea69c26 --- /dev/null +++ b/desktop/DebugService.ts @@ -0,0 +1,28 @@ +import { ProtoGrpcType } from '../api/generated'; + +import Logger from './logger'; +import NetServiceFactory from './NetServiceFactory'; +import { getPrivateNodeConnectionConfig } from './main/utils'; + +const PROTO_PATH = 'vendor/api/spacemesh/v1/debug.proto'; + +class DebugService extends NetServiceFactory< + ProtoGrpcType, + 'v1', + 'DebugService' +> { + logger = Logger({ className: 'DebugService' }); + + createService = () => { + this.createNetService( + PROTO_PATH, + getPrivateNodeConnectionConfig(), + 'v1', + 'DebugService' + ); + }; + + getNetworkInfo = () => this.callService('NetworkInfo', {}); +} + +export default DebugService; diff --git a/desktop/main/reactions/handleExportInfoIPC.ts b/desktop/main/reactions/handleExportInfoIPC.ts new file mode 100644 index 000000000..e01ac6054 --- /dev/null +++ b/desktop/main/reactions/handleExportInfoIPC.ts @@ -0,0 +1,63 @@ +import { writeFile } from 'fs/promises'; +import { combineLatest, from, map, mergeMap, Observable } from 'rxjs'; +import { BrowserWindow, dialog } from 'electron'; +import { handleIPC, handlerResult, makeSubscription } from '../rx.utils'; +import { ipcConsts } from '../../../app/vars'; +import AdminService from '../../AdminService'; +import DebugService from '../../DebugService'; +import Logger from '../../logger'; + +const logger = Logger({ className: 'handleExportInfoIPC' }); + +const saveDialog = async ( + browser: BrowserWindow, + data: Record +) => { + const { canceled, filePath } = await dialog.showSaveDialog(browser, { + title: 'Export network info', + buttonLabel: 'Export', + defaultPath: 'netInfo.json', + }); + if (canceled || !filePath) { + return { filePath: null, data, canceled }; + } + return { filePath, data, canceled }; +}; + +const handleExportInfoIPC = ($mainWindow: Observable) => + makeSubscription( + handleIPC( + ipcConsts.EXPORT_NET_INFO, + () => { + const adminService = new AdminService(); + const debugService = new DebugService(); + debugService.createService(); + adminService.createService(); + + const netInfo = from(debugService.getNetworkInfo()); + const peerInfo = from(adminService.getPeerInfo()); + + return combineLatest([netInfo, peerInfo, $mainWindow]).pipe( + mergeMap(([netInfo, peerInfo, browser]) => + from(saveDialog(browser, { netInfo, peerInfo })) + ), + map(handlerResult) + ); + }, + (data) => data + ), + ({ filePath, data }) => { + if (filePath) { + writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8') + // eslint-disable-next-line promise/always-return + .then(() => { + logger.log('Network data exported', { filePath, data }); + }) + .catch((err) => + logger.error('Cannot write file', err, { filePath, data }) + ); + } + } + ); + +export default handleExportInfoIPC; diff --git a/desktop/main/startApp.ts b/desktop/main/startApp.ts index 8dc8f2aa1..0a44b7636 100644 --- a/desktop/main/startApp.ts +++ b/desktop/main/startApp.ts @@ -49,6 +49,7 @@ import syncAutoStartAndConfig from './reactions/syncAutoStartAndConfig'; import restartNode from './reactions/restartNode'; import { updateConfigHash } from './configHash'; import { ensureConfigCacheDir } from './fallbackConfigs'; +import handleExportInfoIPC from './reactions/handleExportInfoIPC'; const positiveNum = (def: number, n: number) => (n > 0 ? n : def); @@ -271,6 +272,7 @@ const startApp = (): AppStore => { listenNodeConfigAndRestartNode($nodeConfig, $managers), handleBenchmarksIpc($mainWindow, $nodeConfig), syncAutoStartAndConfig($warnings), + handleExportInfoIPC($mainWindow), ]; return {