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' ]);
monerodProcess.stdout.on('data', (data) => {
win?.webContents.send('on-monerod-version', `${data}`);
win?.webContents.send('monero-version', `${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> => {
return new Promise((resolve, reject) => {
// Crea il file decomprimendo il .bz2 in uno .tar temporaneo
@ -354,11 +346,10 @@ try {
startMoneroDaemon(configFilePath);
})
ipcMain.on('get-monerod-version', (event, configFilePath: string) => {
ipcMain.handle('get-monero-version', (event, configFilePath: string) => {
getMonerodVersion(configFilePath);
});
// Gestione IPC
ipcMain.handle('download-monero', async (event, downloadUrl: string, destination: string) => {
try {

View file

@ -10,5 +10,14 @@ contextBridge.exposeInMainWorld('electronAPI', {
},
onMoneroClose: (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 { APP_CONFIG } from '../environments/environment';
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({
selector: 'app-root',
@ -13,10 +15,16 @@ export class AppComponent {
public loading: boolean;
public daemonRunning: boolean;
public get initializing(): boolean {
return this.daemonData.initializing;
}
constructor(
private electronService: ElectronService,
private translate: TranslateService,
private daemonService: DaemonService
private daemonService: DaemonService,
private daemonData: DaemonDataService,
private LogService: LogsService
) {
this.translate.setDefaultLang('en');
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;
}
/*
if (!this.electronService.isElectron) {
console.error("Could not start monero daemon: not electron app");
return;
}
*/
this.starting = true;
console.log("Starting daemon");
@ -270,7 +263,7 @@ export class DaemonService {
if (this.electronService.ipcRenderer) this.electronService.ipcRenderer.send('start-monerod', settings.toCommandOptions());
else {
const wdw = (window as any).electronAPI.startMonerod(settings.toCommandOptions());
(window as any).electronAPI.startMonerod(settings.toCommandOptions());
}
await this.delay(3000);
@ -546,17 +539,29 @@ export class DaemonService {
}
else if (dontUseRpc) {
const monerodPath: string = ''; // TO DO get local monerod path
const wdw = (window as any);
return new Promise<DaemonVersion>((resolve, reject) => {
this.electronService.ipcRenderer.on('on-monerod-version', (event, version: string) => {
resolve(DaemonVersion.parse(version));
});
if (this.electronService.isElectron) {
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) => {
reject(version);
});
this.electronService.ipcRenderer.on('on-monerod-version-error', (event, version: string) => {
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 './daemon/daemon.service';
export * from './daemon/daemon-data.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="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) {
@if(card.loading && !stoppingDaemon) {
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;" aria-hidden="true">
@ -57,8 +44,6 @@
}
</div>
</div>
<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 { DaemonService } from '../../core/services/daemon/daemon.service';
import { SyncInfo } from '../../../common/SyncInfo';
import { Component, AfterViewInit, NgZone } from '@angular/core';
import { Peer } from '../../../common/Peer';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { NavigationEnd, Router } from '@angular/router';
import { DaemonInfo } from '../../../common/DaemonInfo';
import { LogsService } from '../logs/logs.service';
import { ElectronService } from '../../core/services';
import { DaemonService, DaemonDataService } from '../../core/services';
@Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss']
})
export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
export class DetailComponent implements AfterViewInit {
public daemonRunning: boolean;
public startingDaemon: boolean;
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 daemonRunning(): boolean {
return this.daemonData.running;
}
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 firstLoading: boolean = true;
constructor(
private router: Router,private daemonService: DaemonService,
private navbarService: NavbarService, private logsService: LogsService,
private ngZone: NgZone, private electronService: ElectronService) {
this.daemonRunning = false;
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;
private daemonService: DaemonService,
private navbarService: NavbarService,
private daemonData: DaemonDataService,
private ngZone: NgZone) {
this.navbarLinks = [
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)
];
this.cards = this.createLoadingCards();
this.cards = this.createCards();
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
if (event.url != '/detail') return;
//this.onNavigationEnd();
this.daemonData.syncInfoRefreshEnd.subscribe(() => {
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');
else
{
$table.bootstrapTable('load', this.getPeers());
$table.bootstrapTable('hideLoading');
}
});
this.daemonService.onDaemonStatusChanged.subscribe((running: boolean) => {
this.ngZone.run(() => {
this.daemonRunning = running;
if (!running && this.stoppingDaemon) {
this.stoppingDaemon = false;
}
})
});
this.cards = this.createCards();
})
}
ngOnInit(): void {
console.log('DetailComponent INIT');
}
ngAfterViewInit(): void {
console.log('DetailComponent AFTER VIEW INIT');
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.load().then(() => {
this.cards = this.createCards();
});
});
this.loadInterval = setInterval(() => {
/*
const $table = $('#table');
$table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', {
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[] {
@ -224,8 +155,8 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
new Card('Next needed pruning seed', `${this.nextNeededPruningSeed}`, true),
new Card('Block count', `${this.blockCount}`, true),
new Card('Monero version', this.version, true),
new Card('Blockchain size', this.blockchainSize, true),
new Card('Disk usage', this.diskUsage, true),
new Card('Blockchain size', `${this.blockchainSize} GB`, true),
new Card('Disk usage', `${this.diskUsage} %`, true),
new Card('Transaction count', `${this.txCount}`, 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) {
return [];
}
if (this.firstLoading || this.daemonService.starting) {
if (this.daemonData.initializing || this.daemonService.starting) {
return this.createLoadingCards();
}
return [
@ -247,102 +178,19 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
new Card('Next needed pruning seed', `${this.nextNeededPruningSeed}`),
new Card('Block count', `${this.blockCount}`),
new Card('Monero version', this.version),
new Card('Blockchain size', this.blockchainSize),
new Card('Disk usage', this.diskUsage),
new Card('Blockchain size', `${this.blockchainSize} GB`),
new Card('Disk usage', `${this.diskUsage} %`),
new Card('Transaction count', `${this.txCount}`),
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[] {
if (!this.syncInfo) return [];
if (!this.daemonData.syncInfo) return [];
const peers: any[] = [];
this.syncInfo.peers.forEach((peer: Peer) => peers.push({
this.daemonData.syncInfo.peers.forEach((peer: Peer) => peers.push({
'address': peer.info.address,
'peerId': peer.info.peerId,
'height': peer.info.height,

View file

@ -56,7 +56,8 @@ export class VersionComponent implements AfterViewInit {
}
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();
this.currentVersion = version;

View file

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