mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2025-01-03 09:29:36 +00:00
Monerod process stats
This commit is contained in:
parent
10d832a614
commit
cd2bb56522
10 changed files with 233 additions and 38 deletions
103
app/main.ts
103
app/main.ts
|
@ -1,4 +1,4 @@
|
||||||
import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions } from 'electron';
|
import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions, IpcMainInvokeEvent } from 'electron';
|
||||||
import { ChildProcessWithoutNullStreams, exec, ExecException, spawn } from 'child_process';
|
import { ChildProcessWithoutNullStreams, exec, ExecException, spawn } from 'child_process';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
@ -6,6 +6,44 @@ import * as https from 'https';
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
import * as tar from 'tar';
|
import * as tar from 'tar';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
|
import * as pidusage from 'pidusage';
|
||||||
|
|
||||||
|
interface Stats {
|
||||||
|
/**
|
||||||
|
* percentage (from 0 to 100*vcore)
|
||||||
|
*/
|
||||||
|
cpu: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bytes
|
||||||
|
*/
|
||||||
|
memory: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PPID
|
||||||
|
*/
|
||||||
|
ppid: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PID
|
||||||
|
*/
|
||||||
|
pid: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ms user + system time
|
||||||
|
*/
|
||||||
|
ctime: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ms since the start of the process
|
||||||
|
*/
|
||||||
|
elapsed: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ms since epoch
|
||||||
|
*/
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
//import bz2 from 'unbzip2-stream';
|
//import bz2 from 'unbzip2-stream';
|
||||||
//import * as bz2 from 'unbzip2-stream';
|
//import * as bz2 from 'unbzip2-stream';
|
||||||
|
@ -14,6 +52,7 @@ const bz2 = require('unbzip2-stream');
|
||||||
let win: BrowserWindow | null = null;
|
let win: BrowserWindow | null = null;
|
||||||
let isHidden: boolean = false;
|
let isHidden: boolean = false;
|
||||||
let isQuitting: boolean = false;
|
let isQuitting: boolean = false;
|
||||||
|
let monerodProcess: ChildProcessWithoutNullStreams | null = null;
|
||||||
|
|
||||||
const args = process.argv.slice(1),
|
const args = process.argv.slice(1),
|
||||||
serve = args.some(val => val === '--serve');
|
serve = args.some(val => val === '--serve');
|
||||||
|
@ -133,28 +172,6 @@ function createWindow(): BrowserWindow {
|
||||||
return win;
|
return win;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isWifiConnectedOld() {
|
|
||||||
console.log("isWifiConnected()");
|
|
||||||
const networkInterfaces = os.networkInterfaces();
|
|
||||||
|
|
||||||
console.log(`isWifiConnected(): network interfaces ${networkInterfaces}`);
|
|
||||||
|
|
||||||
for (const interfaceName in networkInterfaces) {
|
|
||||||
const networkInterface = networkInterfaces[interfaceName];
|
|
||||||
|
|
||||||
if (networkInterface) {
|
|
||||||
for (const network of networkInterface) {
|
|
||||||
if (network.family === 'IPv4' && !network.internal && network.mac !== '00:00:00:00:00:00') {
|
|
||||||
if (interfaceName.toLowerCase().includes('wifi') || interfaceName.toLowerCase().includes('wlan')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isConnectedToWiFi(): Promise<boolean> {
|
function isConnectedToWiFi(): Promise<boolean> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const platform = os.platform(); // Use os to get the platform
|
const platform = os.platform(); // Use os to get the platform
|
||||||
|
@ -229,8 +246,13 @@ function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStr
|
||||||
const monerodPath = commandOptions.shift();
|
const monerodPath = commandOptions.shift();
|
||||||
|
|
||||||
if (!monerodPath) {
|
if (!monerodPath) {
|
||||||
win?.webContents.send('monero-sterr', `Invalid monerod path provided: ${monerodPath}`);
|
win?.webContents.send('monero-stderr', `Invalid monerod path provided: ${monerodPath}`);
|
||||||
throw Error("Invalid monerod path provided");
|
throw new Error("Invalid monerod path provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monerodProcess != null) {
|
||||||
|
win?.webContents.send('monero-stderr', 'Monerod already started');
|
||||||
|
throw new Error("Monerod already started");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Starting monerod daemon with options: " + commandOptions.join(" "));
|
console.log("Starting monerod daemon with options: " + commandOptions.join(" "));
|
||||||
|
@ -238,7 +260,7 @@ function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStr
|
||||||
moneroFirstStdout = true;
|
moneroFirstStdout = true;
|
||||||
|
|
||||||
// Avvia il processo usando spawn
|
// Avvia il processo usando spawn
|
||||||
const monerodProcess = spawn(monerodPath, commandOptions);
|
monerodProcess = spawn(monerodPath, commandOptions);
|
||||||
|
|
||||||
// Gestisci l'output di stdout in streaming
|
// Gestisci l'output di stdout in streaming
|
||||||
monerodProcess.stdout.on('data', (data) => {
|
monerodProcess.stdout.on('data', (data) => {
|
||||||
|
@ -271,11 +293,34 @@ function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStr
|
||||||
console.log(`monerod exited with code: ${code}`);
|
console.log(`monerod exited with code: ${code}`);
|
||||||
win?.webContents.send('monero-stdout', `monerod exited with code: ${code}`);
|
win?.webContents.send('monero-stdout', `monerod exited with code: ${code}`);
|
||||||
win?.webContents.send('monero-close', code);
|
win?.webContents.send('monero-close', code);
|
||||||
|
monerodProcess = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
return monerodProcess;
|
return monerodProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function monitorMonerod(): void {
|
||||||
|
if (!monerodProcess) {
|
||||||
|
win?.webContents.send('on-monitor-monerod-error', 'Monerod not running');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!monerodProcess.pid) {
|
||||||
|
win?.webContents.send('on-monitor-monerod-error', 'Unknown monero pid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pidusage(monerodProcess.pid, (error: Error | null, stats: Stats) => {
|
||||||
|
if (error) {
|
||||||
|
win?.webContents.send('on-monitor-monerod-error', `${error}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
win?.webContents.send('on-monitor-monerod', stats);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const downloadFile = (url: string, destinationDir: string, onProgress: (progress: number) => void): Promise<string> => {
|
const downloadFile = (url: string, destinationDir: string, onProgress: (progress: number) => void): Promise<string> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const request = (url: string) => {
|
const request = (url: string) => {
|
||||||
|
@ -524,14 +569,18 @@ try {
|
||||||
|
|
||||||
ipcMain.handle('is-wifi-connected', async (event) => {
|
ipcMain.handle('is-wifi-connected', async (event) => {
|
||||||
isWifiConnected();
|
isWifiConnected();
|
||||||
//win?.webContents.send('is-wifi-connected-result', isWifiConnected());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('get-os-type', (event) => {
|
ipcMain.handle('get-os-type', (event) => {
|
||||||
win?.webContents.send('got-os-type', { platform: os.platform(), arch: os.arch() });
|
win?.webContents.send('got-os-type', { platform: os.platform(), arch: os.arch() });
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('monitor-monerod', (event: IpcMainInvokeEvent) => {
|
||||||
|
monitorMonerod();
|
||||||
|
});
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Catch Error
|
// Catch Error
|
||||||
|
console.error(e);
|
||||||
// throw e;
|
// throw e;
|
||||||
}
|
}
|
||||||
|
|
63
app/package-lock.json
generated
63
app/package-lock.json
generated
|
@ -1,16 +1,20 @@
|
||||||
{
|
{
|
||||||
"name": "monerod-gui",
|
"name": "monerod-gui",
|
||||||
"version": "14.0.1",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "monerod-gui",
|
"name": "monerod-gui",
|
||||||
"version": "14.0.1",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"os": "^0.1.2",
|
"os": "^0.1.2",
|
||||||
|
"pidusage": "^3.0.2",
|
||||||
"tar": "^7.4.3",
|
"tar": "^7.4.3",
|
||||||
"unbzip2-stream": "^1.4.3"
|
"unbzip2-stream": "^1.4.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/pidusage": "^2.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@isaacs/cliui": {
|
"node_modules/@isaacs/cliui": {
|
||||||
|
@ -49,6 +53,12 @@
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/pidusage": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pidusage/-/pidusage-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-MIiyZI4/MK9UGUXWt0jJcCZhVw7YdhBuTOuqP/BjuLDLZ2PmmViMIQgZiWxtaMicQfAz/kMrZ5T7PKxFSkTeUA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/ansi-regex": {
|
"node_modules/ansi-regex": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||||
|
@ -339,6 +349,17 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pidusage": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rimraf": {
|
"node_modules/rimraf": {
|
||||||
"version": "5.0.10",
|
"version": "5.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
||||||
|
@ -353,6 +374,25 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
|
@ -636,6 +676,12 @@
|
||||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"@types/pidusage": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pidusage/-/pidusage-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-MIiyZI4/MK9UGUXWt0jJcCZhVw7YdhBuTOuqP/BjuLDLZ2PmmViMIQgZiWxtaMicQfAz/kMrZ5T7PKxFSkTeUA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
|
||||||
|
@ -813,6 +859,14 @@
|
||||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pidusage": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pidusage/-/pidusage-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-g0VU+y08pKw5M8EZ2rIGiEBaB8wrQMjYGFfW2QVIfyT8V+fq8YFLkvlz4bz5ljvFDJYNFCWT3PWqcRr2FKO81w==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "^5.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"rimraf": {
|
"rimraf": {
|
||||||
"version": "5.0.10",
|
"version": "5.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
||||||
|
@ -821,6 +875,11 @@
|
||||||
"glob": "^10.3.7"
|
"glob": "^10.3.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||||
|
},
|
||||||
"shebang-command": {
|
"shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
|
|
|
@ -11,7 +11,11 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"os": "^0.1.2",
|
"os": "^0.1.2",
|
||||||
|
"pidusage": "^3.0.2",
|
||||||
"tar": "^7.4.3",
|
"tar": "^7.4.3",
|
||||||
"unbzip2-stream": "^1.4.3"
|
"unbzip2-stream": "^1.4.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/pidusage": "^2.0.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,15 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
onMonerodStarted: (callback) => {
|
onMonerodStarted: (callback) => {
|
||||||
ipcRenderer.on('monerod-started', callback);
|
ipcRenderer.on('monerod-started', callback);
|
||||||
},
|
},
|
||||||
|
monitorMonerod: () => {
|
||||||
|
ipcRenderer.invoke('monitor-monerod');
|
||||||
|
},
|
||||||
|
onMonitorMonerod: (callback) => {
|
||||||
|
ipcRenderer.on('on-monitor-monerod', callback);
|
||||||
|
},
|
||||||
|
onMonitorMonerodError: (callback) => {
|
||||||
|
ipcRenderer.on('on-monitor-monerod-error', callback);
|
||||||
|
},
|
||||||
unsubscribeOnMonerodStarted: () => {
|
unsubscribeOnMonerodStarted: () => {
|
||||||
const listeners = ipcRenderer.listeners('monerod-started');
|
const listeners = ipcRenderer.listeners('monerod-started');
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { EventEmitter, Injectable, NgZone } from '@angular/core';
|
import { EventEmitter, Injectable, NgZone } from '@angular/core';
|
||||||
import { DaemonService } from './daemon.service';
|
import { DaemonService } from './daemon.service';
|
||||||
import { BlockCount, BlockHeader, Chain, Connection, CoreIsBusyError, DaemonInfo, MinerData, MiningStatus, NetStats, NetStatsHistory, PeerInfo, PublicNode, SyncInfo, TxBacklogEntry, TxPool } from '../../../../common';
|
import { BlockCount, BlockHeader, Chain, Connection, CoreIsBusyError, DaemonInfo, MinerData, MiningStatus, NetStats, NetStatsHistory, PeerInfo, ProcessStats, PublicNode, SyncInfo, TxBacklogEntry, TxPool } from '../../../../common';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
@ -16,6 +16,9 @@ export class DaemonDataService {
|
||||||
|
|
||||||
private _daemonRunning: boolean = false;
|
private _daemonRunning: boolean = false;
|
||||||
|
|
||||||
|
private _processStats?: ProcessStats;
|
||||||
|
private _gettingProcessStats: boolean = false;
|
||||||
|
|
||||||
private _daemonInfo?: DaemonInfo;
|
private _daemonInfo?: DaemonInfo;
|
||||||
private _gettingDaemonInfo: boolean = false;
|
private _gettingDaemonInfo: boolean = false;
|
||||||
|
|
||||||
|
@ -110,6 +113,14 @@ export class DaemonDataService {
|
||||||
return this._refreshing;
|
return this._refreshing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get processStats(): ProcessStats | undefined {
|
||||||
|
return this._processStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get gettingProcessStats(): boolean {
|
||||||
|
return this._gettingProcessStats;
|
||||||
|
}
|
||||||
|
|
||||||
public get info(): DaemonInfo | undefined {
|
public get info(): DaemonInfo | undefined {
|
||||||
return this._daemonInfo;
|
return this._daemonInfo;
|
||||||
}
|
}
|
||||||
|
@ -268,10 +279,6 @@ export class DaemonDataService {
|
||||||
return Date.now() - this._lastRefresh <= this.refreshTimeoutMs;
|
return Date.now() - this._lastRefresh <= this.refreshTimeoutMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getInfo(): Promise<void> {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private async refreshMiningStatus(): Promise<void> {
|
private async refreshMiningStatus(): Promise<void> {
|
||||||
this._gettingMiningStatus = true;
|
this._gettingMiningStatus = true;
|
||||||
|
|
||||||
|
@ -409,7 +416,7 @@ export class DaemonDataService {
|
||||||
}
|
}
|
||||||
this._gettingIsBlockchainPruned = false;
|
this._gettingIsBlockchainPruned = false;
|
||||||
|
|
||||||
await this.refreshAltChains();
|
if (this._daemonInfo.synchronized) await this.refreshAltChains();
|
||||||
|
|
||||||
this._gettingNetStats = true;
|
this._gettingNetStats = true;
|
||||||
this.netStatsRefreshStart.emit();
|
this.netStatsRefreshStart.emit();
|
||||||
|
@ -418,7 +425,7 @@ export class DaemonDataService {
|
||||||
this.netStatsRefreshEnd.emit();
|
this.netStatsRefreshEnd.emit();
|
||||||
this._gettingNetStats = false;
|
this._gettingNetStats = false;
|
||||||
|
|
||||||
await this.refreshMiningStatus();
|
if (this._daemonInfo.synchronized) await this.refreshMiningStatus();
|
||||||
|
|
||||||
if (this._daemonInfo.synchronized) await this.refreshMinerData();
|
if (this._daemonInfo.synchronized) await this.refreshMinerData();
|
||||||
|
|
||||||
|
@ -440,6 +447,8 @@ export class DaemonDataService {
|
||||||
this._connections = await this.daemonService.getConnections();
|
this._connections = await this.daemonService.getConnections();
|
||||||
this._gettingConnections = false;
|
this._gettingConnections = false;
|
||||||
|
|
||||||
|
await this.refreshProcessStats();
|
||||||
|
|
||||||
this._lastRefreshHeight = this._daemonInfo.heightWithoutBootstrap;
|
this._lastRefreshHeight = this._daemonInfo.heightWithoutBootstrap;
|
||||||
this._lastRefresh = Date.now();
|
this._lastRefresh = Date.now();
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
|
@ -468,4 +477,18 @@ export class DaemonDataService {
|
||||||
this._refreshing = false;
|
this._refreshing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async refreshProcessStats(): Promise<void> {
|
||||||
|
this._gettingProcessStats = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._processStats = await this.daemonService.getProcessStats();
|
||||||
|
}
|
||||||
|
catch(error: any) {
|
||||||
|
console.error(error);
|
||||||
|
this._processStats = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._gettingProcessStats = false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ import { TxInfo } from '../../../../common/TxInfo';
|
||||||
import { DaemonSettings } from '../../../../common/DaemonSettings';
|
import { DaemonSettings } from '../../../../common/DaemonSettings';
|
||||||
import { MethodNotFoundError } from '../../../../common/error/MethodNotFoundError';
|
import { MethodNotFoundError } from '../../../../common/error/MethodNotFoundError';
|
||||||
import { openDB, IDBPDatabase } from "idb"
|
import { openDB, IDBPDatabase } from "idb"
|
||||||
import { PeerInfo, TxPool } from '../../../../common';
|
import { PeerInfo, ProcessStats, TxPool } from '../../../../common';
|
||||||
import { MoneroInstallerService } from '../monero-installer/monero-installer.service';
|
import { MoneroInstallerService } from '../monero-installer/monero-installer.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
|
@ -1120,6 +1120,26 @@ export class DaemonService {
|
||||||
return "0.1.0-alpha";
|
return "0.1.0-alpha";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getProcessStats(): Promise<ProcessStats> {
|
||||||
|
if (!await this.isRunning()) {
|
||||||
|
throw new Error("Daemon not running");
|
||||||
|
}
|
||||||
|
|
||||||
|
const getProcessStatsPromise = new Promise<ProcessStats>((resolve, reject) => {
|
||||||
|
window.electronAPI.onMonitorMonerodError((event: any, error: string) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.electronAPI.onMonitorMonerod((event: any, stats: ProcessStats) => {
|
||||||
|
resolve(stats);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
window.electronAPI.monitorMonerod();
|
||||||
|
|
||||||
|
return await getProcessStatsPromise;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RpcError { code: number, message: string }
|
export interface RpcError { code: number, message: string }
|
|
@ -232,7 +232,7 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
|
||||||
if (this.daemonData.initializing || this.daemonService.starting) {
|
if (this.daemonData.initializing || this.daemonService.starting) {
|
||||||
return this.createLoadingCards();
|
return this.createLoadingCards();
|
||||||
}
|
}
|
||||||
return [
|
const cards = [
|
||||||
new Card('Connection Status', this.connectionStatus),
|
new Card('Connection Status', this.connectionStatus),
|
||||||
new Card('Network Type', this.networkType),
|
new Card('Network Type', this.networkType),
|
||||||
new Card('Node Type', this.nodeType),
|
new Card('Node Type', this.nodeType),
|
||||||
|
@ -246,6 +246,15 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
|
||||||
new Card('Transaction count', `${this.txCount}`),
|
new Card('Transaction count', `${this.txCount}`),
|
||||||
new Card('Pool size', `${this.poolSize}`)
|
new Card('Pool size', `${this.poolSize}`)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (this.daemonData.processStats) {
|
||||||
|
cards.push(
|
||||||
|
new Card('CPU usage', `${this.daemonData.processStats.cpu.toFixed(2)} %`),
|
||||||
|
new Card('Memory usage', `${(this.daemonData.processStats.memory / 1024 / 1024).toFixed(2)} MB`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cards;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPeers(): Connection[] {
|
public getPeers(): Connection[] {
|
||||||
|
|
9
src/common/ProcessStats.ts
Normal file
9
src/common/ProcessStats.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export interface ProcessStats {
|
||||||
|
cpu: number;
|
||||||
|
memory: number;
|
||||||
|
ppid: number;
|
||||||
|
pid: number;
|
||||||
|
ctime: number;
|
||||||
|
elapsed: number;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ export { NetStatsHistory, NetStatsHistoryEntry } from './NetStatsHistory';
|
||||||
export { UnconfirmedTx } from './UnconfirmedTx';
|
export { UnconfirmedTx } from './UnconfirmedTx';
|
||||||
export { SpentKeyImage } from './SpentKeyImage';
|
export { SpentKeyImage } from './SpentKeyImage';
|
||||||
export { TxPool } from './TxPool';
|
export { TxPool } from './TxPool';
|
||||||
|
export { ProcessStats } from './ProcessStats';
|
||||||
|
|
||||||
export * from './error';
|
export * from './error';
|
||||||
export * from './request';
|
export * from './request';
|
||||||
|
|
|
@ -59,6 +59,18 @@ declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
electronAPI: {
|
electronAPI: {
|
||||||
startMonerod: (options: string[]) => void;
|
startMonerod: (options: string[]) => void;
|
||||||
|
monitorMonerod: () => void;
|
||||||
|
onMonitorMonerod: (callback: (event: any, stats: {
|
||||||
|
cpu: number;
|
||||||
|
memory: number;
|
||||||
|
ppid: number;
|
||||||
|
pid: number;
|
||||||
|
ctime: number;
|
||||||
|
elapsed: number;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
) => void) => void;
|
||||||
|
onMonitorMonerodError: (callback: (event: any, error: string) => void) => void;
|
||||||
onMonerodStarted: (callback: (event: any, started: boolean) => void) => void;
|
onMonerodStarted: (callback: (event: any, started: boolean) => void) => void;
|
||||||
unsubscribeOnMonerodStarted: () => void;
|
unsubscribeOnMonerodStarted: () => void;
|
||||||
onMoneroClose: (callback: (event: any, code: number) => void) => void;
|
onMoneroClose: (callback: (event: any, code: number) => void) => void;
|
||||||
|
|
Loading…
Reference in a new issue