From 9b28d60acf3f9300b11cfc88c3e325efee7dcd42 Mon Sep 17 00:00:00 2001 From: everoddandeven Date: Thu, 26 Sep 2024 18:45:28 +0200 Subject: [PATCH] Version component --- app/main.ts | 33 ++++++++-- src/app/app.component.html | 2 +- .../core/services/daemon/daemon.service.ts | 58 +++++++++++++++-- src/app/pages/detail/detail.component.html | 4 +- src/app/pages/detail/detail.component.ts | 2 + src/app/pages/logs/logs.component.html | 7 +- src/app/pages/logs/logs.component.ts | 9 ++- src/app/pages/version/version.component.html | 28 +++++++- src/app/pages/version/version.component.ts | 42 +++++++++++- .../components/navbar/navbar.component.html | 2 +- .../components/sidebar/sidebar.component.html | 1 + .../components/sidebar/sidebar.component.scss | 64 +++++++++++++++++++ .../components/sidebar/sidebar.component.ts | 2 + src/app/shared/utils/SimpleBootstrapCard.ts | 11 ++++ src/app/shared/utils/index.ts | 1 + src/common/DaemonVersion.ts | 8 ++- src/styles.scss | 2 + 17 files changed, 254 insertions(+), 22 deletions(-) create mode 100644 src/app/shared/utils/SimpleBootstrapCard.ts create mode 100644 src/app/shared/utils/index.ts diff --git a/app/main.ts b/app/main.ts index a85e5cc..389d20c 100644 --- a/app/main.ts +++ b/app/main.ts @@ -10,6 +10,10 @@ let win: BrowserWindow | null = null; const args = process.argv.slice(1), serve = args.some(val => val === '--serve'); +function getMonerodPath(): string { + return path.resolve(__dirname, monerodFilePath); +} + function createWindow(): BrowserWindow { const size = screen.getPrimaryDisplay().workAreaSize; @@ -25,6 +29,7 @@ function createWindow(): BrowserWindow { allowRunningInsecureContent: (serve), contextIsolation: false }, + icon: path.join(__dirname, 'assets/icons/favicon.ico') }); if (serve) { @@ -96,8 +101,20 @@ function execMoneroDaemon(configFilePath: string): ChildProcess { return monerodProcess; } -function startMoneroDaemon(commandOptions: string[], logHandler?: (message: string) => void): ChildProcessWithoutNullStreams { - const monerodPath = path.resolve(__dirname, monerodFilePath); +function getMonerodVersion(monerodFilePath: string): void { + const monerodProcess = spawn(getMonerodPath(), [ '--version' ]); + + monerodProcess.stdout.on('data', (data) => { + win?.webContents.send('on-monerod-version', `${data}`); + }) + + monerodProcess.stderr.on('data', (data) => { + win?.webContents.send('on-monerod-version-error', `${data}`); + }) +} + +function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStreams { + const monerodPath = getMonerodPath(); console.log("Starting monerod daemon with options: " + commandOptions.join(" ")); @@ -106,14 +123,14 @@ function startMoneroDaemon(commandOptions: string[], logHandler?: (message: stri // Gestisci l'output di stdout in streaming monerodProcess.stdout.on('data', (data) => { - console.log(`monerod stdout: ${data}`); + //console.log(`monerod stdout: ${data}`); win?.webContents.send('monero-stdout', `${data}`); // Puoi anche inviare i log all'interfaccia utente tramite IPC }); // Gestisci gli errori in stderr monerodProcess.stderr.on('data', (data) => { - console.error(`monerod stderr: ${data}`); + //console.error(`monerod stderr: ${data}`); win?.webContents.send('monero-stderr', `${data}`); }); @@ -150,10 +167,14 @@ try { } }); - ipcMain.on('start-monerod', (event, configFilePath: string[], logHandler?: (message: string) => void) => { - startMoneroDaemon(configFilePath, logHandler); + ipcMain.on('start-monerod', (event, configFilePath: string[]) => { + startMoneroDaemon(configFilePath); }) + ipcMain.on('get-monerod-version', (event, configFilePath: string) => { + getMonerodVersion(configFilePath); + }); + } catch (e) { // Catch Error // throw e; diff --git a/src/app/app.component.html b/src/app/app.component.html index dba58c2..a3299bb 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,5 +1,5 @@ -
+
diff --git a/src/app/core/services/daemon/daemon.service.ts b/src/app/core/services/daemon/daemon.service.ts index 8d9d3c1..ff34ad0 100644 --- a/src/app/core/services/daemon/daemon.service.ts +++ b/src/app/core/services/daemon/daemon.service.ts @@ -79,6 +79,7 @@ import { resolve } from 'path'; providedIn: 'root' }) export class DaemonService { + private readonly versionApiUrl: string = 'https://api.github.com/repos/monero-project/monero/releases/latest'; private dbName = 'DaemonSettingsDB'; private storeName = 'settingsStore'; private openDbPromise: Promise; @@ -185,6 +186,14 @@ export class DaemonService { await new Promise(f => setTimeout(f, ms)); } + private async get(uri: string): Promise<{[key: string]: any}> { + return await firstValueFrom<{ [key: string]: any }>(this.httpClient.get(`${uri}`,this.headers)); + } + + private async post(uri: string, params: {[key: string]: any} = {}): Promise<{[key: string]: any}> { + return await firstValueFrom<{ [key: string]: any }>(this.httpClient.post(`${uri}`, params, this.headers)); + } + private async callRpc(request: RPCRequest): Promise<{ [key: string]: any }> { try { let method: string = ''; @@ -196,7 +205,7 @@ export class DaemonService { method = request.method; } - const response = await firstValueFrom<{ [key: string]: any }>(this.httpClient.post(`${this.url}/${method}`, request.toDictionary(), this.headers)); + const response = await this.post(`${this.url}/${method}`, request.toDictionary()); if (response.error) { this.raiseRpcError(response.error); @@ -460,10 +469,51 @@ export class DaemonService { return SyncInfo.parse(response.result); } - public async getVersion(): Promise { - const response = await this.callRpc(new GetVersionRequest()); + public async getLatestVersion(): Promise { + const response = await this.get(this.versionApiUrl); - return DaemonVersion.parse(response.result); + if (typeof response.tag_name != 'string') { + throw new Error("Could not get tag name version"); + } + + if (typeof response.name != 'string') { + throw new Error("Could not get name version"); + } + + const nameComponents = response.name.split(","); + + if (nameComponents.length == 0) { + throw new Error("Could not get name"); + } + + const name = nameComponents[0]; + + return new DaemonVersion(0, true, `Monero '${name}' (${response.tag_name}-release)`); + } + + public async getVersion(dontUseRpc: boolean = false): Promise { + if(!dontUseRpc && this.daemonRunning) { + const response = await this.callRpc(new GetVersionRequest()); + + return DaemonVersion.parse(response.result); + } + else if (dontUseRpc) { + const monerodPath: string = ''; // TO DO get local monerod path + + return new Promise((resolve, reject) => { + 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.send('get-monerod-version', monerodPath); + }); + } + + throw new Error("Daemon not running"); } public async getFeeEstimate(): Promise { diff --git a/src/app/pages/detail/detail.component.html b/src/app/pages/detail/detail.component.html index e2d3d53..fac7031 100644 --- a/src/app/pages/detail/detail.component.html +++ b/src/app/pages/detail/detail.component.html @@ -28,7 +28,7 @@
@for(card of cards; track card.header) { - @if(card.loading) { + @if(card.loading && !stoppingDaemon) { } - @else { + @else if (!stoppingDaemon) {
{{card.header}}
diff --git a/src/app/pages/detail/detail.component.ts b/src/app/pages/detail/detail.component.ts index 6e9fa9a..eebc7e6 100644 --- a/src/app/pages/detail/detail.component.ts +++ b/src/app/pages/detail/detail.component.ts @@ -150,6 +150,8 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy { console.error(error); this.daemonRunning = false; } + + this.cards = this.createLoadingCards(); this.startingDaemon = false; }, 500); diff --git a/src/app/pages/logs/logs.component.html b/src/app/pages/logs/logs.component.html index 0165d43..d3f0910 100644 --- a/src/app/pages/logs/logs.component.html +++ b/src/app/pages/logs/logs.component.html @@ -1,4 +1,9 @@ -
+
+

No logs

+

Start monero daemon to enable session logging

+
+ +
{{ line }}
diff --git a/src/app/pages/logs/logs.component.ts b/src/app/pages/logs/logs.component.ts index db6bcdf..11adf80 100644 --- a/src/app/pages/logs/logs.component.ts +++ b/src/app/pages/logs/logs.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Component, NgZone } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, NgZone, ViewChild } from '@angular/core'; import { LogsService } from './logs.service'; import { NavbarService } from '../../shared/components/navbar/navbar.service'; @@ -8,6 +8,7 @@ import { NavbarService } from '../../shared/components/navbar/navbar.service'; styleUrl: './logs.component.scss' }) export class LogsComponent implements AfterViewInit { + @ViewChild('logTerminal', { read: ElementRef }) public logTerminal?: ElementRef; constructor(private navbarService: NavbarService, private logsService: LogsService, private ngZone: NgZone) { this.logsService.onLog.subscribe((message: string) => this.onLog()); @@ -18,14 +19,16 @@ export class LogsComponent implements AfterViewInit { } private onLog(): void { + if (this.logTerminal) this.logTerminal.nativeElement.scrollTop = this.logTerminal.nativeElement.scrollHeight; // Scorri automaticamente in basso setTimeout(() => { this.ngZone.run(() => { this.lines; - const terminalOutput = document.getElementById('terminalOutput'); + const terminalOutput = document.getElementById('terminalOutput'); if (terminalOutput) { terminalOutput.style.width = `${window.innerWidth}`; - terminalOutput.scrollTop = terminalOutput.scrollHeight; + console.log(`scrolling from ${terminalOutput.offsetTop} to ${terminalOutput.scrollHeight}`) + terminalOutput.scrollBy(0, terminalOutput.scrollHeight) } }) diff --git a/src/app/pages/version/version.component.html b/src/app/pages/version/version.component.html index 82d5c5c..982c5db 100644 --- a/src/app/pages/version/version.component.html +++ b/src/app/pages/version/version.component.html @@ -1 +1,27 @@ -

version works!

+
+ @for(card of cards; track card.header) { + @if(card.loading) { + + } + @else { +
+
{{card.header}}
+
+
{{card.content}}
+
+
+ } + } +
\ No newline at end of file diff --git a/src/app/pages/version/version.component.ts b/src/app/pages/version/version.component.ts index 569b6ee..73912ac 100644 --- a/src/app/pages/version/version.component.ts +++ b/src/app/pages/version/version.component.ts @@ -2,6 +2,8 @@ import { AfterViewInit, Component } from '@angular/core'; import { NavbarService } from '../../shared/components/navbar/navbar.service'; import { NavbarLink } from '../../shared/components/navbar/navbar.model'; import { DaemonService } from '../../core/services/daemon/daemon.service'; +import { SimpleBootstrapCard } from '../../shared/utils'; +import { DaemonVersion } from '../../../common/DaemonVersion'; @Component({ selector: 'app-version', @@ -10,14 +12,50 @@ import { DaemonService } from '../../core/services/daemon/daemon.service'; }) export class VersionComponent implements AfterViewInit { private readonly links: NavbarLink[]; + public cards: SimpleBootstrapCard[]; + public currentVersion?: DaemonVersion; + public latestVersion?: DaemonVersion; constructor(private navbarService: NavbarService, private daemonService: DaemonService) { this.links = [ new NavbarLink('pills-overview-tab', '#pills-overview', 'pills-overview', true, 'Overview') ]; + this.cards = this.createCards(); } - ngAfterViewInit(): void { - this.navbarService.setLinks(this.links); + private createCards(): SimpleBootstrapCard[] { + return [ + new SimpleBootstrapCard('Current version', this.currentVersion ? this.currentVersion.fullname : '', this.currentVersion == null), + new SimpleBootstrapCard('Latest version', this.latestVersion ? this.latestVersion.fullname : '', this.latestVersion == null) + ]; } + + private createErrorCards(): SimpleBootstrapCard[] { + return [ + new SimpleBootstrapCard('Current version', 'Error', false), + new SimpleBootstrapCard('Latest version', 'Error', false) + ]; + } + + public ngAfterViewInit(): void { + this.navbarService.setLinks(this.links); + this.load() + .then(() => { + this.cards = this.createCards(); + }) + .catch((error: any) => { + this.currentVersion = undefined; + this.latestVersion = undefined + this.cards = this.createErrorCards(); + }); + } + + public async load(): Promise { + const version = await this.daemonService.getVersion(true); + const latestVersion = await this.daemonService.getLatestVersion(); + + this.currentVersion = version; + this.latestVersion = latestVersion; + } + } diff --git a/src/app/shared/components/navbar/navbar.component.html b/src/app/shared/components/navbar/navbar.component.html index 795c191..bf3ede9 100644 --- a/src/app/shared/components/navbar/navbar.component.html +++ b/src/app/shared/components/navbar/navbar.component.html @@ -1,6 +1,6 @@