Better network charts

This commit is contained in:
everoddandeven 2024-10-26 14:46:46 +02:00
parent 388021b25b
commit 80e0a5091b
6 changed files with 103 additions and 60 deletions

View file

@ -400,6 +400,14 @@ export class DaemonService {
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();
if (!this.settings.noSync && !this.settings.syncOnWifi && await this.isWifiConnected()) {

View file

@ -47,7 +47,23 @@ export abstract class BasePageComponent implements AfterContentInit, OnDestroy {
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)) {
this.initTable(id);
}
@ -60,10 +76,11 @@ export abstract class BasePageComponent implements AfterContentInit, OnDestroy {
const $table = this.initializedTables[id] as JQuery<HTMLElement>;
$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];
if (!$table) {
@ -76,7 +93,7 @@ export abstract class BasePageComponent implements AfterContentInit, OnDestroy {
this.initializedTables[id] = undefined;
}
private destroyTables(): void {
protected destroyTables(): void {
for(const key in this.initializedTables) {
this.destroyTable(key);
}

View file

@ -150,13 +150,13 @@ export class DetailComponent extends BasePageComponent implements AfterViewInit
this.ngZone.run(() => {
this.cards = this.createCards();
this.loadTables(true);
});
});
const syncInfoRefreshEndSub: Subscription = this.daemonData.syncInfoRefreshEnd.subscribe(() => {
this.loadTables();
this.cards = this.createCards();
this.loadTables();
});
this.subscriptions.push(syncStartSub, syncInfoRefreshEndSub);
@ -169,17 +169,17 @@ export class DetailComponent extends BasePageComponent implements AfterViewInit
});
}
private loadPeersTable(): void {
this.loadTable('peersTable', this.getPeers());
private loadPeersTable(loading: boolean = false): void {
this.loadTable('peersTable', this.getPeers(), loading);
}
private loadSpansTable(): void {
this.loadTable('spansTable', this.getSpans());
private loadSpansTable(loading: boolean = false): void {
this.loadTable('spansTable', this.getSpans(), loading);
}
private loadTables(): void {
this.loadPeersTable();
this.loadSpansTable();
private loadTables(loading: boolean = false): void {
this.loadPeersTable(loading);
this.loadSpansTable(loading);
}
private createCards(): SimpleBootstrapCard[] {

View file

@ -14,10 +14,10 @@
<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">
<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>
<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>
</div>
@ -29,7 +29,6 @@
id="connectionsTable"
data-toggle="connectionsTable"
data-toolbar="#toolbar"
data-pagination="true"
>
<thead>

View file

@ -3,7 +3,7 @@ import { NavbarService } from '../../shared/components/navbar/navbar.service';
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';
import { NetStats, NetStatsHistoryEntry } from '../../../common';
import { Subscription } from 'rxjs';
import { BasePageComponent } from '../base-page/base-page.component';
@ -32,6 +32,8 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
public setLimitSuccess: boolean = false;
public setLimitError: string = '';
public currentNetStats: NetStats;
constructor(navbarService: NavbarService, private daemonService: DaemonService, private daemonData: DaemonDataService) {
super(navbarService);
this.setLinks([
@ -40,6 +42,9 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
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(() => {
this.refreshNetStatsHistory();
});
@ -54,6 +59,10 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
this.netStatsBytesInChart.destroy();
this.netStatsBytesInChart = undefined;
}
if (this.netStatsBytesOutChart) {
this.netStatsBytesOutChart.destroy();
this.netStatsBytesOutChart = undefined;
}
}
else {
this.initNetStatsHistoryChart();
@ -78,7 +87,7 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
const data: number[] = [];
this.daemonData.netStatsHistory.history.forEach((entry: NetStatsHistoryEntry) => {
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
data.push(entry.netStats.totalBytesIn);
data.push(entry.netStats.totalGigaBytesIn);
});
return {
@ -86,9 +95,10 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
datasets: [{
data: data,
backgroundColor: 'transparent',
borderColor: '#007bff',
borderColor: '#ff5733',
borderWidth: 4,
pointBackgroundColor: '#007bff'
pointBackgroundColor: '#ff5733',
radius: 0
}]
};
}
@ -98,7 +108,7 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
const data: number[] = [];
this.daemonData.netStatsHistory.history.forEach((entry: NetStatsHistoryEntry) => {
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
data.push(entry.netStats.totalBytesOut);
data.push(entry.netStats.totalGigaBytesOut);
});
return {
@ -106,9 +116,10 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
datasets: [{
data: data,
backgroundColor: 'transparent',
borderColor: '#007bff',
borderColor: '#ff5733',
borderWidth: 4,
pointBackgroundColor: '#007bff'
pointBackgroundColor: '#ff5733',
radius: 0
}]
};
}
@ -166,32 +177,28 @@ export class NetworkComponent extends BasePageComponent implements AfterViewInit
}
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()}`;
const label = `${last.date.toLocaleDateString()} ${last.date.toLocaleTimeString()}`;
this.netStatsBytesInChart.data.labels?.push(label);
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.datasets.forEach((dataset) => {
dataset.data.push(last.netStats.totalBytesOut);
dataset.data.push(last.netStats.totalGigaBytesOut);
});
this.netStatsBytesInChart.update();
this.netStatsBytesOutChart.update();
this.currentNetStats = last.netStats;
}
}
public async setLimit(): Promise<void> {

View file

@ -1,34 +1,46 @@
export class NetStats {
public readonly startTime: number;
public readonly totalPacketsIn: number;
public readonly totalBytesIn: number;
public readonly totalBytesOut: number;
public readonly startTime: number;
public readonly totalPacketsIn: number;
public readonly totalBytesIn: number;
public readonly totalBytesOut: number;
constructor(startTime: number, totalPacketsIn: number, totalBytesIn: number, totalBytesOut: number) {
this.startTime = startTime;
this.totalPacketsIn = totalPacketsIn;
this.totalBytesIn = totalBytesIn;
this.totalBytesOut = totalBytesOut;
}
public get totalKiloBytesIn(): number {
return this.totalBytesIn / 1000;
}
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;
public get totalKiloBytesOut(): number {
return this.totalBytesOut / 1000;
}
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).
*/