Skip to content

Commit

Permalink
Network methods implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
everoddandeven committed Oct 7, 2024
1 parent ca47455 commit 203fbc9
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 24 deletions.
50 changes: 46 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
13 changes: 12 additions & 1 deletion src/app/core/services/daemon/daemon-data.service.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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;
Expand All @@ -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();

Expand Down Expand Up @@ -139,6 +143,10 @@ export class DaemonDataService {
return this.netStats;
}

public get netStatsHistory(): NetStatsHistory {
return this._netStatsHistory;
}

public get gettingNetStats(): boolean {
return this._gettingNetStats;
}
Expand Down Expand Up @@ -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();
Expand Down
7 changes: 7 additions & 0 deletions src/app/pages/network/network.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ <h1 class="h2">Network</h1>
</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>
Expand Down
141 changes: 135 additions & 6 deletions src/app/pages/network/network.component.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,159 @@
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',
templateUrl: './network.component.html',
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();
}

}
}
20 changes: 8 additions & 12 deletions src/app/pages/settings/settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,19 @@ <h1 class="h2">Settings</h1>
<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>
Expand Down
Loading

0 comments on commit 203fbc9

Please sign in to comment.