Mining methods implementation

Peers methods implementation
This commit is contained in:
everoddandeven 2024-10-08 18:30:07 +02:00
parent eb621860b6
commit 5d4280bcf8
19 changed files with 403 additions and 41 deletions

View file

@ -28,6 +28,7 @@ import { LogsModule } from './pages/logs/logs.module';
import { VersionModule } from './pages/version/version.module';
import { HardForkInfoModule } from './pages/hard-fork-info/hard-fork-info.module';
import { NetworkModule } from './pages/network/network.module';
import { PeersModule } from './pages/peers/peers.module';
// AoT requires an exported function for factories
const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json');
@ -50,6 +51,7 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl
LogsModule,
SettingsModule,
HardForkInfoModule,
PeersModule,
VersionModule,
NetworkModule,
TranslateModule,

View file

@ -1,6 +1,6 @@
import { EventEmitter, Injectable } from '@angular/core';
import { DaemonService } from './daemon.service';
import { BlockCount, BlockHeader, Chain, CoreIsBusyError, DaemonInfo, MinerData, MiningStatus, NetStats, NetStatsHistory, SyncInfo } from '../../../../common';
import { BlockCount, BlockHeader, Chain, CoreIsBusyError, DaemonInfo, MinerData, MiningStatus, NetStats, NetStatsHistory, PublicNode, SyncInfo } from '../../../../common';
@Injectable({
providedIn: 'root'
@ -45,6 +45,9 @@ export class DaemonDataService {
private _minerDataCoreBusyError: boolean = false;
private _gettingMinerData: boolean = false;
private _publicNodes: PublicNode[] = [];
private _gettingPublicNodes: boolean = false;
public readonly syncStart: EventEmitter<void> = new EventEmitter<void>();
public readonly syncEnd: EventEmitter<void> = new EventEmitter<void>();
public readonly syncError: EventEmitter<Error> = new EventEmitter<Error>();
@ -56,7 +59,6 @@ export class DaemonDataService {
public readonly netStatsRefreshEnd: EventEmitter<void> = new EventEmitter<void>();
constructor(private daemonService: DaemonService) {
this.startLoop();
this.daemonService.onDaemonStatusChanged.subscribe((running: boolean) => {
if (running) {
@ -172,6 +174,14 @@ export class DaemonDataService {
return this._gettingMinerData;
}
public get publicNodes(): PublicNode[] {
return this._publicNodes;
}
public get gettingPublicNodes(): boolean {
return this._gettingPublicNodes;
}
public setRefreshTimeout(ms: number = 5000): void {
this.refreshTimeoutMs = ms;
}
@ -314,6 +324,12 @@ export class DaemonDataService {
await this.refreshMinerData();
this._gettingPublicNodes = true;
this._publicNodes = await this.daemonService.getPublicNodes(true, true);
this._gettingPublicNodes = false;
this._lastRefresh = Date.now();
} catch(error) {
console.error(error);
@ -324,6 +340,7 @@ export class DaemonDataService {
this._gettingIsBlockchainPruned = false;
this._gettingAltChains = false;
this._gettingNetStats = false;
this._gettingPublicNodes = false;
this.syncError.emit(<Error>error);

View file

@ -76,7 +76,6 @@ import { TxInfo } from '../../../../common/TxInfo';
import { DaemonSettings } from '../../../../common/DaemonSettings';
import { MethodNotFoundError } from '../../../../common/error/MethodNotFoundError';
import { openDB, IDBPDatabase } from "idb"
import { resolve } from 'path';
@Injectable({
providedIn: 'root'
@ -801,8 +800,8 @@ export class DaemonService {
public async getPublicNodes(whites: boolean = true, grays: boolean = false, includeBlocked: boolean = false): Promise<PublicNode[]> {
const response = await this.callRpc(new GetPublicNodesRequest(whites, grays, includeBlocked));
const _whites: any[] | undefined = response.whites;
const _grays: any[] | undefined = response.grays;
const _whites: any[] | undefined = response.white;
const _grays: any[] | undefined = response.gray;
const nodes: PublicNode[] = [];
if (_whites) _whites.forEach((white) => nodes.push(PublicNode.parse(white, 'white')));

View file

@ -11,7 +11,7 @@
</ul>
</div>
</div>
<div *ngIf="daemonRunning" 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-last-block-header" role="tabpanel" aria-labelledby="pills-last-block-header-tab" tabindex="0">
<div *ngIf="getLastBlockError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
@ -109,6 +109,8 @@
</div>
<div class="tab-pane fade" id="pills-get-block" role="tabpanel" aria-labelledby="pills-get-block-tab" tabindex="0">
<h4 class="mb-3">Get full block information by block height or hash</h4>
<br>
<div *ngIf="getBlockError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
@ -260,6 +262,7 @@
</div>
<div class="tab-pane fade" id="pills-get-block-header" role="tabpanel" aria-labelledby="pills-get-block-header-tab" tabindex="0">
<h4 class="mb-3">Get block header information by block height or hash</h4>
<div *ngIf="blockHeader" class="card p-1">
<div class="card-header bg-primary text-white d-flex">
<h4>Block Header Details</h4>
@ -389,6 +392,7 @@
</div>
<div class="tab-pane fade" id="pills-pop-blocks" role="tabpanel" aria-labelledby="pills-pop-blocks-tab" tabindex="0">
<h4 class="mb-3">Pop blockchain blocks</h4>
<div *ngIf="popBlocksError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
@ -409,7 +413,7 @@
<div class="col-sm-6">
<label for="pop-blocks-nblocks" class="form-label">Blocks to pop</label>
<input type="number" class="form-control" id="pop-blocks-nblocks" placeholder="" [(ngModel)]="popBlocksNBlocks" [ngModelOptions]="{standalone: true}" [disabled]="getBlockHeaderByHash">
<input type="number" min="0" class="form-control" id="pop-blocks-nblocks" placeholder="" [(ngModel)]="popBlocksNBlocks" [ngModelOptions]="{standalone: true}" [disabled]="getBlockHeaderByHash">
<small class="text-body-secondary">Number of blocks top pop from blockchain</small>
</div>
</div>
@ -424,6 +428,15 @@
</div>
<div class="tab-pane fade" id="pills-prune-blockchain" role="tabpanel" aria-labelledby="pills-prune-blockchain-tab" tabindex="0">
<h4 class="mb-3">Prune Blockchain</h4>
<br>
<div class="alert alert-info d-flex text-center" role="alert">
<div>
<i>Pruning</i> allows node operators to save 2/3 of storage space while keeping the full transaction history
</div>
</div>
<div *ngIf="pruneBlockchainError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
@ -438,11 +451,6 @@
</div>
</div>
<div class="alert alert-info d-flex text-center" role="alert">
<div>
'Pruning' allows node operators to save 2/3 of storage space while keeping the full transaction history </div>
</div>
<hr class="my-4">
<button *ngIf="!pruningBlockchain" class="w-100 btn btn-primary btn-lg" type="button" (click)="pruneBlockchain()">Prune Blockchain</button>
@ -451,6 +459,15 @@
</div>
<div class="tab-pane fade" id="pills-save-bc" role="tabpanel" aria-labelledby="pills-save-bc-tab" tabindex="0">
<h4 class="mb-3">Save the blockchain</h4>
<br>
<div class="alert alert-info d-flex text-center" role="alert">
<div>
The blockchain does not need saving and is always saved when modified, however it does a sync to flush the filesystem cache onto the disk for safety purposes against Operating System or Hardware crashes.
</div>
</div>
<div *ngIf="saveBlockchainError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
@ -465,12 +482,6 @@
</div>
</div>
<div class="alert alert-info d-flex text-center" role="alert">
<div>
The blockchain does not need saving and is always saved when modified, however it does a sync to flush the filesystem cache onto the disk for safety purposes against Operating System or Hardware crashes.
</div>
</div>
<hr class="my-4">
<button *ngIf="!savingBlockchain" class="w-100 btn btn-primary btn-lg" type="button" (click)="saveBlockchain()">Save Blockchain</button>

View file

@ -2,6 +2,8 @@ import { AfterViewInit, Component, NgZone } from '@angular/core';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { DaemonService } from '../../core/services/daemon/daemon.service';
import { Block, BlockHeader } from '../../../common';
import { DaemonDataService } from '../../core/services';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
@Component({
selector: 'app-blockchain',
@ -10,7 +12,15 @@ import { Block, BlockHeader } from '../../../common';
})
export class BlockchainComponent implements AfterViewInit {
public readonly navbarLinks: NavbarLink[];
public daemonRunning: boolean = false;
public get daemonRunning(): boolean {
return this.daemonData.running;
}
public get daemonStopping(): boolean {
return this.daemonData.stopping;
}
public lastBlockHeader?: BlockHeader;
public getLastBlockError: string = '';
public block?: Block;
@ -43,7 +53,7 @@ export class BlockchainComponent implements AfterViewInit {
public pruneBlockchainError: string = '';
public blockchainPruned: boolean = false;
constructor(private daemonService: DaemonService, private ngZone: NgZone) {
constructor(private daemonService: DaemonService, private daemonData: DaemonDataService, private navbarService: NavbarService, private ngZone: NgZone) {
this.navbarLinks = [
new NavbarLink('pills-last-block-header-tab', '#pills-last-block-header', 'pills-last-block-header', true, 'Last Block Header'),
new NavbarLink('pills-get-block-tab', '#pills-get-block', 'pills-get-block', false, 'Get Block'),
@ -52,23 +62,10 @@ export class BlockchainComponent implements AfterViewInit {
new NavbarLink('pills-prune-blockchain-tab', '#pills-prune-blockchain', 'pills-prune-blockchain', false, 'Prune'),
new NavbarLink('pills-save-bc-tab', '#pills-save-bc', 'pills-save-bc', false, 'Save')
];
this.daemonService.onDaemonStatusChanged.subscribe((running) => {
this.ngZone.run(() => {
this.daemonRunning = running;
this.navbarLinks.forEach((link) => link.disabled = !running);
});
});
this.daemonService.isRunning().then((value: boolean) => {
this.ngZone.run(() => {
this.daemonRunning = value;
this.navbarLinks.forEach((link) => link.disabled = !value);
});
});
}
ngAfterViewInit(): void {
this.navbarService
this.load();
}

View file

@ -81,7 +81,7 @@
<div *ngIf="miningStatus && !miningStatus.active" class="row g-5 p-2">
<div class="cold-md-7 col-lg-12">
<div class="row gy-3">
<h4 class="mb-3">Start mining on the daemon</h4>
<div class="col-sm-12">
<label for="start-mining-miner-address" class="form-label">Miner Address</label>
<input type="text" class="form-control" id="start-mining-miner-address" placeholder="" [(ngModel)]="startMiningMinerAddress" [ngModelOptions]="{standalone: true}">
@ -123,12 +123,15 @@
</div>
<div class="tab-pane fade" id="pills-miner-data" role="tabpanel" aria-labelledby="pills-miner-data-tab" tabindex="0">
<h4 class="mb-3">Necessary data to create a custom block template, used by p2pool</h4>
<div *ngIf="coreBusy" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
Core is busy: miner data is not available during blockchain sync
</div>
</div>
<div *ngIf="!coreBusy && daemonRunning" class="row d-flex justify-content-center">
@for(card of cards; track card.header) {
@ -143,7 +146,24 @@
</div>
</div>
<div class="tab-pane fade" id="pills-hashrate" role="tabpanel" aria-labelledby="pills-hashrate-tab" tabindex="0">
<h4 class="mb-3">Monero network hash rate</h4>
<div class="row d-flex justify-content-center">
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;">
<div class="card-header">Current Hashrate</div>
<div class="card-body">
<h5 class="card-title">{{networkHashRate}} GH/s</h5>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="pills-alternate-chains" role="tabpanel" aria-labelledby="pills-alternate-chains-tab" tabindex="0">
<h4 class="mb-3">Alternative chains seen by the node</h4>
<div class="m-3">
<table
id="chainsTable"
@ -165,6 +185,7 @@
</div>
<div class="tab-pane fade" id="pills-block-template" role="tabpanel" aria-labelledby="pills-block-template-tab" tabindex="0">
<h4 class="mb-3">Get a block template on which mining a new block</h4>
<div *ngIf="getBlockTemplateError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
@ -308,7 +329,6 @@
<button *ngIf="addingAuxPow" class="w-100 btn btn-primary btn-lg" type="button" disabled>Adding Aux PoW ...</button>
</div>
<div class="tab-pane fade" id="pills-submit-block" role="tabpanel" aria-labelledby="pills-submit-block-tab" tabindex="0">
<div *ngIf="submitBlockError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
@ -409,7 +429,7 @@
<div class="row g-5 p-2">
<div class="cold-md-7 col-lg-12">
<div class="row gy-3">
<h4 class="mb-3">Calculate PoW hash for a block candidate</h4>
<h4 class="mb-3">Generate a block and specify the address to receive the coinbase reward</h4>
<div class="col-sm-6">
<label for="generate-blocks-starting-nonce" class="form-label">Starting Nonce</label>
<input type="number" class="form-control" min="0" id="generate-blocks-starting-nonce" placeholder="" [(ngModel)]="generateStartingNonce" [ngModelOptions]="{standalone: true}">

View file

@ -98,8 +98,15 @@ export class MiningComponent implements AfterViewInit {
return this.daemonData.altChains;
}
public get networkHashRate(): number {
const origValue = this.daemonData.info ? this.daemonData.info.gigaHashRate : 0;
return parseFloat(origValue.toFixed(2));
}
//private txBacklog: MineableTxBacklog[]
public cards: Card[];
public get daemonRunning(): boolean {
return this.daemonData.running;
}
@ -136,6 +143,7 @@ export class MiningComponent implements AfterViewInit {
this.navbarLinks = [
new NavbarLink('pills-mining-status-tab', '#pills-mining-status', 'mining-status', true, 'Status'),
new NavbarLink('pills-miner-data-tab', '#pills-miner-data', 'miner-data', false, 'Miner Data'),
new NavbarLink('pills-hashrate-tab', '#pills-hashrate', 'hashrate', false, 'Hashrate'),
new NavbarLink('pills-alternate-chains-tab', '#pills-alternate-chains', 'alternate-chains', false, 'Alternate Chains'),
new NavbarLink('pills-block-template-tab', '#pills-block-template', 'block-template', false, 'Block Template'),
new NavbarLink('pills-generate-blocks-tab', '#pills-generate-blocks', 'generate-blocks', false, 'Generate Blocks'),

View file

@ -10,7 +10,7 @@ import { MiningComponent } from './mining.component';
@NgModule({
declarations: [MiningComponent],
imports: [
CommonModule, SharedModule,MiningRoutingModule, LoadComponent
CommonModule, SharedModule, MiningRoutingModule, LoadComponent
]
})
export class MiningModule { }

View file

@ -11,7 +11,7 @@
</div>
</div>
<div *ngIf="daemonRunning" 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">
<h2>Bytes In</h2>
<canvas class="my-4 w-100" id="netStatsBytesInChart" width="900" height="380"></canvas>

View file

@ -20,11 +20,14 @@ export class NetworkComponent implements AfterViewInit {
return this.daemonData.running;
}
public get daemonStopping(): boolean {
return this.daemonData.stopping;
}
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')
new NavbarLink('pills-limits-tab', '#pills-limits', 'pills-limits', false, 'Limits')
];
this.daemonData.netStatsRefreshEnd.subscribe(() => {

View file

@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PeersComponent } from './peers.component';
const routes: Routes = [{
path: 'peers',
component: PeersComponent
}];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class PeersRoutingModule { }

View file

@ -0,0 +1,115 @@
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Peers</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
@for(navbarLink of navbarLinks; track navbarLink.name) {
<li class="nav-item mr-2" role="presentation">
<button [class]="navbarLink.selected ? 'nav-link active btn-sm' : 'nav-link btn-sm'" [id]="navbarLink.id" data-bs-toggle="pill" [attr.data-bs-target]="navbarLink.target" type="button" role="tab" [attr.aria-controls]="navbarLink.controls" [attr.aria-selected]="navbarLink.selected" [disabled]="navbarLink.disabled">{{navbarLink.name}}</button>
</li>
}
</ul>
</div>
</div>
<div *ngIf="daemonRunning && !daemonStopping" class="tab-content" id="pills-tabContent">
<div class="tab-pane fade show active" id="pills-public-nodes" role="tabpanel" aria-labelledby="pills-public-nodes-tab" tabindex="0">
<h4 class="mb-3">Public peer information</h4>
<div class="m-3">
<table
id="publicNodesTable"
data-toggle="publicNodesTable"
data-toolbar="#toolbar"
data-height="460"
>
<thead>
<tr>
<th data-field="host">Host</th>
<th data-field="lastSeenDateTime">Last Seen</th>
<th data-field="rpcCreditsPerHash">RPC Credits per Hash</th>
<th data-field="rpcPort">RPC Port</th>
<th data-field="type">Type</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="tab-pane fade" id="pills-in-peers" role="tabpanel" aria-labelledby="pills-in-peers-tab" tabindex="0">
<h4 class="mb3">Limit number of Incoming peers</h4>
<div *ngIf="limitInPeersError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
{{limitInPeersError}}
</div>
</div>
<div *ngIf="limitInPeersSuccess" class="alert alert-success d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-check-circle m-2"></i></h4>&nbsp;&nbsp;
<div>
Incoming peers limit set to {{limitInPeersResult}}
</div>
</div>
<div class="row g-5 p-2">
<div class="cold-md-7 col-lg-12">
<div class="row gy-3">
<div class="col-sm-6">
<label for="limit-in-peers" class="form-label">In Peers</label>
<input type="number" min="0" class="form-control" id="limit-in-peers" placeholder="" [(ngModel)]="limitInPeers" [ngModelOptions]="{standalone: true}">
<small class="text-body-secondary">Max number of incoming peers</small>
</div>
</div>
</div>
</div>
<hr class="my-4">
<button *ngIf="!limitingInPeers" class="w-100 btn btn-primary btn-lg" type="button" (click)="inPeers()">Limit In Peers</button>
<button *ngIf="limitingInPeers" class="w-100 btn btn-primary btn-lg" type="button" disabled>Limiting In Peers ...</button>
</div>
<div class="tab-pane fade" id="pills-out-peers" role="tabpanel" aria-labelledby="pills-out-peers-tab" tabindex="0">
<h4 class="mb3">Limit number of Outgoing peers</h4>
<div *ngIf="limitOutPeersError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
{{limitOutPeersError}}
</div>
</div>
<div *ngIf="limitOutPeersSuccess" class="alert alert-success d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-check-circle m-2"></i></h4>&nbsp;&nbsp;
<div>
Outgoing peers limit set to {{limitOutPeersResult}}
</div>
</div>
<div class="row g-5 p-2">
<div class="cold-md-7 col-lg-12">
<div class="row gy-3">
<div class="col-sm-6">
<label for="limit-out-peers" class="form-label">Out Peers</label>
<input type="number" min="0" class="form-control" id="limit-out-peers" placeholder="" [(ngModel)]="limitOutPeers" [ngModelOptions]="{standalone: true}">
<small class="text-body-secondary">Max number of outgoing peers</small>
</div>
</div>
</div>
</div>
<hr class="my-4">
<button *ngIf="!limitingOutPeers" class="w-100 btn btn-primary btn-lg" type="button" (click)="outPeers()">Limit Out Peers</button>
<button *ngIf="limitingOutPeers" class="w-100 btn btn-primary btn-lg" type="button" disabled>Limiting Out Peers ...</button>
</div>
</div>
<app-daemon-not-running></app-daemon-not-running>
<app-daemon-stopping></app-daemon-stopping>

View file

View file

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PeersComponent } from './peers.component';
describe('PeersComponent', () => {
let component: PeersComponent;
let fixture: ComponentFixture<PeersComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PeersComponent]
})
.compileComponents();
fixture = TestBed.createComponent(PeersComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,108 @@
import { AfterViewInit, Component, NgZone, OnDestroy } from '@angular/core';
import { DaemonDataService, DaemonService } from '../../core/services';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-peers',
templateUrl: './peers.component.html',
styleUrl: './peers.component.scss'
})
export class PeersComponent implements AfterViewInit, OnDestroy {
public readonly navbarLinks: NavbarLink[];
public limitInPeers: number = 0;
public limitingInPeers: boolean = false;
public limitInPeersSuccess: boolean = false;
public limitInPeersError: string = '';
public limitInPeersResult: number = 0;
public limitOutPeers: number = 0;
public limitingOutPeers: boolean = false;
public limitOutPeersSuccess: boolean = false;
public limitOutPeersError: string = '';
public limitOutPeersResult: number = 0;
public get daemonRunning(): boolean {
return this.daemonData.running;
}
public get daemonStopping(): boolean {
return this.daemonData.stopping;
}
private subscriptions: Subscription[] = [];
constructor(private daemonService: DaemonService, private daemonData: DaemonDataService, private navbarService: NavbarService, private ngZone: NgZone) {
this.navbarLinks = [
new NavbarLink('pills-public-nodes-tab', '#pills-public-nodes', 'pills-public-nodes', false, 'Public Nodes'),
new NavbarLink('pills-in-peers-tab', '#pills-in-peers', 'pills-in-peers', false, 'In Peers'),
new NavbarLink('pills-out-peers-tab', '#pills-out-peers', 'pills-out-peers', false, 'Out Peers')
];
}
public ngAfterViewInit(): void {
this.navbarService.setLinks(this.navbarLinks);
this.ngZone.run(() => {
const $publicNodesTable = $('#publicNodesTable');
$publicNodesTable.bootstrapTable({});
$publicNodesTable.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
$publicNodesTable.bootstrapTable('load', this.daemonData.publicNodes);
const sub = this.daemonData.syncEnd.subscribe(() => {
$publicNodesTable.bootstrapTable('load', this.daemonData.publicNodes);
});
this.subscriptions.push(sub);
});
}
public ngOnDestroy(): void {
this.subscriptions.forEach((sub) => {
sub.unsubscribe();
});
this.subscriptions = [];
}
public async inPeers(): Promise<void> {
this.limitingInPeers = true;
try {
this.limitInPeersResult = await this.daemonService.inPeers(this.limitInPeers);
this.limitInPeersError = '';
this.limitInPeersSuccess = true;
} catch(error) {
console.error(error);
this.limitInPeersSuccess = false;
this.limitInPeersResult = 0;
this.limitInPeersError = `${error}`;
}
this.limitingInPeers = false;
}
public async outPeers(): Promise<void> {
this.limitingOutPeers = true;
try {
this.limitOutPeersResult = await this.daemonService.outPeers(this.limitOutPeers);
this.limitOutPeersError = '';
this.limitOutPeersSuccess = true;
} catch(error) {
console.error(error);
this.limitOutPeersSuccess = false;
this.limitOutPeersResult = 0;
this.limitOutPeersError = `${error}`;
}
this.limitingOutPeers = false;
}
}

View file

@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { PeersRoutingModule } from './peers-routing.module';
import { PeersComponent } from './peers.component';
import { SharedModule } from '../../shared/shared.module';
@NgModule({
declarations: [PeersComponent],
imports: [
CommonModule,
SharedModule,
PeersRoutingModule
]
})
export class PeersModule { }

View file

@ -39,6 +39,7 @@ export class SidebarComponent implements OnChanges {
new NavLink('Hard Fork Info', '/hardforkinfo', 'bi bi-signpost-split'),
new NavLink('XMRig', '/xmrig', 'icon-xr text-primary'),
new NavLink('Network', '/network', 'bi bi-hdd-network', 'bottom'),
new NavLink('Peers', '/peers', 'bi bi-people', 'bottom'),
new NavLink('Bans', '/bans', 'bi bi-ban', 'bottom'),
new NavLink('Logs', '/logs', 'bi bi-terminal', 'bottom'),
new NavLink('Version', '/version', 'bi bi-git', 'bottom'),

View file

@ -40,6 +40,28 @@ export class DaemonInfo {
public readonly whitePeerlistSize: number;
public readonly wideCumulativeDifficulty: string;
public readonly wideDifficulty: string;
public get hashRate(): number {
const target = this.target;
if (target <= 0) {
return 0;
}
return this.difficulty / this.target;
}
public get kiloHashRate(): number {
return this.hashRate / 1000;
}
public get megaHashRate(): number {
return this.kiloHashRate / 1000;
}
public get gigaHashRate(): number {
return this.hashRate / 1000;
}
constructor(
adjustedTime: number,

View file

@ -5,12 +5,17 @@ export class PublicNode {
public readonly rpcPort: number;
public readonly type: 'white' | 'gray';
public readonly lastSeenDateTime: string;
constructor(type: 'white' | 'gray', host: string, lastSeen: number, rpcCreditsPerHash: number, rpcPort: number) {
this.host = host;
this.lastSeen = lastSeen;
this.rpcCreditsPerHash = rpcCreditsPerHash;
this.rpcPort = rpcPort;
this.type = type;
const date = new Date(this.lastSeen * 1000);
this.lastSeenDateTime = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
}
public static parse(publicNode: any, nodeType: 'white' | 'gray'): PublicNode {