mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2025-03-12 09:30:30 +00:00
Network methods implementation
This commit is contained in:
parent
ca4745578e
commit
203fbc9968
9 changed files with 264 additions and 24 deletions
50
package-lock.json
generated
50
package-lock.json
generated
|
@ -19,7 +19,9 @@
|
|||
"@angular/router": "17.3.6",
|
||||
"bootstrap": "5.3.3",
|
||||
"bootstrap-icons": "1.11.3",
|
||||
"bootstrap-table": "1.23.4",
|
||||
"bootstrap-table": "1.23.5",
|
||||
"chart.js": "4.4.4",
|
||||
"chartjs": "0.3.24",
|
||||
"crypto": "1.0.1",
|
||||
"idb": "8.0.0",
|
||||
"jquery": "3.7.1",
|
||||
|
@ -44,6 +46,7 @@
|
|||
"@ngx-translate/http-loader": "8.0.0",
|
||||
"@playwright/test": "1.43.1",
|
||||
"@types/bootstrap": "5.2.10",
|
||||
"@types/chart.js": "2.9.41",
|
||||
"@types/jest": "29.5.12",
|
||||
"@types/jquery": "3.5.30",
|
||||
"@types/node": "20.12.7",
|
||||
|
@ -4579,6 +4582,11 @@
|
|||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@kurkle/color": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
|
||||
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
|
||||
},
|
||||
"node_modules/@leichtgewicht/ip-codec": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
|
||||
|
@ -5807,6 +5815,15 @@
|
|||
"@types/responselike": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/chart.js": {
|
||||
"version": "2.9.41",
|
||||
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.41.tgz",
|
||||
"integrity": "sha512-3dvkDvueckY83UyUXtJMalYoH6faOLkWQoaTlJgB4Djde3oORmNP0Jw85HtzTuXyliUHcdp704s0mZFQKio/KQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"moment": "^2.10.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/connect": {
|
||||
"version": "3.4.38",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
||||
|
@ -8278,9 +8295,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/bootstrap-table": {
|
||||
"version": "1.23.4",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.23.4.tgz",
|
||||
"integrity": "sha512-3HHBJzzpg5z03F4eY8AHpLdW26FlzI0hFcmCb+8HRd5CbqLTd4ZJ5dfJUWFE+euU29rr6vkTyhSu44ucueYPDw==",
|
||||
"version": "1.23.5",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.23.5.tgz",
|
||||
"integrity": "sha512-9WByoSpJvA73gi2YYIlX6IWR74oZtBmSixul/Th8FTBtBd/kZRpbKESGTjhA3BA3AYTnfyY8Iy1KeRWPlV2GWQ==",
|
||||
"peerDependencies": {
|
||||
"jquery": "3"
|
||||
}
|
||||
|
@ -8988,6 +9005,22 @@
|
|||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/chart.js": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz",
|
||||
"integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==",
|
||||
"dependencies": {
|
||||
"@kurkle/color": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chartjs": {
|
||||
"version": "0.3.24",
|
||||
"resolved": "https://registry.npmjs.org/chartjs/-/chartjs-0.3.24.tgz",
|
||||
"integrity": "sha512-h6G9qcDqmFYnSWqjWCzQMeOLiypS+pM6Fq2Rj7LPty8Kjx5yHonwwJ7oEHImZpQ2u9Pu36XGYfardvvBiQVrhg=="
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
|
@ -17982,6 +18015,15 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mrmime": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
||||
|
|
|
@ -56,7 +56,9 @@
|
|||
"@angular/router": "17.3.6",
|
||||
"bootstrap": "5.3.3",
|
||||
"bootstrap-icons": "1.11.3",
|
||||
"bootstrap-table": "1.23.4",
|
||||
"bootstrap-table": "1.23.5",
|
||||
"chart.js": "4.4.4",
|
||||
"chartjs": "0.3.24",
|
||||
"crypto": "1.0.1",
|
||||
"idb": "8.0.0",
|
||||
"jquery": "3.7.1",
|
||||
|
@ -81,6 +83,7 @@
|
|||
"@ngx-translate/http-loader": "8.0.0",
|
||||
"@playwright/test": "1.43.1",
|
||||
"@types/bootstrap": "5.2.10",
|
||||
"@types/chart.js": "2.9.41",
|
||||
"@types/jest": "29.5.12",
|
||||
"@types/jquery": "3.5.30",
|
||||
"@types/node": "20.12.7",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { DaemonService } from './daemon.service';
|
||||
import { BlockCount, BlockHeader, Chain, DaemonInfo, MinerData, MiningStatus, NetStats, SyncInfo } from '../../../../common';
|
||||
import { BlockCount, BlockHeader, Chain, DaemonInfo, MinerData, MiningStatus, NetStats, NetStatsHistory, SyncInfo } from '../../../../common';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -35,6 +35,7 @@ export class DaemonDataService {
|
|||
private _gettingAltChains: boolean = false;
|
||||
|
||||
private _netStats?: NetStats;
|
||||
private _netStatsHistory: NetStatsHistory = new NetStatsHistory();
|
||||
private _gettingNetStats: boolean = false;
|
||||
|
||||
private _miningStatus?: MiningStatus;
|
||||
|
@ -50,6 +51,9 @@ export class DaemonDataService {
|
|||
public readonly syncInfoRefreshStart: EventEmitter<void> = new EventEmitter<void>();
|
||||
public readonly syncInfoRefreshEnd: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
public readonly netStatsRefreshStart: EventEmitter<void> = new EventEmitter<void>();
|
||||
public readonly netStatsRefreshEnd: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
||||
constructor(private daemonService: DaemonService) {
|
||||
this.startLoop();
|
||||
|
||||
|
@ -139,6 +143,10 @@ export class DaemonDataService {
|
|||
return this.netStats;
|
||||
}
|
||||
|
||||
public get netStatsHistory(): NetStatsHistory {
|
||||
return this._netStatsHistory;
|
||||
}
|
||||
|
||||
public get gettingNetStats(): boolean {
|
||||
return this._gettingNetStats;
|
||||
}
|
||||
|
@ -271,7 +279,10 @@ export class DaemonDataService {
|
|||
await this.refreshAltChains();
|
||||
|
||||
this._gettingNetStats = true;
|
||||
this.netStatsRefreshStart.emit();
|
||||
this._netStats = await this.daemonService.getNetStats();
|
||||
this._netStatsHistory.add(this._netStats);
|
||||
this.netStatsRefreshEnd.emit();
|
||||
this._gettingNetStats = false;
|
||||
|
||||
await this.refreshMiningStatus();
|
||||
|
|
|
@ -12,6 +12,13 @@
|
|||
</div>
|
||||
|
||||
<div *ngIf="daemonRunning" class="tab-content" id="pills-tabContent">
|
||||
<div class="tab-pane fade show active" id="pills-net-stats" role="tabpanel" aria-labelledby="pills-net-stats-tab" tabindex="0">
|
||||
<h2>Bytes In</h2>
|
||||
<canvas class="my-4 w-100" id="netStatsBytesInChart" width="900" height="380"></canvas>
|
||||
|
||||
<h2>Bytes Out</h2>
|
||||
<canvas class="my-4 w-100" id="netStatsBytesOutChart" width="900" height="380"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-daemon-not-running></app-daemon-not-running>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { AfterViewInit, Component } from '@angular/core';
|
||||
import { NavbarService } from '../../shared/components/navbar/navbar.service';
|
||||
import { DaemonDataService } from '../../core/services';
|
||||
import { DaemonDataService, DaemonService } from '../../core/services';
|
||||
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
|
||||
import { Chart, ChartData } from 'chart.js/auto'
|
||||
import { NetStatsHistoryEntry } from '../../../common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-network',
|
||||
|
@ -9,22 +11,149 @@ import { NavbarLink } from '../../shared/components/navbar/navbar.model';
|
|||
styleUrl: './network.component.scss'
|
||||
})
|
||||
export class NetworkComponent implements AfterViewInit {
|
||||
public daemonRunning: boolean = false;
|
||||
public readonly navbarLinks: NavbarLink[];
|
||||
|
||||
constructor(private navbarService: NavbarService, private daemonData: DaemonDataService) {
|
||||
private netStatsBytesInChart?: Chart;
|
||||
private netStatsBytesOutChart?: Chart;
|
||||
|
||||
public get daemonRunning(): boolean {
|
||||
return this.daemonData.running;
|
||||
}
|
||||
|
||||
constructor(private navbarService: NavbarService, private daemonService: DaemonService, private daemonData: DaemonDataService) {
|
||||
this.navbarLinks = [
|
||||
new NavbarLink('pills-net-stats-tab', '#pills-net-stats', 'pills-net-stats', false, 'Statistics'),
|
||||
new NavbarLink('pills-limits-tab', '#pills-limits', 'pills-limits', false, 'Limits'),
|
||||
new NavbarLink('pills-public-nodes-tab', '#pills-public-nodes', 'pills-public-nodes', false, 'Public Nodes')
|
||||
];
|
||||
|
||||
this.daemonData.netStatsRefreshEnd.subscribe(() => {
|
||||
this.refreshNetStatsHistory();
|
||||
});
|
||||
|
||||
this.daemonService.onDaemonStatusChanged.subscribe((running: boolean) => {
|
||||
if (!running) {
|
||||
if (this.netStatsBytesInChart) {
|
||||
this.netStatsBytesInChart.destroy();
|
||||
this.netStatsBytesInChart = undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
this.daemonRunning = this.daemonData.running;
|
||||
|
||||
this.navbarService.setLinks(this.navbarLinks);
|
||||
this.initNetStatsHistoryChart();
|
||||
}
|
||||
|
||||
}
|
||||
private buildChartBytesInData(): ChartData {
|
||||
const labels: string [] = [];
|
||||
const data: number[] = [];
|
||||
this.daemonData.netStatsHistory.history.forEach((entry: NetStatsHistoryEntry) => {
|
||||
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
|
||||
data.push(entry.netStats.totalBytesIn);
|
||||
});
|
||||
|
||||
return {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
data: data,
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: '#007bff',
|
||||
borderWidth: 4,
|
||||
pointBackgroundColor: '#007bff'
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
private buildChartBytesOutData(): ChartData {
|
||||
const labels: string [] = [];
|
||||
const data: number[] = [];
|
||||
this.daemonData.netStatsHistory.history.forEach((entry: NetStatsHistoryEntry) => {
|
||||
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
|
||||
data.push(entry.netStats.totalBytesOut);
|
||||
});
|
||||
|
||||
return {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
data: data,
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: '#007bff',
|
||||
borderWidth: 4,
|
||||
pointBackgroundColor: '#007bff'
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
private initNetStatsHistoryChart(): void {
|
||||
const ctx1 = <HTMLCanvasElement>document.getElementById('netStatsBytesInChart');
|
||||
const ctx2 = <HTMLCanvasElement>document.getElementById('netStatsBytesOutChart');
|
||||
|
||||
if (!ctx1 || !ctx2) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.netStatsBytesInChart = new Chart(ctx1, {
|
||||
type: 'line',
|
||||
data: this.buildChartBytesInData(),
|
||||
options: {
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
tooltip: {
|
||||
boxPadding: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.netStatsBytesOutChart = new Chart(ctx2, {
|
||||
type: 'line',
|
||||
data: this.buildChartBytesOutData(),
|
||||
options: {
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
tooltip: {
|
||||
boxPadding: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.netStatsBytesInChart.update();
|
||||
this.netStatsBytesOutChart.update();
|
||||
}
|
||||
|
||||
private refreshNetStatsHistory(): void {
|
||||
if (!this.netStatsBytesInChart) {
|
||||
return;
|
||||
}
|
||||
|
||||
const last = this.daemonData.netStatsHistory.last;
|
||||
|
||||
if (!this.netStatsBytesInChart || !this.netStatsBytesOutChart) {
|
||||
this.initNetStatsHistoryChart();
|
||||
}
|
||||
else if (last) {
|
||||
const label = `${last.date.toLocaleTimeString()} ${last.date.toLocaleDateString()}`;
|
||||
|
||||
this.netStatsBytesInChart.data.labels?.push(label);
|
||||
this.netStatsBytesInChart.data.datasets.forEach((dataset) => {
|
||||
dataset.data.push(last.netStats.totalBytesIn);
|
||||
});
|
||||
|
||||
this.netStatsBytesOutChart.data.labels?.push(label);
|
||||
this.netStatsBytesOutChart.data.datasets.forEach((dataset) => {
|
||||
dataset.data.push(last.netStats.totalBytesOut);
|
||||
});
|
||||
|
||||
this.netStatsBytesInChart.update();
|
||||
this.netStatsBytesOutChart.update();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -21,23 +21,19 @@
|
|||
<h4 class="mb-3">Node</h4>
|
||||
|
||||
<div class="row gy-3">
|
||||
|
||||
<div class="col-md-12">
|
||||
<label for="general-monerod-path" class="form-label">Monerod path</label>
|
||||
<input type="file" class="form-control" id="general-monerod-path" [(ngModel)]="currentSettings.monerodPath" [ngModelOptions]="{standalone: true}" (change)="onMonerodPathChange()" placeholder="AAA">
|
||||
<label for="general-monerod-path-control" class="form-label">Monerod path</label>
|
||||
<div class="input-group mb-3">
|
||||
<input id="general-monerod-path-control" type="text" class="form-control form-control-sm" placeholder="" aria-label="Monerod path" aria-describedby="basic-addon2" [value]="currentSettings.monerodPath" readonly>
|
||||
<span class="input-group-text" id="basic-addon2"><button type="button" class="btn btn-secondary btn-sm" (click)="chooseMonerodFile()">Choose file</button></span>
|
||||
</div>
|
||||
<input type="file" class="form-control d-none" id="general-monerod-path" [(ngModel)]="currentSettings.monerodPath" [ngModelOptions]="{standalone: true}" (change)="onMonerodPathChange()" placeholder="AAA">
|
||||
<small class="text-body-secondary">Path to monerod executable</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row gy-3">
|
||||
<div class="col-md-12">
|
||||
<label for="general-xmrig-path" class="form-label">XMRig path</label>
|
||||
<input type="file" class="form-control" id="general-xmrig-path" [(ngModel)]="currentSettings.monerodPath" [ngModelOptions]="{standalone: true}" (change)="onMonerodPathChange()" placeholder="AAA">
|
||||
<small class="text-body-secondary">Path to XMRig executable</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -147,4 +147,24 @@ export class SettingsComponent implements AfterViewInit {
|
|||
|
||||
this.originalSettings = this.currentSettings.clone();
|
||||
}
|
||||
|
||||
public chooseMonerodFile(): void {
|
||||
const input = document.getElementById('general-monerod-path');
|
||||
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
|
||||
input.click();
|
||||
}
|
||||
|
||||
public chooseXmrigFile(): void {
|
||||
const input = document.getElementById('general-xmrig-path');
|
||||
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
|
||||
input.click();
|
||||
}
|
||||
}
|
||||
|
|
31
src/common/NetStatsHistory.ts
Normal file
31
src/common/NetStatsHistory.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { NetStats } from "./NetStats";
|
||||
|
||||
export type NetStatsHistoryEntry = { date: Date, netStats: NetStats};
|
||||
|
||||
export class NetStatsHistory {
|
||||
private _history: NetStatsHistoryEntry[];
|
||||
private _last?: NetStatsHistoryEntry;
|
||||
|
||||
public get history(): NetStatsHistoryEntry[] {
|
||||
return this._history;
|
||||
}
|
||||
|
||||
public get last(): NetStatsHistoryEntry | undefined {
|
||||
return this._last;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this._history = [];
|
||||
}
|
||||
|
||||
public add(netStats: NetStats): void {
|
||||
const entry = {
|
||||
date: new Date(),
|
||||
netStats: netStats
|
||||
};
|
||||
|
||||
this._history.push(entry);
|
||||
|
||||
this._last = entry;
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ export { TxBacklogEntry } from './TxBacklogEntry';
|
|||
export { TxInfo } from './TxInfo';
|
||||
export { UpdateInfo } from './UpdateInfo';
|
||||
export { LogCategoryLevel, LogCategories } from './LogCategories';
|
||||
export { NetStatsHistory, NetStatsHistoryEntry } from './NetStatsHistory';
|
||||
|
||||
export * from './error';
|
||||
export * from './request';
|
||||
|
|
Loading…
Reference in a new issue