mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2024-12-31 16:09:53 +00:00
Better network charts
This commit is contained in:
parent
388021b25b
commit
80e0a5091b
6 changed files with 103 additions and 60 deletions
|
@ -400,6 +400,14 @@ export class DaemonService {
|
||||||
|
|
||||||
console.log("Starting daemon");
|
console.log("Starting daemon");
|
||||||
|
|
||||||
|
if (!this.restarting && !this.enablingSync) {
|
||||||
|
window.electronAPI.showNotification({
|
||||||
|
title: 'Daemon starting',
|
||||||
|
body: 'Monero daemon is starting',
|
||||||
|
closeButtonText: 'Dismiss'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.settings = customSettings ? customSettings : await this.getSettings();
|
this.settings = customSettings ? customSettings : await this.getSettings();
|
||||||
|
|
||||||
if (!this.settings.noSync && !this.settings.syncOnWifi && await this.isWifiConnected()) {
|
if (!this.settings.noSync && !this.settings.syncOnWifi && await this.isWifiConnected()) {
|
||||||
|
|
|
@ -47,7 +47,23 @@ export abstract class BasePageComponent implements AfterContentInit, OnDestroy {
|
||||||
this.setTableInitialized(id, $table);
|
this.setTableInitialized(id, $table);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadTable(id: string, rows: any[]): void {
|
protected setTableLoading(id: string, loading: boolean = true): void {
|
||||||
|
if (!this.isTableInitialized(id)) {
|
||||||
|
this.initTable(id, loading);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const $table = this.initializedTables[id];
|
||||||
|
|
||||||
|
if (!$table) {
|
||||||
|
console.warn(`Could not set table loading to ${id}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$table.bootstrapTable('showLoading');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected loadTable(id: string, rows: any[], loading: boolean = false): void {
|
||||||
if (!this.isTableInitialized(id)) {
|
if (!this.isTableInitialized(id)) {
|
||||||
this.initTable(id);
|
this.initTable(id);
|
||||||
}
|
}
|
||||||
|
@ -60,10 +76,11 @@ export abstract class BasePageComponent implements AfterContentInit, OnDestroy {
|
||||||
const $table = this.initializedTables[id] as JQuery<HTMLElement>;
|
const $table = this.initializedTables[id] as JQuery<HTMLElement>;
|
||||||
|
|
||||||
$table.bootstrapTable('load', rows);
|
$table.bootstrapTable('load', rows);
|
||||||
$table.bootstrapTable('hideLoading');
|
if (loading) $table.bootstrapTable('showLoading');
|
||||||
|
else $table.bootstrapTable('hideLoading');
|
||||||
}
|
}
|
||||||
|
|
||||||
private destroyTable(id: string): void {
|
protected destroyTable(id: string): void {
|
||||||
const $table = this.initializedTables[id];
|
const $table = this.initializedTables[id];
|
||||||
|
|
||||||
if (!$table) {
|
if (!$table) {
|
||||||
|
@ -76,7 +93,7 @@ export abstract class BasePageComponent implements AfterContentInit, OnDestroy {
|
||||||
this.initializedTables[id] = undefined;
|
this.initializedTables[id] = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private destroyTables(): void {
|
protected destroyTables(): void {
|
||||||
for(const key in this.initializedTables) {
|
for(const key in this.initializedTables) {
|
||||||
this.destroyTable(key);
|
this.destroyTable(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,13 +150,13 @@ export class DetailComponent extends BasePageComponent implements AfterViewInit
|
||||||
|
|
||||||
this.ngZone.run(() => {
|
this.ngZone.run(() => {
|
||||||
this.cards = this.createCards();
|
this.cards = this.createCards();
|
||||||
|
this.loadTables(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const syncInfoRefreshEndSub: Subscription = this.daemonData.syncInfoRefreshEnd.subscribe(() => {
|
const syncInfoRefreshEndSub: Subscription = this.daemonData.syncInfoRefreshEnd.subscribe(() => {
|
||||||
this.loadTables();
|
|
||||||
|
|
||||||
this.cards = this.createCards();
|
this.cards = this.createCards();
|
||||||
|
this.loadTables();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.subscriptions.push(syncStartSub, syncInfoRefreshEndSub);
|
this.subscriptions.push(syncStartSub, syncInfoRefreshEndSub);
|
||||||
|
@ -169,17 +169,17 @@ export class DetailComponent extends BasePageComponent implements AfterViewInit
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadPeersTable(): void {
|
private loadPeersTable(loading: boolean = false): void {
|
||||||
this.loadTable('peersTable', this.getPeers());
|
this.loadTable('peersTable', this.getPeers(), loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadSpansTable(): void {
|
private loadSpansTable(loading: boolean = false): void {
|
||||||
this.loadTable('spansTable', this.getSpans());
|
this.loadTable('spansTable', this.getSpans(), loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadTables(): void {
|
private loadTables(loading: boolean = false): void {
|
||||||
this.loadPeersTable();
|
this.loadPeersTable(loading);
|
||||||
this.loadSpansTable();
|
this.loadSpansTable(loading);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createCards(): SimpleBootstrapCard[] {
|
private createCards(): SimpleBootstrapCard[] {
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
<div *ngIf="daemonRunning && !daemonStopping" class="tab-content" id="pills-tabContent">
|
<div *ngIf="daemonRunning && !daemonStopping" 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">
|
<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>
|
<h2><i class="bi bi-cloud-arrow-down m-4"></i> Download ({{ currentNetStats.totalGigaBytesIn.toFixed(2) }} GB)</h2>
|
||||||
<canvas class="my-4 w-100" id="netStatsBytesInChart" width="900" height="380"></canvas>
|
<canvas class="my-4 w-100" id="netStatsBytesInChart" width="900" height="380"></canvas>
|
||||||
|
|
||||||
<h2>Bytes Out</h2>
|
<h2><i class="bi bi-cloud-arrow-up m-4"></i> Upload ({{ currentNetStats.totalGigaBytesOut.toFixed(2) }} GB)</h2>
|
||||||
<canvas class="my-4 w-100" id="netStatsBytesOutChart" width="900" height="380"></canvas>
|
<canvas class="my-4 w-100" id="netStatsBytesOutChart" width="900" height="380"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@
|
||||||
id="connectionsTable"
|
id="connectionsTable"
|
||||||
data-toggle="connectionsTable"
|
data-toggle="connectionsTable"
|
||||||
data-toolbar="#toolbar"
|
data-toolbar="#toolbar"
|
||||||
|
|
||||||
data-pagination="true"
|
data-pagination="true"
|
||||||
>
|
>
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { NavbarService } from '../../shared/components/navbar/navbar.service';
|
||||||
import { DaemonDataService, DaemonService } from '../../core/services';
|
import { DaemonDataService, DaemonService } from '../../core/services';
|
||||||
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
|
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
|
||||||
import { Chart, ChartData } from 'chart.js/auto'
|
import { Chart, ChartData } from 'chart.js/auto'
|
||||||
import { NetStatsHistoryEntry } from '../../../common';
|
import { NetStats, NetStatsHistoryEntry } from '../../../common';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { BasePageComponent } from '../base-page/base-page.component';
|
import { BasePageComponent } from '../base-page/base-page.component';
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
|
||||||
public setLimitSuccess: boolean = false;
|
public setLimitSuccess: boolean = false;
|
||||||
public setLimitError: string = '';
|
public setLimitError: string = '';
|
||||||
|
|
||||||
|
public currentNetStats: NetStats;
|
||||||
|
|
||||||
constructor(navbarService: NavbarService, private daemonService: DaemonService, private daemonData: DaemonDataService) {
|
constructor(navbarService: NavbarService, private daemonService: DaemonService, private daemonData: DaemonDataService) {
|
||||||
super(navbarService);
|
super(navbarService);
|
||||||
this.setLinks([
|
this.setLinks([
|
||||||
|
@ -40,6 +42,9 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
|
||||||
new NavbarLink('pills-limits-tab', '#pills-limit', 'pills-limit', false, 'Limit')
|
new NavbarLink('pills-limits-tab', '#pills-limit', 'pills-limit', false, 'Limit')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const lastNetStats = this.daemonData.netStatsHistory.last;
|
||||||
|
this.currentNetStats = lastNetStats ? lastNetStats.netStats : new NetStats(0, 0, 0, 0);
|
||||||
|
|
||||||
const netStatsRefreshStartSub: Subscription = this.daemonData.netStatsRefreshEnd.subscribe(() => {
|
const netStatsRefreshStartSub: Subscription = this.daemonData.netStatsRefreshEnd.subscribe(() => {
|
||||||
this.refreshNetStatsHistory();
|
this.refreshNetStatsHistory();
|
||||||
});
|
});
|
||||||
|
@ -54,6 +59,10 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
|
||||||
this.netStatsBytesInChart.destroy();
|
this.netStatsBytesInChart.destroy();
|
||||||
this.netStatsBytesInChart = undefined;
|
this.netStatsBytesInChart = undefined;
|
||||||
}
|
}
|
||||||
|
if (this.netStatsBytesOutChart) {
|
||||||
|
this.netStatsBytesOutChart.destroy();
|
||||||
|
this.netStatsBytesOutChart = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.initNetStatsHistoryChart();
|
this.initNetStatsHistoryChart();
|
||||||
|
@ -78,7 +87,7 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
|
||||||
const data: number[] = [];
|
const data: number[] = [];
|
||||||
this.daemonData.netStatsHistory.history.forEach((entry: NetStatsHistoryEntry) => {
|
this.daemonData.netStatsHistory.history.forEach((entry: NetStatsHistoryEntry) => {
|
||||||
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
|
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
|
||||||
data.push(entry.netStats.totalBytesIn);
|
data.push(entry.netStats.totalGigaBytesIn);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -86,9 +95,10 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: data,
|
data: data,
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
borderColor: '#007bff',
|
borderColor: '#ff5733',
|
||||||
borderWidth: 4,
|
borderWidth: 4,
|
||||||
pointBackgroundColor: '#007bff'
|
pointBackgroundColor: '#ff5733',
|
||||||
|
radius: 0
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -98,7 +108,7 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
|
||||||
const data: number[] = [];
|
const data: number[] = [];
|
||||||
this.daemonData.netStatsHistory.history.forEach((entry: NetStatsHistoryEntry) => {
|
this.daemonData.netStatsHistory.history.forEach((entry: NetStatsHistoryEntry) => {
|
||||||
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
|
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
|
||||||
data.push(entry.netStats.totalBytesOut);
|
data.push(entry.netStats.totalGigaBytesOut);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -106,9 +116,10 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: data,
|
data: data,
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
borderColor: '#007bff',
|
borderColor: '#ff5733',
|
||||||
borderWidth: 4,
|
borderWidth: 4,
|
||||||
pointBackgroundColor: '#007bff'
|
pointBackgroundColor: '#ff5733',
|
||||||
|
radius: 0
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -166,32 +177,28 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
|
||||||
}
|
}
|
||||||
|
|
||||||
private refreshNetStatsHistory(): void {
|
private refreshNetStatsHistory(): void {
|
||||||
if (!this.netStatsBytesInChart) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const last = this.daemonData.netStatsHistory.last;
|
const last = this.daemonData.netStatsHistory.last;
|
||||||
|
|
||||||
if (!this.netStatsBytesInChart || !this.netStatsBytesOutChart) {
|
if (!this.netStatsBytesInChart || !this.netStatsBytesOutChart) {
|
||||||
this.initNetStatsHistoryChart();
|
this.initNetStatsHistoryChart();
|
||||||
}
|
}
|
||||||
else if (last) {
|
else if (last) {
|
||||||
const label = `${last.date.toLocaleTimeString()} ${last.date.toLocaleDateString()}`;
|
const label = `${last.date.toLocaleDateString()} ${last.date.toLocaleTimeString()}`;
|
||||||
|
|
||||||
this.netStatsBytesInChart.data.labels?.push(label);
|
this.netStatsBytesInChart.data.labels?.push(label);
|
||||||
this.netStatsBytesInChart.data.datasets.forEach((dataset) => {
|
this.netStatsBytesInChart.data.datasets.forEach((dataset) => {
|
||||||
dataset.data.push(last.netStats.totalBytesIn);
|
dataset.data.push(last.netStats.totalGigaBytesIn);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.netStatsBytesOutChart.data.labels?.push(label);
|
this.netStatsBytesOutChart.data.labels?.push(label);
|
||||||
this.netStatsBytesOutChart.data.datasets.forEach((dataset) => {
|
this.netStatsBytesOutChart.data.datasets.forEach((dataset) => {
|
||||||
dataset.data.push(last.netStats.totalBytesOut);
|
dataset.data.push(last.netStats.totalGigaBytesOut);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.netStatsBytesInChart.update();
|
this.netStatsBytesInChart.update();
|
||||||
this.netStatsBytesOutChart.update();
|
this.netStatsBytesOutChart.update();
|
||||||
|
this.currentNetStats = last.netStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setLimit(): Promise<void> {
|
public async setLimit(): Promise<void> {
|
||||||
|
|
|
@ -1,34 +1,46 @@
|
||||||
export class NetStats {
|
export class NetStats {
|
||||||
public readonly startTime: number;
|
public readonly startTime: number;
|
||||||
public readonly totalPacketsIn: number;
|
public readonly totalPacketsIn: number;
|
||||||
public readonly totalBytesIn: number;
|
public readonly totalBytesIn: number;
|
||||||
public readonly totalBytesOut: number;
|
public readonly totalBytesOut: number;
|
||||||
|
|
||||||
constructor(startTime: number, totalPacketsIn: number, totalBytesIn: number, totalBytesOut: number) {
|
public get totalKiloBytesIn(): number {
|
||||||
this.startTime = startTime;
|
return this.totalBytesIn / 1000;
|
||||||
this.totalPacketsIn = totalPacketsIn;
|
}
|
||||||
this.totalBytesIn = totalBytesIn;
|
|
||||||
this.totalBytesOut = totalBytesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static parse(netStats: any): NetStats {
|
public get totalKiloBytesOut(): number {
|
||||||
const startTime: number = netStats.start_time;
|
return this.totalBytesOut / 1000;
|
||||||
const totalPacketsIn: number = netStats.total_packets_in;
|
}
|
||||||
const totalBytesIn: number = netStats.total_bytes_in;
|
|
||||||
const totalBytesOut: number = netStats.total_bytes_out;
|
|
||||||
|
|
||||||
return new NetStats(startTime, totalPacketsIn, totalBytesIn, totalBytesOut);
|
public get totalMegaBytesIn(): number {
|
||||||
}
|
return this.totalKiloBytesIn / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get totalMegaBytesOut(): number {
|
||||||
|
return this.totalKiloBytesOut / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get totalGigaBytesIn(): number {
|
||||||
|
return this.totalMegaBytesIn / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get totalGigaBytesOut(): number {
|
||||||
|
return this.totalMegaBytesOut / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(startTime: number, totalPacketsIn: number, totalBytesIn: number, totalBytesOut: number) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
this.totalPacketsIn = totalPacketsIn;
|
||||||
|
this.totalBytesIn = totalBytesIn;
|
||||||
|
this.totalBytesOut = totalBytesOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static parse(netStats: any): NetStats {
|
||||||
|
const startTime: number = netStats.start_time;
|
||||||
|
const totalPacketsIn: number = netStats.total_packets_in;
|
||||||
|
const totalBytesIn: number = netStats.total_bytes_in;
|
||||||
|
const totalBytesOut: number = netStats.total_bytes_out;
|
||||||
|
|
||||||
|
return new NetStats(startTime, totalPacketsIn, totalBytesIn, totalBytesOut);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* start_time - unsigned int; Unix start time.
|
|
||||||
total_packets_in - unsigned int;
|
|
||||||
total_bytes_in - unsigned int;
|
|
||||||
total_packets_out - unsigned int;
|
|
||||||
total_bytes_out - unsigned int;
|
|
||||||
status - string; General RPC error code. "OK" means everything looks good.
|
|
||||||
untrusted - boolean; States if the result is obtained using the bootstrap mode, and is therefore not trusted (true), or when the daemon is fully synced and thus handles the RPC locally (false).
|
|
||||||
*/
|
|
Loading…
Reference in a new issue