mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2025-03-12 09:30:30 +00:00
Mining methods implementation
Peers methods implementation
This commit is contained in:
parent
eb621860b6
commit
5d4280bcf8
19 changed files with 403 additions and 41 deletions
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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')));
|
||||
|
|
|
@ -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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
<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>
|
||||
<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>
|
||||
|
@ -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}">
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -10,7 +10,7 @@ import { MiningComponent } from './mining.component';
|
|||
@NgModule({
|
||||
declarations: [MiningComponent],
|
||||
imports: [
|
||||
CommonModule, SharedModule,MiningRoutingModule, LoadComponent
|
||||
CommonModule, SharedModule, MiningRoutingModule, LoadComponent
|
||||
]
|
||||
})
|
||||
export class MiningModule { }
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
14
src/app/pages/peers/peers-routing.module.ts
Normal file
14
src/app/pages/peers/peers-routing.module.ts
Normal 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 { }
|
115
src/app/pages/peers/peers.component.html
Normal file
115
src/app/pages/peers/peers.component.html
Normal 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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
0
src/app/pages/peers/peers.component.scss
Normal file
0
src/app/pages/peers/peers.component.scss
Normal file
23
src/app/pages/peers/peers.component.spec.ts
Normal file
23
src/app/pages/peers/peers.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
108
src/app/pages/peers/peers.component.ts
Normal file
108
src/app/pages/peers/peers.component.ts
Normal 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;
|
||||
}
|
||||
|
||||
}
|
17
src/app/pages/peers/peers.module.ts
Normal file
17
src/app/pages/peers/peers.module.ts
Normal 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 { }
|
|
@ -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'),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue