Daemon data service implementation

This commit is contained in:
everoddandeven 2024-10-01 20:45:10 +02:00
parent b0060fde8a
commit 131199113d
11 changed files with 391 additions and 313 deletions

View file

@ -113,11 +113,11 @@ function getMonerodVersion(monerodFilePath: string): void {
const monerodProcess = spawn(getMonerodPath(), [ '--version' ]); const monerodProcess = spawn(getMonerodPath(), [ '--version' ]);
monerodProcess.stdout.on('data', (data) => { monerodProcess.stdout.on('data', (data) => {
win?.webContents.send('on-monerod-version', `${data}`); win?.webContents.send('monero-version', `${data}`);
}) })
monerodProcess.stderr.on('data', (data) => { monerodProcess.stderr.on('data', (data) => {
win?.webContents.send('on-monerod-version-error', `${data}`); win?.webContents.send('monero-version-error', `${data}`);
}) })
} }
@ -290,14 +290,6 @@ const verifyFileHash = (filePath: string): Promise<string> => {
}); });
}; };
// Funzione per estrarre tar.bz2
const extractTarBz2Old = (filePath: string, destination: string): Promise<void> => {
return tar.x({
file: filePath,
cwd: destination,
});
};
const extractTarBz2 = (filePath: string, destination: string): Promise<void> => { const extractTarBz2 = (filePath: string, destination: string): Promise<void> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// Crea il file decomprimendo il .bz2 in uno .tar temporaneo // Crea il file decomprimendo il .bz2 in uno .tar temporaneo
@ -354,11 +346,10 @@ try {
startMoneroDaemon(configFilePath); startMoneroDaemon(configFilePath);
}) })
ipcMain.on('get-monerod-version', (event, configFilePath: string) => { ipcMain.handle('get-monero-version', (event, configFilePath: string) => {
getMonerodVersion(configFilePath); getMonerodVersion(configFilePath);
}); });
// Gestione IPC // Gestione IPC
ipcMain.handle('download-monero', async (event, downloadUrl: string, destination: string) => { ipcMain.handle('download-monero', async (event, downloadUrl: string, destination: string) => {
try { try {

View file

@ -10,5 +10,14 @@ contextBridge.exposeInMainWorld('electronAPI', {
}, },
onMoneroClose: (callback) => { onMoneroClose: (callback) => {
ipcRenderer.on('monero-close', callback); ipcRenderer.on('monero-close', callback);
},
getMoneroVersion: () => {
ipcRenderer.invoke('get-monero-version');
},
onMoneroVersion: (callback) => {
ipcRenderer.on('monero-version', callback);
},
onMoneroVersionError: (callback) => {
ipcRenderer.on('monero-version-error', callback);
} }
}); });

View file

@ -3,6 +3,8 @@ import { ElectronService } from './core/services';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { APP_CONFIG } from '../environments/environment'; import { APP_CONFIG } from '../environments/environment';
import { DaemonService } from './core/services/daemon/daemon.service'; import { DaemonService } from './core/services/daemon/daemon.service';
import { DaemonDataService } from './core/services/daemon/daemon-data.service';
import { LogsService } from './pages/logs/logs.service';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -13,10 +15,16 @@ export class AppComponent {
public loading: boolean; public loading: boolean;
public daemonRunning: boolean; public daemonRunning: boolean;
public get initializing(): boolean {
return this.daemonData.initializing;
}
constructor( constructor(
private electronService: ElectronService, private electronService: ElectronService,
private translate: TranslateService, private translate: TranslateService,
private daemonService: DaemonService private daemonService: DaemonService,
private daemonData: DaemonDataService,
private LogService: LogsService
) { ) {
this.translate.setDefaultLang('en'); this.translate.setDefaultLang('en');
console.log('APP_CONFIG', APP_CONFIG); console.log('APP_CONFIG', APP_CONFIG);

View file

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { DaemonDataService } from './daemon-data.service';
describe('DaemonDataService', () => {
let service: DaemonDataService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(DaemonDataService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View file

@ -0,0 +1,203 @@
import { EventEmitter, Injectable } from '@angular/core';
import { DaemonService } from './daemon.service';
import { BlockCount, BlockHeader, DaemonInfo, SyncInfo } from '../../../../common';
@Injectable({
providedIn: 'root'
})
export class DaemonDataService {
private refreshTimeoutMs: number = 5000;
private refreshInterval?: NodeJS.Timeout;
private _refreshing: boolean = false;
private _firstRefresh: boolean = true;
private _lastRefresh: number = Date.now();
private _daemonRunning: boolean = false;
private _daemonRestarting: boolean = false;
private _daemonInfo?: DaemonInfo;
private _gettingDaemonInfo: boolean = false;
private _syncInfo?: SyncInfo;
private _gettingSyncInfo: boolean = false;
private _blockCount?: BlockCount;
private _gettingBlockCount: boolean = false;
private _isBlockchainPruned: boolean = false;
private _gettingIsBlockchainPruned: boolean = false;
private _lastBlockHeader?: BlockHeader;
private _gettingLastBlockHeader: 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>();
public readonly syncInfoRefreshStart: EventEmitter<void> = new EventEmitter<void>();
public readonly syncInfoRefreshEnd: EventEmitter<void> = new EventEmitter<void>();
constructor(private daemonService: DaemonService) {
this.startLoop();
this.daemonService.onDaemonStatusChanged.subscribe((running: boolean) => {
if (running) {
this.startLoop();
}
else {
this.stopLoop();
}
})
}
public get initializing(): boolean {
return this._firstRefresh;
}
public get running(): boolean {
return this._daemonRunning;
}
public get starting(): boolean {
return this.daemonService.starting;
}
public get stopping(): boolean {
return this.daemonService.stopping;
}
public get restarting(): boolean {
return this._daemonRestarting;
}
public get refreshing(): boolean {
return this._refreshing;
}
public get info(): DaemonInfo | undefined {
return this._daemonInfo;
}
public get gettingInfo(): boolean {
return this._gettingDaemonInfo;
}
public get syncInfo(): SyncInfo | undefined {
return this._syncInfo;
}
public get gettingSyncInfo(): boolean {
return this._gettingSyncInfo;
}
public get blockCount(): BlockCount | undefined {
return this._blockCount;
}
public get gettingBlockCount(): boolean {
return this._gettingBlockCount;
}
public get isBlockchainPruned(): boolean {
return this._isBlockchainPruned;
}
public get gettingIsBlockchainPruned(): boolean {
return this._gettingIsBlockchainPruned;
}
public get lastBlockHeader(): BlockHeader | undefined {
return this._lastBlockHeader;
}
public get gettingLastBlockHeader(): boolean {
return this._gettingLastBlockHeader;
}
public setRefreshTimeout(ms: number = 5000): void {
this.refreshTimeoutMs = ms;
}
private startLoop(): void {
if (this.refreshInterval != undefined) {
throw new Error("Loop already started");
}
this._firstRefresh = true;
this.refreshInterval = setInterval(() => {
this.refresh();
},this.refreshTimeoutMs);
}
private stopLoop(): void {
if (this.refreshInterval == undefined) {
throw new Error("Loop already stopped");
}
clearInterval(this.refreshInterval);
this.refreshInterval = undefined;
this._refreshing = false;
}
private get tooEarlyForRefresh(): boolean {
return Date.now() - this._lastRefresh <= this.refreshTimeoutMs;
}
private async refresh(): Promise<void> {
if (this.refreshing || this.tooEarlyForRefresh) {
return;
}
this._refreshing = true;
this.syncStart.emit();
try {
const firstRefresh = this._firstRefresh;
this._daemonRunning = await this.daemonService.isRunning();
this._firstRefresh = false;
this._gettingDaemonInfo = true;
this._daemonInfo = await this.daemonService.getInfo();
this._gettingDaemonInfo = false;
this._gettingSyncInfo = true;
this.syncInfoRefreshStart.emit();
this._syncInfo = await this.daemonService.syncInfo();
this._gettingSyncInfo = false;
this.syncInfoRefreshEnd.emit();
this._gettingBlockCount = true;
this._blockCount = await this.daemonService.getBlockCount();
this._gettingBlockCount = false;
this._gettingLastBlockHeader = true;
this._lastBlockHeader = await this.daemonService.getLastBlockHeader(true);
this._gettingLastBlockHeader = false;
this._gettingIsBlockchainPruned = true;
if (firstRefresh) this._isBlockchainPruned = (await this.daemonService.pruneBlockchain(true)).pruned;
this._gettingIsBlockchainPruned = false;
this._lastRefresh = Date.now();
} catch(error) {
console.error(error);
this._gettingDaemonInfo = false;
this._gettingSyncInfo = false;
this._gettingBlockCount = false;
this._gettingLastBlockHeader = false;
this._gettingIsBlockchainPruned = false;
this.syncError.emit(<Error>error);
if (!await this.daemonService.isRunning()) {
this.stopLoop();
}
}
this.syncEnd.emit();
this._firstRefresh = false;
this._refreshing = false;
}
}

View file

@ -256,13 +256,6 @@ export class DaemonService {
return; return;
} }
/*
if (!this.electronService.isElectron) {
console.error("Could not start monero daemon: not electron app");
return;
}
*/
this.starting = true; this.starting = true;
console.log("Starting daemon"); console.log("Starting daemon");
@ -270,7 +263,7 @@ export class DaemonService {
if (this.electronService.ipcRenderer) this.electronService.ipcRenderer.send('start-monerod', settings.toCommandOptions()); if (this.electronService.ipcRenderer) this.electronService.ipcRenderer.send('start-monerod', settings.toCommandOptions());
else { else {
const wdw = (window as any).electronAPI.startMonerod(settings.toCommandOptions()); (window as any).electronAPI.startMonerod(settings.toCommandOptions());
} }
await this.delay(3000); await this.delay(3000);
@ -546,17 +539,29 @@ export class DaemonService {
} }
else if (dontUseRpc) { else if (dontUseRpc) {
const monerodPath: string = ''; // TO DO get local monerod path const monerodPath: string = ''; // TO DO get local monerod path
const wdw = (window as any);
return new Promise<DaemonVersion>((resolve, reject) => { return new Promise<DaemonVersion>((resolve, reject) => {
this.electronService.ipcRenderer.on('on-monerod-version', (event, version: string) => { if (this.electronService.isElectron) {
resolve(DaemonVersion.parse(version)); this.electronService.ipcRenderer.on('on-monerod-version', (event, version: string) => {
}); resolve(DaemonVersion.parse(version));
});
this.electronService.ipcRenderer.on('on-monerod-version-error', (event, version: string) => { this.electronService.ipcRenderer.on('on-monerod-version-error', (event, version: string) => {
reject(version); reject(version);
}); });
this.electronService.ipcRenderer.send('get-monerod-version', monerodPath); this.electronService.ipcRenderer.send('get-monerod-version', monerodPath);
}
else if (wdw.electronAPI && wdw.electronAPI.getMoneroVersion) {
wdw.electronAPI.onMoneroVersion((event: any, version: string) => {
resolve(DaemonVersion.parse(version));
})
wdw.electronAPI.onMoneroVersionError((event: any, error: string) => {
reject(error);
});
wdw.electronAPI.getMoneroVersion();
}
}); });
} }

View file

@ -1,3 +1,4 @@
export * from './electron/electron.service'; export * from './electron/electron.service';
export * from './daemon/daemon.service'; export * from './daemon/daemon.service';
export * from './daemon/daemon-data.service';
export { MoneroInstallerService } from './monero-installer/monero-installer.service'; export { MoneroInstallerService } from './monero-installer/monero-installer.service';

View file

@ -17,19 +17,6 @@
<div class="tab-pane fade show active" id="pills-home" role="tabpanel" aria-labelledby="pills-home-tab" tabindex="0"> <div class="tab-pane fade show active" id="pills-home" role="tabpanel" aria-labelledby="pills-home-tab" tabindex="0">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div *ngIf="daemonRunning" class="card text-bg-dark m-3 text-center" style="max-width: 18rem;">
<div class="card-header"><strong>Daemon running</strong></div>
<div class="card-body">
<h5 class="card-title">
<button *ngIf="!stoppingDaemon" type="button" class="btn btn-danger btn-lg" (click)="stopDaemon()"><i class="bi bi-stop-circle"></i>&nbsp;Stop</button>
<button *ngIf="stoppingDaemon" class="btn btn-danger-light" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Stopping daemon
</button>
</h5>
</div>
</div>
@for(card of cards; track card.header) { @for(card of cards; track card.header) {
@if(card.loading && !stoppingDaemon) { @if(card.loading && !stoppingDaemon) {
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;" aria-hidden="true"> <div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;" aria-hidden="true">
@ -57,8 +44,6 @@
} }
</div> </div>
</div> </div>
<div class="tab-pane fade" id="pills-profile" role="tabpanel" aria-labelledby="pills-profile-tab" tabindex="0"> <div class="tab-pane fade" id="pills-profile" role="tabpanel" aria-labelledby="pills-profile-tab" tabindex="0">

View file

@ -1,81 +1,107 @@
import { Component, OnInit, AfterViewInit, NgZone, OnDestroy } from '@angular/core'; import { Component, AfterViewInit, NgZone } from '@angular/core';
import { DaemonService } from '../../core/services/daemon/daemon.service';
import { SyncInfo } from '../../../common/SyncInfo';
import { Peer } from '../../../common/Peer'; import { Peer } from '../../../common/Peer';
import { NavbarLink } from '../../shared/components/navbar/navbar.model'; import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { NavbarService } from '../../shared/components/navbar/navbar.service'; import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { NavigationEnd, Router } from '@angular/router'; import { DaemonService, DaemonDataService } from '../../core/services';
import { DaemonInfo } from '../../../common/DaemonInfo';
import { LogsService } from '../logs/logs.service';
import { ElectronService } from '../../core/services';
@Component({ @Component({
selector: 'app-detail', selector: 'app-detail',
templateUrl: './detail.component.html', templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss'] styleUrls: ['./detail.component.scss']
}) })
export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { export class DetailComponent implements AfterViewInit {
public daemonRunning: boolean; public get daemonRunning(): boolean {
public startingDaemon: boolean; return this.daemonData.running;
public stoppingDaemon: boolean;
private syncInfo?: SyncInfo;
private daemonInfo?: DaemonInfo;
public readonly navbarLinks: NavbarLink[];
private syncStatus: string;
private height: number;
private targetHeight: number;
private nextNeededPruningSeed: number;
private overview: string;
private blockCount: number;
private version: string;
private blockchainSize: string;
private diskUsage: string;
private networkType: string;
private connectionStatus: string;
private txCount: number;
private poolSize: number;
private nodeType: string;
private syncProgress: string;
private isLoading: boolean;
private loadInterval?: any;
public get loading(): boolean {
return this.isLoading;
} }
public get startingDaemon(): boolean {
return this.daemonData.starting;
}
public get stoppingDaemon(): boolean {
return this.daemonData.stopping;
}
public readonly navbarLinks: NavbarLink[];
//private get syncStatus: string;
//#region Sync Info
private get height(): number {
return this.daemonData.syncInfo ? this.daemonData.syncInfo.height : 0;
}
private get targetHeight(): number {
return this.daemonData.syncInfo ? this.daemonData.syncInfo.targetHeight : 0;
}
private get nextNeededPruningSeed(): number {
return this.daemonData.syncInfo ? this.daemonData.syncInfo.nextNeededPruningSeed : 0;
}
private get overview(): string {
return this.daemonData.syncInfo ? this.daemonData.syncInfo.overview : '[]';
}
//#endregion
private get blockCount(): number {
return this.daemonData.blockCount ? this.daemonData.blockCount.count : 0;
}
//#region Daemon Info
private get version(): string {
return this.daemonData.info ? this.daemonData.info.version : 'Unknown';
}
private get blockchainSize(): number {
return this.daemonData.info ? parseFloat((this.daemonData.info.databaseSize / 1000 / 1000 / 1000).toFixed(2)) : 0;
}
private get capacity(): number {
return this.daemonData.info ? this.daemonData.info.freeSpace + this.daemonData.info.databaseSize : 0;
}
private get diskUsage(): number {
return this.daemonData.info ? parseFloat((this.daemonData.info.databaseSize * 100 / this.capacity).toFixed(2)) : 0;
}
private get networkType(): string {
return this.daemonData.info ? this.daemonData.info.nettype : 'unknown';
}
private get connectionStatus(): string {
return this.daemonData.info ? this.daemonData.info.offline ? 'offline' : 'online' : 'offline';
}
private get txCount(): number {
return this.daemonData.info ? this.daemonData.info.txCount : 0;
}
private get poolSize(): number {
return this.daemonData.info ? this.daemonData.info.txPoolSize : 0;
}
private get nodeType(): string {
return this.daemonData.isBlockchainPruned ? 'pruned' : 'full';
}
private get syncProgress(): string {
return `${(this.height*100/this.targetHeight).toFixed(2)} %`;
}
//#endregion
public cards: Card[]; public cards: Card[];
public firstLoading: boolean = true;
constructor( constructor(
private router: Router,private daemonService: DaemonService, private daemonService: DaemonService,
private navbarService: NavbarService, private logsService: LogsService, private navbarService: NavbarService,
private ngZone: NgZone, private electronService: ElectronService) { private daemonData: DaemonDataService,
this.daemonRunning = false; private ngZone: NgZone) {
this.startingDaemon = false;
this.stoppingDaemon = false;
this.syncStatus = 'Not synced';
this.height = 0;
this.targetHeight = 0;
this.nextNeededPruningSeed = 0;
this.overview = '';
this.blockCount = 0;
this.version = '';
this.diskUsage = '0 %';
this.networkType = '';
this.connectionStatus = 'offline';
this.txCount = 0;
this.poolSize = 0;
this.nodeType = 'unknown';
this.blockchainSize = '0 GB';
this.syncProgress = '0 %';
this.isLoading = false;
this.navbarLinks = [ this.navbarLinks = [
new NavbarLink('pills-home-tab', '#pills-home', 'pills-home', true, 'Overview', true), new NavbarLink('pills-home-tab', '#pills-home', 'pills-home', true, 'Overview', true),
@ -83,135 +109,40 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
new NavbarLink('pills-spans-tab', '#pills-spans', 'pills-spans', false, 'Spans', true) new NavbarLink('pills-spans-tab', '#pills-spans', 'pills-spans', false, 'Spans', true)
]; ];
this.cards = this.createLoadingCards(); this.cards = this.createCards();
this.router.events.subscribe((event) => { this.daemonData.syncInfoRefreshEnd.subscribe(() => {
if (event instanceof NavigationEnd) { const $table = $('#table');
if (event.url != '/detail') return; //$table.bootstrapTable({});
//this.onNavigationEnd(); $table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
if (this.getPeers().length == 0) $table.bootstrapTable('showLoading');
else
{
$table.bootstrapTable('load', this.getPeers());
$table.bootstrapTable('hideLoading');
} }
});
this.daemonService.onDaemonStatusChanged.subscribe((running: boolean) => { this.cards = this.createCards();
this.ngZone.run(() => { })
this.daemonRunning = running;
if (!running && this.stoppingDaemon) {
this.stoppingDaemon = false;
}
})
});
} }
ngOnInit(): void {
console.log('DetailComponent INIT');
}
ngAfterViewInit(): void { ngAfterViewInit(): void {
console.log('DetailComponent AFTER VIEW INIT'); console.log('DetailComponent AFTER VIEW INIT');
this.navbarService.setLinks(this.navbarLinks); this.navbarService.setLinks(this.navbarLinks);
setTimeout(() => {
this.ngZone.run(() => {
const $table = $('#table');
$table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
$table.bootstrapTable('showLoading');
/*
$table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
*/
});
}, 1000);
if (this.loadInterval != null) return;
this.ngZone.run(() => { this.ngZone.run(() => {
this.load().then(() => {
this.cards = this.createCards();
});
});
this.loadInterval = setInterval(() => {
/*
const $table = $('#table'); const $table = $('#table');
$table.bootstrapTable({}); $table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', { $table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped' classes: 'table table-bordered table-hover table-dark table-striped'
}); });
*/
if (this.stoppingDaemon) return;
this.ngZone.run(() => { $table.bootstrapTable('showLoading');
this.load().then(() => { });
this.cards = this.createCards();
});
}, 5000);
})
}
ngOnDestroy(): void {
console.log("DetailComponent ON DESTROY");
if(this.loadInterval != null) {
clearInterval(this.loadInterval);
}
}
public async startDaemon(): Promise<void> {
if (this.daemonRunning) {
console.warn("Daemon already running");
return;
}
if (this.startingDaemon || this.stoppingDaemon) {
return;
}
this.startingDaemon = true;
setTimeout(async () => {
try {
await this.daemonService.startDaemon();
this.daemonRunning = await this.daemonService.isRunning();
}
catch(error) {
console.error(error);
this.daemonRunning = false;
}
this.cards = this.createLoadingCards();
this.startingDaemon = false;
}, 500);
}
public async stopDaemon(): Promise<void> {
if (this.stoppingDaemon || this.startingDaemon || !this.daemonRunning) {
return;
}
this.stoppingDaemon = true;
try {
if (this.loadInterval) clearInterval(this.loadInterval);
await this.daemonService.stopDaemon();
if(!this.electronService.isElectron) this.daemonRunning = false;
}
catch (error) {
console.error(error);
}
if(!this.electronService.isElectron) this.stoppingDaemon = false;
} }
private createLoadingCards(): Card[] { private createLoadingCards(): Card[] {
@ -224,8 +155,8 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
new Card('Next needed pruning seed', `${this.nextNeededPruningSeed}`, true), new Card('Next needed pruning seed', `${this.nextNeededPruningSeed}`, true),
new Card('Block count', `${this.blockCount}`, true), new Card('Block count', `${this.blockCount}`, true),
new Card('Monero version', this.version, true), new Card('Monero version', this.version, true),
new Card('Blockchain size', this.blockchainSize, true), new Card('Blockchain size', `${this.blockchainSize} GB`, true),
new Card('Disk usage', this.diskUsage, true), new Card('Disk usage', `${this.diskUsage} %`, true),
new Card('Transaction count', `${this.txCount}`, true), new Card('Transaction count', `${this.txCount}`, true),
new Card('Pool size', `${this.poolSize}`, true) new Card('Pool size', `${this.poolSize}`, true)
]; ];
@ -235,7 +166,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
if (!this.daemonRunning && !this.daemonService.starting) { if (!this.daemonRunning && !this.daemonService.starting) {
return []; return [];
} }
if (this.firstLoading || this.daemonService.starting) { if (this.daemonData.initializing || this.daemonService.starting) {
return this.createLoadingCards(); return this.createLoadingCards();
} }
return [ return [
@ -247,102 +178,19 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
new Card('Next needed pruning seed', `${this.nextNeededPruningSeed}`), new Card('Next needed pruning seed', `${this.nextNeededPruningSeed}`),
new Card('Block count', `${this.blockCount}`), new Card('Block count', `${this.blockCount}`),
new Card('Monero version', this.version), new Card('Monero version', this.version),
new Card('Blockchain size', this.blockchainSize), new Card('Blockchain size', `${this.blockchainSize} GB`),
new Card('Disk usage', this.diskUsage), new Card('Disk usage', `${this.diskUsage} %`),
new Card('Transaction count', `${this.txCount}`), new Card('Transaction count', `${this.txCount}`),
new Card('Pool size', `${this.poolSize}`) new Card('Pool size', `${this.poolSize}`)
]; ];
} }
private async load(): Promise<void> {
if (this.isLoading) {
return;
}
try {
this.isLoading = true;
this.daemonRunning = await this.daemonService.isRunning();
if (!this.daemonRunning) {
this.navbarService.disableLinks();
this.isLoading = false;
return;
}
this.navbarService.enableLinks();
const $table = $('#table');
$table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
if (this.getPeers().length == 0) $table.bootstrapTable('showLoading');
this.syncInfo = await this.daemonService.syncInfo();
this.height = this.syncInfo.height;
this.targetHeight = this.syncInfo.targetHeight;
this.nextNeededPruningSeed = this.syncInfo.nextNeededPruningSeed;
if (this.height > 0 && this.targetHeight == 0) {
this.targetHeight = this.height;
this.syncStatus = 'Daemon synced';
}
else if (this.height > 0 && this.targetHeight > 0 && this.height == this.targetHeight) {
this.syncStatus = 'Daemon synced';
}
this.overview = this.syncInfo.overview;
const blockCount = await this.daemonService.getBlockCount();
this.blockCount = blockCount.count;
//const version = await this.daemonService.getVersion();
//this.version = `${version.version}`;
this.daemonInfo = await this.daemonService.getInfo();
const capacity: number = this.daemonInfo.freeSpace + this.daemonInfo.databaseSize;
const diskUsage = parseInt(`${this.daemonInfo.databaseSize * 100 / capacity}`);
const blockchainSize = (this.daemonInfo.databaseSize / 1000 / 1000 / 1000).toFixed(2);
this.blockchainSize = `${blockchainSize} GB`;
this.diskUsage = `${diskUsage} %`;
this.networkType = this.daemonInfo.nettype;
this.connectionStatus = this.daemonInfo.offline ? 'offline' : 'online';
this.txCount = this.daemonInfo.txCount;
this.poolSize = this.daemonInfo.txPoolSize;
this.version = this.daemonInfo.version;
this.syncProgress = `${(this.height*100/this.targetHeight).toFixed(2)} %`;
const blockchainPruned = await this.isBlockchainPruned();
//const blockchainPruned = false;
this.nodeType = blockchainPruned ? 'pruned' : 'full';
$table.bootstrapTable('load', this.getPeers());
$table.bootstrapTable('hideLoading');
}
catch(error) {
console.error(error);
}
this.isLoading = false;
this.firstLoading = false;
}
public async isBlockchainPruned(): Promise<boolean> {
const result = await this.daemonService.pruneBlockchain(true);
return result.pruned;
}
public getPeers(): any[] { public getPeers(): any[] {
if (!this.syncInfo) return []; if (!this.daemonData.syncInfo) return [];
const peers: any[] = []; const peers: any[] = [];
this.syncInfo.peers.forEach((peer: Peer) => peers.push({ this.daemonData.syncInfo.peers.forEach((peer: Peer) => peers.push({
'address': peer.info.address, 'address': peer.info.address,
'peerId': peer.info.peerId, 'peerId': peer.info.peerId,
'height': peer.info.height, 'height': peer.info.height,

View file

@ -56,7 +56,8 @@ export class VersionComponent implements AfterViewInit {
} }
public async load(): Promise<void> { public async load(): Promise<void> {
const version = await this.daemonService.getVersion(this.electronService.isElectron); const isElectron = this.electronService.isElectron || (window as any).electronAPI != null;
const version = await this.daemonService.getVersion(isElectron);
const latestVersion = await this.daemonService.getLatestVersion(); const latestVersion = await this.daemonService.getLatestVersion();
this.currentVersion = version; this.currentVersion = version;

View file

@ -1,17 +1,25 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { NavbarLink } from './navbar.model'; import { NavbarLink } from './navbar.model';
import { DaemonService } from '../../../core/services';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class NavbarService { export class NavbarService {
private _navbarLinks: NavbarLink[] = []; private _navbarLinks: NavbarLink[] = [];
private daemonRunning: boolean = false;
public get links(): NavbarLink[] { public get links(): NavbarLink[] {
return this._navbarLinks; return this._navbarLinks;
} }
constructor() { } constructor(private daemonService: DaemonService) {
this.daemonService.onDaemonStatusChanged.subscribe((running: boolean) => {
this.daemonRunning = running;
if (!running) this.disableLinks();
if (running) this.enableLinks();
})
}
public addLink(... navbarLinks: NavbarLink[]): void { public addLink(... navbarLinks: NavbarLink[]): void {
navbarLinks.forEach((navLink: NavbarLink) => this._navbarLinks.push(navLink)); navbarLinks.forEach((navLink: NavbarLink) => this._navbarLinks.push(navLink));
@ -19,6 +27,9 @@ export class NavbarService {
public setLinks(navbarLinks: NavbarLink[]): void { public setLinks(navbarLinks: NavbarLink[]): void {
this._navbarLinks = navbarLinks; this._navbarLinks = navbarLinks;
if (this.daemonRunning) this.enableLinks();
else this.disableLinks();
} }
public removeLinks(): void { public removeLinks(): void {