mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2024-10-30 02:37:36 +00:00
Upgrade monerod implementation
This commit is contained in:
parent
d066b7cdaa
commit
f9d878906f
10 changed files with 327 additions and 176 deletions
103
app/main.ts
103
app/main.ts
|
@ -1,4 +1,4 @@
|
||||||
import {app, BrowserWindow, ipcMain, screen} from 'electron';
|
import {app, BrowserWindow, ipcMain, screen, dialog } from 'electron';
|
||||||
import { ChildProcess, ChildProcessWithoutNullStreams, exec, spawn } from 'child_process';
|
import { ChildProcess, ChildProcessWithoutNullStreams, exec, spawn } from 'child_process';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
@ -35,9 +35,10 @@ function createWindow(): BrowserWindow {
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
allowRunningInsecureContent: (serve),
|
allowRunningInsecureContent: (serve),
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
devTools: true
|
devTools: true,
|
||||||
},
|
},
|
||||||
icon: path.join(__dirname, 'assets/icons/favicon.ico')
|
autoHideMenuBar: true,
|
||||||
|
icon: path.join(__dirname, '../src/assets/icons/favicon.ico')
|
||||||
});
|
});
|
||||||
|
|
||||||
win.webContents.openDevTools();
|
win.webContents.openDevTools();
|
||||||
|
@ -72,45 +73,6 @@ function createWindow(): BrowserWindow {
|
||||||
return win;
|
return win;
|
||||||
}
|
}
|
||||||
|
|
||||||
function execMoneroDaemon(configFilePath: string): ChildProcess {
|
|
||||||
const monerodPath = path.resolve(__dirname, 'path/to/monerod'); // Percorso del binario di monerod
|
|
||||||
//const command = `"${monerodPath}" --config-file "${configFilePath}"`;
|
|
||||||
const command = `/home/sidney/Documenti/monero-x86_64-linux-gnu-v0.18.3.4/monerod --testnet --fast-block-sync 1 --prune-blockchain --sync-pruned-blocks --confirm-external-bind --max-concurrency 1 --log-level 1 --rpc-access-control-origins=*`;
|
|
||||||
|
|
||||||
const monerodProcess = exec(command, (error, stdout, stderr) => {
|
|
||||||
if (error) {
|
|
||||||
console.error(`Errore durante l'avvio di monerod: ${error.message}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stderr) {
|
|
||||||
console.error(`stderr: ${stderr}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`stdout: ${stdout}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Gestisci l'output in tempo reale
|
|
||||||
if (monerodProcess.stdout == null) {
|
|
||||||
throw new Error("No stdout for monero process")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monerodProcess.stderr == null) {
|
|
||||||
throw new Error("No stderr for monero process");
|
|
||||||
}
|
|
||||||
|
|
||||||
monerodProcess.stdout.on('data', (data) => {
|
|
||||||
console.log(`monerod stdout: ${data}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
monerodProcess.stderr.on('data', (data) => {
|
|
||||||
console.error(`monerod stderr: ${data}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
return monerodProcess;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMonerodVersion(monerodFilePath: string): void {
|
function getMonerodVersion(monerodFilePath: string): void {
|
||||||
const monerodProcess = spawn(getMonerodPath(), [ '--version' ]);
|
const monerodProcess = spawn(getMonerodPath(), [ '--version' ]);
|
||||||
|
|
||||||
|
@ -160,36 +122,6 @@ function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStr
|
||||||
return monerodProcess;
|
return monerodProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Funzione per il download
|
|
||||||
const downloadFileOld = (url: string, destination: string, onProgress: (progress: number) => void): Promise<void> => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const file = fs.createWriteStream(destination);
|
|
||||||
https.get(url, (response) => {
|
|
||||||
if (response.statusCode === 200) {
|
|
||||||
const totalBytes = parseInt(response.headers['content-length'] || '0', 10);
|
|
||||||
let downloadedBytes = 0;
|
|
||||||
|
|
||||||
response.on('data', (chunk) => {
|
|
||||||
downloadedBytes += chunk.length;
|
|
||||||
const progress = (downloadedBytes / totalBytes) * 100;
|
|
||||||
onProgress(progress); // Notifica il progresso
|
|
||||||
});
|
|
||||||
|
|
||||||
response.pipe(file);
|
|
||||||
|
|
||||||
file.on('finish', () => {
|
|
||||||
file.close(() => resolve());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reject(new Error(`Failed to download: ${response.statusCode}`));
|
|
||||||
}
|
|
||||||
}).on('error', (err) => {
|
|
||||||
fs.unlink(destination, () => reject(err));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadFile = (url: string, destinationDir: string, onProgress: (progress: number) => void): Promise<string> => {
|
const downloadFile = (url: string, destinationDir: string, onProgress: (progress: number) => void): Promise<string> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const request = (url: string) => {
|
const request = (url: string) => {
|
||||||
|
@ -246,8 +178,6 @@ const downloadFile = (url: string, destinationDir: string, onProgress: (progress
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Funzione per scaricare e verificare l'hash
|
// Funzione per scaricare e verificare l'hash
|
||||||
const downloadAndVerifyHash = async (hashUrl: string, fileName: string, filePath: string): Promise<boolean> => {
|
const downloadAndVerifyHash = async (hashUrl: string, fileName: string, filePath: string): Promise<boolean> => {
|
||||||
//const hashFilePath = path.join(app.getPath('temp'), 'monero_hashes.txt');
|
//const hashFilePath = path.join(app.getPath('temp'), 'monero_hashes.txt');
|
||||||
|
@ -366,28 +296,39 @@ try {
|
||||||
const hashUrl = 'https://www.getmonero.org/downloads/hashes.txt';
|
const hashUrl = 'https://www.getmonero.org/downloads/hashes.txt';
|
||||||
|
|
||||||
// Inizializza il progresso
|
// Inizializza il progresso
|
||||||
event.sender.send('download-progress', { progress: 0, status: 'Starting download...' });
|
event.sender.send('download-progress', { progress: 0, status: 'Starting download' });
|
||||||
|
|
||||||
// Scarica il file Monero
|
// Scarica il file Monero
|
||||||
const fileName = await downloadFile(downloadUrl, destination, (progress) => {
|
const fileName = await downloadFile(downloadUrl, destination, (progress) => {
|
||||||
event.sender.send('download-progress', { progress, status: 'Downloading...' });
|
event.sender.send('download-progress', { progress, status: 'Downloading' });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scarica e verifica l'hash
|
// Scarica e verifica l'hash
|
||||||
event.sender.send('download-progress', { progress: 100, status: 'Verifying hash...' });
|
event.sender.send('download-progress', { progress: 100, status: 'Verifying hash' });
|
||||||
await downloadAndVerifyHash(hashUrl, fileName, destination);
|
await downloadAndVerifyHash(hashUrl, fileName, destination);
|
||||||
|
|
||||||
// Estrai il file
|
// Estrai il file
|
||||||
event.sender.send('download-progress', { progress: 100, status: 'Extracting...' });
|
const fPath = `${destination}/${fileName}`;
|
||||||
await extractTarBz2(`${destination}${fileName}`, destination);
|
event.sender.send('download-progress', { progress: 100, status: 'Extracting' });
|
||||||
|
await extractTarBz2(fPath, destination);
|
||||||
|
|
||||||
event.sender.send('download-progress', { progress: 100, status: 'Download and extraction completed successfully.' });
|
event.sender.send('download-progress', { progress: 100, status: 'Download and extraction completed successfully' });
|
||||||
|
event.sender.send('download-progress', { progress: 200, status: fPath.replace('.tar.bz2', '') });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.sender.send('download-progress', { progress: 0, status: `Error: ${error}` });
|
event.sender.send('download-progress', { progress: 0, status: `Error: ${error}` });
|
||||||
throw new Error(`Error: ${error}`);
|
//throw new Error(`Error: ${error}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('select-folder', async (event) => {
|
||||||
|
const result = await dialog.showOpenDialog({
|
||||||
|
properties: ['openDirectory'], // Specifica che vogliamo solo cartelle
|
||||||
|
});
|
||||||
|
|
||||||
|
const path = result.canceled ? null : result.filePaths[0];
|
||||||
|
|
||||||
|
win?.webContents.send('selected-folder', path ? `${path}` : '');
|
||||||
|
});
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Catch Error
|
// Catch Error
|
||||||
|
|
|
@ -25,5 +25,11 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
},
|
},
|
||||||
onDownloadProgress: (callback) => {
|
onDownloadProgress: (callback) => {
|
||||||
ipcRenderer.on('download-progress', callback);
|
ipcRenderer.on('download-progress', callback);
|
||||||
|
},
|
||||||
|
selectFolder: () => {
|
||||||
|
ipcRenderer.invoke('select-folder')
|
||||||
|
},
|
||||||
|
onSelectedFolder: (callback) => {
|
||||||
|
ipcRenderer.on('selected-folder', callback);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,36 +1,59 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable, NgZone } from '@angular/core';
|
||||||
import { ElectronService } from '../electron/electron.service';
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class MoneroInstallerService {
|
export class MoneroInstallerService {
|
||||||
constructor(private electronService: ElectronService) {}
|
private _upgrading: boolean = false;
|
||||||
|
private _progress: { progress: number, status: string } = { progress: 0, status: 'Starting upgrade' }
|
||||||
|
|
||||||
public downloadMonero(downloadUrl: string, destination: string): Promise<void> {
|
public get upgrading(): boolean {
|
||||||
return new Promise((resolve, reject) => {
|
return this._upgrading;
|
||||||
if (this.electronService.isElectron) {
|
}
|
||||||
this.electronService.ipcRenderer.invoke('download-monero', downloadUrl, destination)
|
|
||||||
.then(() => resolve())
|
|
||||||
.catch((error) => reject(error));
|
|
||||||
|
|
||||||
this.electronService.ipcRenderer.on('download-progress', (event, { progress, status }) => {
|
public get progress(): { progress: number, status: string } {
|
||||||
console.log(`Progress: ${progress}% - ${status}`);
|
return this._progress;
|
||||||
// Qui puoi aggiornare lo stato di progresso nel tuo componente
|
}
|
||||||
});
|
|
||||||
}
|
constructor(private ngZone: NgZone) {}
|
||||||
else {
|
|
||||||
|
public async downloadMonero(downloadUrl: string, destination: string): Promise<string> {
|
||||||
|
this._upgrading = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await new Promise<string>((resolve, reject) => {
|
||||||
const wdw = (window as any);
|
const wdw = (window as any);
|
||||||
|
|
||||||
if (wdw.electronAPI && wdw.electronAPI.onDownloadProgress && wdw.electronAPI.downloadMonerod) {
|
if (wdw.electronAPI && wdw.electronAPI.onDownloadProgress && wdw.electronAPI.downloadMonerod) {
|
||||||
wdw.electronAPI.onDownloadProgress((event: any, progress: any) => {
|
wdw.electronAPI.onDownloadProgress((event: any, progress: { progress: number, status: string }) => {
|
||||||
console.log(`Download progress: ${progress}`);
|
//console.log(`${progress.progress.toFixed(2)} % ${progress.status}`);
|
||||||
|
this.ngZone.run(() => {
|
||||||
|
this._progress = progress;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (progress.status.includes('Error')) {
|
||||||
|
reject(progress.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress.progress == 200) {
|
||||||
|
resolve(progress.status);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
wdw.electronAPI.downloadMonerod(downloadUrl, destination);
|
wdw.electronAPI.downloadMonerod(downloadUrl, destination);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
this._upgrading = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
this._upgrading = false;
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,19 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="!loading" class="tab-content" id="pills-settings-tabContent">
|
<div *ngIf="!loading" class="tab-content" id="pills-settings-tabContent">
|
||||||
|
<div *ngIf="savingChangesError != ''" 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>
|
||||||
|
{{savingChangesError}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="savingChangesSuccess" 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>
|
||||||
|
Successfully saved settings
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane fade show active" id="pills-general" role="tabpanel" aria-labelledby="pills-general-tab" tabindex="0">
|
<div class="tab-pane fade show active" id="pills-general" role="tabpanel" aria-labelledby="pills-general-tab" tabindex="0">
|
||||||
<div class="row g-5 p-2">
|
<div class="row g-5 p-2">
|
||||||
|
@ -32,6 +45,23 @@
|
||||||
<small class="text-body-secondary">Path to monerod executable</small>
|
<small class="text-body-secondary">Path to monerod executable</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check form-switch col-md-6">
|
||||||
|
<label for="upgrade-automatically" class="form-check-label">Upgrade Automatically</label>
|
||||||
|
<input class="form-control form-check-input" type="checkbox" role="switch" id="upgrade-automatically" [checked]="currentSettings.upgradeAutomatically" [(ngModel)]="currentSettings.upgradeAutomatically" [ngModelOptions]="{standalone: true}">
|
||||||
|
<br>
|
||||||
|
<small class="text-body-secondary">Upgrade monerod automatically when a new version is available</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label for="upgrade-download-path" class="form-label">Download path</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input id="upgrade-download-path=" type="text" class="form-control form-control-sm" placeholder="" aria-label="Monerod path" aria-describedby="basic-addon2" [value]="currentSettings.downloadUpgradePath" readonly>
|
||||||
|
<span class="input-group-text" id="basic-addon2"><button type="button" class="btn btn-secondary btn-sm" (click)="chooseMoneroDownloadPath()">Choose folder</button></span>
|
||||||
|
</div>
|
||||||
|
<input type="file" class="form-control d-none" id="general-download-monerod-path" webkitdirectory multiple>
|
||||||
|
<small class="text-body-secondary">Folder where to save updates</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AfterViewInit, Component } from '@angular/core';
|
import { AfterViewInit, Component, NgZone } from '@angular/core';
|
||||||
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
|
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
|
||||||
import { DaemonSettings } from '../../../common/DaemonSettings';
|
import { DaemonSettings } from '../../../common/DaemonSettings';
|
||||||
import { DaemonService } from '../../core/services/daemon/daemon.service';
|
import { DaemonService } from '../../core/services/daemon/daemon.service';
|
||||||
|
@ -16,13 +16,15 @@ export class SettingsComponent implements AfterViewInit {
|
||||||
public currentSettings: DaemonSettings;
|
public currentSettings: DaemonSettings;
|
||||||
|
|
||||||
public savingChanges: boolean = false;
|
public savingChanges: boolean = false;
|
||||||
|
public savingChangesError = ``;
|
||||||
|
public savingChangesSuccess: boolean = false;
|
||||||
public rpcLoginUser: string;
|
public rpcLoginUser: string;
|
||||||
public rpcLoginPassword: string;
|
public rpcLoginPassword: string;
|
||||||
public loading: boolean;
|
public loading: boolean;
|
||||||
|
|
||||||
public networkType: 'mainnet' | 'testnet' | 'stagenet' = 'mainnet';
|
public networkType: 'mainnet' | 'testnet' | 'stagenet' = 'mainnet';
|
||||||
|
|
||||||
constructor(private daemonService: DaemonService) {
|
constructor(private daemonService: DaemonService, private ngZone: NgZone) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
this.navbarLinks = [
|
this.navbarLinks = [
|
||||||
|
@ -141,6 +143,15 @@ export class SettingsComponent implements AfterViewInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onMonerodDownloadPathChange(): void {
|
||||||
|
if (document) {
|
||||||
|
const element = <HTMLInputElement>document.getElementById('general-download-monerod-path');
|
||||||
|
if (element.files) {
|
||||||
|
this.currentSettings.downloadUpgradePath = element.files[0].path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async OnSave(): Promise<void> {
|
public async OnSave(): Promise<void> {
|
||||||
if (!this.modified) {
|
if (!this.modified) {
|
||||||
return;
|
return;
|
||||||
|
@ -149,12 +160,21 @@ export class SettingsComponent implements AfterViewInit {
|
||||||
this.savingChanges = true;
|
this.savingChanges = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (this.currentSettings.upgradeAutomatically && this.currentSettings.downloadUpgradePath == '') {
|
||||||
|
throw new Error('You must set a download path for monerod updates when enabling automatic upgrade');
|
||||||
|
}
|
||||||
|
|
||||||
await this.daemonService.saveSettings(this.currentSettings);
|
await this.daemonService.saveSettings(this.currentSettings);
|
||||||
|
|
||||||
this.originalSettings = this.currentSettings.clone();
|
this.originalSettings = this.currentSettings.clone();
|
||||||
|
|
||||||
|
this.savingChangesError = ``;
|
||||||
|
this.savingChangesSuccess = true;
|
||||||
}
|
}
|
||||||
catch(error) {
|
catch(error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
this.savingChangesError = `${error}`;
|
||||||
|
this.savingChangesSuccess = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.savingChanges = false;
|
this.savingChanges = false;
|
||||||
|
@ -168,6 +188,33 @@ export class SettingsComponent implements AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
input.click();
|
input.click();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public chooseMoneroDownloadPath(): void {
|
||||||
|
/*
|
||||||
|
const input = document.getElementById('general-download-monerod-path');
|
||||||
|
|
||||||
|
if (!input) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.click();
|
||||||
|
*/
|
||||||
|
const wdw = (window as any);
|
||||||
|
|
||||||
|
if (wdw.electronAPI && wdw.electronAPI.selectFolder && wdw.electronAPI.onSelectedFolder) {
|
||||||
|
wdw.electronAPI.onSelectedFolder((event: any, folder: string) => {
|
||||||
|
if (folder == '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.ngZone.run(() => {
|
||||||
|
this.currentSettings.downloadUpgradePath = folder;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
wdw.electronAPI.selectFolder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public chooseXmrigFile(): void {
|
public chooseXmrigFile(): void {
|
||||||
|
|
|
@ -2,44 +2,65 @@
|
||||||
<h1 class="h2">Version</h1>
|
<h1 class="h2">Version</h1>
|
||||||
<div class="btn-toolbar mb-2 mb-md-0">
|
<div class="btn-toolbar mb-2 mb-md-0">
|
||||||
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
|
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
|
||||||
<!--
|
@for(navbarLink of links; track navbarLink.name) {
|
||||||
@for(navbarLink of navbarLinks; track navbarLink.name) {
|
|
||||||
<li class="nav-item mr-2" role="presentation">
|
<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>
|
<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>
|
</li>
|
||||||
} -->
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row d-flex justify-content-center">
|
<div class="tab-content" id="pills-tabContent">
|
||||||
@for(card of cards; track card.header) {
|
<div class="tab-pane fade show active" id="pills-monero" role="tabpanel" aria-labelledby="pills-monero-tab" tabindex="0">
|
||||||
@if(card.loading) {
|
<div *ngIf="upgradeError != ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
|
||||||
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;" aria-hidden="true">
|
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>
|
||||||
<div class="card-header"><strong>{{card.header}}</strong></div>
|
<div>
|
||||||
<div class="card-body">
|
{{upgradeError}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p class="card-text placeholder-glow">
|
<div *ngIf="upgradeSuccess" class="alert alert-success d-flex align-items-center justify-content-center text-center" role="alert">
|
||||||
<span class="placeholder col-7"></span>
|
<h4><i class="bi bi-check-circle m-2"></i></h4>
|
||||||
<span class="placeholder col-4"></span>
|
<div>
|
||||||
<span class="placeholder col-4"></span>
|
Successfully upgraded monerod
|
||||||
<span class="placeholder col-6"></span>
|
|
||||||
<span class="placeholder col-8"></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
@else {
|
|
||||||
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;">
|
<div class="row d-flex justify-content-center">
|
||||||
<div class="card-header"><strong>{{card.header}}</strong></div>
|
@for(card of cards; track card.header) {
|
||||||
<div class="card-body">
|
@if(card.loading) {
|
||||||
<h5 class="card-title">{{card.content}}</h5>
|
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;" aria-hidden="true">
|
||||||
</div>
|
<div class="card-header"><strong>{{card.header}}</strong></div>
|
||||||
</div>
|
<div class="card-body">
|
||||||
}
|
|
||||||
}
|
<p class="card-text placeholder-glow">
|
||||||
|
<span class="placeholder col-7"></span>
|
||||||
|
<span class="placeholder col-4"></span>
|
||||||
|
<span class="placeholder col-4"></span>
|
||||||
|
<span class="placeholder col-6"></span>
|
||||||
|
<span class="placeholder col-8"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@else {
|
||||||
|
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;">
|
||||||
|
<div class="card-header"><strong>{{card.header}}</strong></div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">{{card.content}}</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-4">
|
||||||
|
|
||||||
|
<button *ngIf="!upgrading" class="w-100 btn btn-primary btn-lg" type="submit" (click)="upgrade()" [disabled]="buttonDisabled">{{ buttonTitle }}</button>
|
||||||
|
<button *ngIf="upgrading" class="w-100 btn btn-primary btn-lg" type="button" disabled>
|
||||||
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||||
|
Upgrading monerod
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-4">
|
|
||||||
|
|
||||||
<button class="w-100 btn btn-primary btn-lg" type="submit" (click)="upgrade()">Upgrade</button>
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { NavbarLink } from '../../shared/components/navbar/navbar.model';
|
||||||
import { DaemonService } from '../../core/services/daemon/daemon.service';
|
import { DaemonService } from '../../core/services/daemon/daemon.service';
|
||||||
import { SimpleBootstrapCard } from '../../shared/utils';
|
import { SimpleBootstrapCard } from '../../shared/utils';
|
||||||
import { DaemonVersion } from '../../../common/DaemonVersion';
|
import { DaemonVersion } from '../../../common/DaemonVersion';
|
||||||
import { ElectronService, MoneroInstallerService } from '../../core/services';
|
import { DaemonDataService, ElectronService, MoneroInstallerService } from '../../core/services';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-version',
|
selector: 'app-version',
|
||||||
|
@ -12,16 +12,49 @@ import { ElectronService, MoneroInstallerService } from '../../core/services';
|
||||||
styleUrl: './version.component.scss'
|
styleUrl: './version.component.scss'
|
||||||
})
|
})
|
||||||
export class VersionComponent implements AfterViewInit {
|
export class VersionComponent implements AfterViewInit {
|
||||||
private readonly links: NavbarLink[];
|
public readonly links: NavbarLink[];
|
||||||
public cards: SimpleBootstrapCard[];
|
public cards: SimpleBootstrapCard[];
|
||||||
public currentVersion?: DaemonVersion;
|
public currentVersion?: DaemonVersion;
|
||||||
public latestVersion?: DaemonVersion;
|
public latestVersion?: DaemonVersion;
|
||||||
|
|
||||||
public downloadPath: string = '/home/sidney/monerod/';
|
public downloadPath: string = '/home/sidney/monerod/';
|
||||||
|
|
||||||
constructor(private navbarService: NavbarService, private daemonService: DaemonService, private electronService: ElectronService, private moneroInstaller: MoneroInstallerService) {
|
public get buttonDisabled(): boolean {
|
||||||
|
const title = this.buttonTitle;
|
||||||
|
|
||||||
|
if (title == 'Install') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const configured = this.daemonService.settings.monerodPath != '';
|
||||||
|
const updateAvailable = this.daemonData.info ? this.daemonData.info.updateAvailable : false;
|
||||||
|
|
||||||
|
if (title == 'Upgrade' && configured && updateAvailable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get buttonTitle(): string {
|
||||||
|
const updateAvailable = this.daemonData.info ? this.daemonData.info.updateAvailable : false;
|
||||||
|
|
||||||
|
if (updateAvailable) {
|
||||||
|
return 'Upgrade';
|
||||||
|
}
|
||||||
|
|
||||||
|
const notConfigured = this.daemonService.settings.monerodPath == '';
|
||||||
|
|
||||||
|
if (notConfigured) {
|
||||||
|
return 'Install';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Upgrade';
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private daemonData: DaemonDataService, private daemonService: DaemonService, private electronService: ElectronService, private moneroInstaller: MoneroInstallerService) {
|
||||||
this.links = [
|
this.links = [
|
||||||
new NavbarLink('pills-overview-tab', '#pills-overview', 'pills-overview', true, 'Overview')
|
new NavbarLink('pills-monero-tab', '#pills-monero', 'pills-monero', true, 'Monero')
|
||||||
];
|
];
|
||||||
this.cards = this.createCards();
|
this.cards = this.createCards();
|
||||||
}
|
}
|
||||||
|
@ -43,16 +76,16 @@ export class VersionComponent implements AfterViewInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngAfterViewInit(): void {
|
public ngAfterViewInit(): void {
|
||||||
this.navbarService.setLinks(this.links);
|
this.upgrading = this.moneroInstaller.upgrading;
|
||||||
this.load()
|
this.load()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.cards = this.createCards();
|
this.cards = this.createCards();
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
this.currentVersion = undefined;
|
this.currentVersion = undefined;
|
||||||
this.latestVersion = undefined
|
this.latestVersion = undefined
|
||||||
this.cards = this.createErrorCards();
|
this.cards = this.createErrorCards();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async load(): Promise<void> {
|
public async load(): Promise<void> {
|
||||||
|
@ -64,21 +97,46 @@ export class VersionComponent implements AfterViewInit {
|
||||||
this.latestVersion = latestVersion;
|
this.latestVersion = latestVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public upgrading: boolean = false;
|
||||||
|
public upgradeSuccess: boolean = false;
|
||||||
|
public upgradeError: string = '';
|
||||||
public downloadProgress: number = 100;
|
public downloadProgress: number = 100;
|
||||||
public downloadStatus : string = '';
|
public downloadStatus : string = '';
|
||||||
|
|
||||||
public async upgrade(): Promise<void> {
|
public async upgrade(): Promise<void> {
|
||||||
|
if (this.upgrading) {
|
||||||
|
console.warn("Already upgrading");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const downloadUrl = 'https://downloads.getmonero.org/cli/linux64'; // Cambia in base al sistema
|
this.upgrading = true;
|
||||||
const destination = '/home/sidney/'; // Aggiorna con il percorso desiderato
|
try {
|
||||||
|
const settings = await this.daemonService.getSettings();
|
||||||
|
if (settings.upgradeAutomatically) {
|
||||||
|
throw new Error('Monero Daemon will upgrade automatically');
|
||||||
|
}
|
||||||
|
if (settings.downloadUpgradePath == '') {
|
||||||
|
throw new Error("Download path not configured");
|
||||||
|
}
|
||||||
|
|
||||||
this.moneroInstaller.downloadMonero(downloadUrl, destination)
|
const downloadUrl = 'https://downloads.getmonero.org/cli/linux64'; // Cambia in base al sistema
|
||||||
.then(() => {
|
const destination = settings.downloadUpgradePath; // Aggiorna con il percorso desiderato
|
||||||
console.log('Download completato con successo.');
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Errore:', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const moneroFolder = await this.moneroInstaller.downloadMonero(downloadUrl, destination);
|
||||||
|
|
||||||
|
settings.monerodPath = `${moneroFolder}/monerod`;
|
||||||
|
|
||||||
|
await this.daemonService.saveSettings(settings);
|
||||||
|
|
||||||
|
this.upgradeError = '';
|
||||||
|
this.upgradeSuccess = true;
|
||||||
|
}
|
||||||
|
catch(error) {
|
||||||
|
console.error(error);
|
||||||
|
this.upgradeSuccess = false;
|
||||||
|
this.upgradeError = `${error}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.upgrading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
<div *ngIf="!daemonRunning || stoppingDaemon || restartingDaemon" class="h-100 p-5 text-bg-dark rounded-3 m-4 text-center">
|
<div *ngIf="!daemonRunning || stoppingDaemon || restartingDaemon" class="h-100 p-5 text-bg-dark rounded-3 m-4 text-center">
|
||||||
<h2 *ngIf="!daemonRunning && !startingDaemon && !stoppingDaemon && !restartingDaemon && daemonConfigured"><i class="bi bi-exclamation-diamond m-4"></i> Daemon not running</h2>
|
<h2 *ngIf="!daemonRunning && !startingDaemon && !stoppingDaemon && !restartingDaemon && !upgrading && daemonConfigured"><i class="bi bi-exclamation-diamond m-4"></i> Daemon not running</h2>
|
||||||
<h2 *ngIf="!daemonRunning && !startingDaemon && !stoppingDaemon && !restartingDaemon && !daemonConfigured"><i class="bi bi-exclamation-diamond m-4"></i> Daemon not configured</h2>
|
<h2 *ngIf="!daemonRunning && !startingDaemon && !stoppingDaemon && !restartingDaemon && !upgrading && !daemonConfigured"><i class="bi bi-exclamation-diamond m-4"></i> Daemon not configured or installed</h2>
|
||||||
<h2 *ngIf="restartingDaemon"><i class="bi bi-arrow-clockwise m-4"></i> Daemon restarting</h2>
|
<h2 *ngIf="restartingDaemon && !upgrading"><i class="bi bi-arrow-clockwise m-4"></i> Daemon restarting</h2>
|
||||||
<h2 *ngIf="stoppingDaemon"><i class="bi bi-stop-fill m-4"></i> Daemon is stopping</h2>
|
<h2 *ngIf="stoppingDaemon && !upgrading"><i class="bi bi-stop-fill m-4"></i> Daemon is stopping</h2>
|
||||||
|
<h2 *ngIf="upgrading"><i class="bi bi-cloud-download m-4"></i> Daemon is upgrading</h2>
|
||||||
|
|
||||||
<p *ngIf="!daemonRunning && !startingDaemon && !stoppingDaemon && !restartingDaemon && daemonConfigured">Start monero daemon</p>
|
<p *ngIf="!daemonRunning && !startingDaemon && !stoppingDaemon && !restartingDaemon && daemonConfigured && !upgrading">Start monero daemon</p>
|
||||||
<p *ngIf="!startingDaemon && !startingDaemon && !stoppingDaemon && !restartingDaemon && !daemonConfigured">Configure monero daemon</p>
|
<p *ngIf="!startingDaemon && !startingDaemon && !stoppingDaemon && !restartingDaemon && !daemonConfigured && !upgrading">Configure or install monero daemon</p>
|
||||||
|
|
||||||
<h2 *ngIf="startingDaemon"><i class="bi bi-play-fill m-4"></i> Daemon is starting</h2>
|
<h2 *ngIf="startingDaemon"><i class="bi bi-play-fill m-4"></i> Daemon is starting</h2>
|
||||||
<p *ngIf="startingDaemon">Starting monero daemon</p>
|
<p *ngIf="startingDaemon">Starting monero daemon</p>
|
||||||
<p *ngIf="restartingDaemon">Restarting monero daemon</p>
|
<p *ngIf="restartingDaemon">Restarting monero daemon</p>
|
||||||
|
<p *ngIf="upgrading">Upgrading monero daemon to latest version</p>
|
||||||
|
|
||||||
<button *ngIf="!startingDaemon && !stoppingDaemon && !restartingDaemon && daemonConfigured" class="btn btn-outline-light" type="button" (click)="startDaemon()"><i class="bi bi-play-fill"></i> Start</button>
|
<button *ngIf="!startingDaemon && !stoppingDaemon && !restartingDaemon && !upgrading && daemonConfigured" class="btn btn-outline-light" type="button" (click)="startDaemon()"><i class="bi bi-play-fill"></i> Start</button>
|
||||||
<button *ngIf="startingDaemon" class="btn btn-outline-light" type="button" disabled>
|
<button *ngIf="startingDaemon" class="btn btn-outline-light" type="button" disabled>
|
||||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||||
Starting monerod
|
Starting monerod
|
||||||
|
@ -27,6 +29,12 @@
|
||||||
Stopping monerod
|
Stopping monerod
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button *ngIf="upgrading" class="btn btn-outline-light" type="button" disabled>
|
||||||
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||||
|
{{ progressStatus }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
<button *ngIf="!startingDaemon && !stoppingDaemon && !restartingDaemon" routerLink="/settings" class="btn btn-outline-light" type="button"><i class="bi bi-gear"></i> Configure</button>
|
<button *ngIf="!startingDaemon && !stoppingDaemon && !restartingDaemon && !upgrading" routerLink="/settings" class="btn btn-outline-light" type="button"><i class="bi bi-gear"></i> Configure</button>
|
||||||
</div>
|
<button *ngIf="!startingDaemon && !stoppingDaemon && !restartingDaemon && !upgrading" routerLink="/version" class="btn btn-outline-light" type="button"><i class="bi bi-arrow-down-circle"></i> Install</button>
|
||||||
|
</div>
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, Input, NgZone } from '@angular/core';
|
import { Component, Input, NgZone } from '@angular/core';
|
||||||
import { DaemonService } from '../../../core/services/daemon/daemon.service';
|
import { DaemonService } from '../../../core/services/daemon/daemon.service';
|
||||||
import { DaemonDataService } from '../../../core/services';
|
import { DaemonDataService, MoneroInstallerService } from '../../../core/services';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-daemon-not-running',
|
selector: 'app-daemon-not-running',
|
||||||
|
@ -9,25 +9,39 @@ import { DaemonDataService } from '../../../core/services';
|
||||||
})
|
})
|
||||||
export class DaemonNotRunningComponent {
|
export class DaemonNotRunningComponent {
|
||||||
|
|
||||||
|
public get upgrading(): boolean {
|
||||||
|
return this.installer.upgrading;
|
||||||
|
}
|
||||||
|
|
||||||
public get daemonRunning(): boolean {
|
public get daemonRunning(): boolean {
|
||||||
return this.daemonData.running && !this.startingDaemon && !this.stoppingDaemon && !this.restartingDaemon;
|
return this.daemonData.running && !this.startingDaemon && !this.stoppingDaemon && !this.restartingDaemon && !this.upgrading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public daemonConfigured: boolean = true;
|
public daemonConfigured: boolean = true;
|
||||||
|
|
||||||
public get startingDaemon(): boolean {
|
public get startingDaemon(): boolean {
|
||||||
return this.daemonService.starting && !this.restartingDaemon;
|
return this.daemonService.starting && !this.restartingDaemon && !this.stoppingDaemon && !this.upgrading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get stoppingDaemon(): boolean{
|
public get stoppingDaemon(): boolean{
|
||||||
return this.daemonData.stopping && !this.restartingDaemon;
|
return this.daemonData.stopping && !this.restartingDaemon && !this.startingDaemon && !this.upgrading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get restartingDaemon(): boolean {
|
public get restartingDaemon(): boolean {
|
||||||
return this.daemonService.restarting;
|
return this.daemonService.restarting && ! this.upgrading;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private daemonData: DaemonDataService, private daemonService: DaemonService, private ngZone: NgZone) {
|
public get progressStatus(): string {
|
||||||
|
const progress = this.installer.progress;
|
||||||
|
|
||||||
|
if (progress.status == 'Downloading') {
|
||||||
|
return `${progress.status} ${progress.progress.toFixed(2)} %`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return progress.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private installer: MoneroInstallerService, private daemonData: DaemonDataService, private daemonService: DaemonService, private ngZone: NgZone) {
|
||||||
this.daemonService.getSettings().then((settings) => {
|
this.daemonService.getSettings().then((settings) => {
|
||||||
this.daemonConfigured = settings.monerodPath != '';
|
this.daemonConfigured = settings.monerodPath != '';
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,6 +6,9 @@ export class DaemonSettings {
|
||||||
public syncPeriodFrom: any = '00:00';
|
public syncPeriodFrom: any = '00:00';
|
||||||
public syncPeriodTo: any = '00:00';
|
public syncPeriodTo: any = '00:00';
|
||||||
|
|
||||||
|
public upgradeAutomatically: boolean = false;
|
||||||
|
public downloadUpgradePath: string = '';
|
||||||
|
|
||||||
public logFile: string = '';
|
public logFile: string = '';
|
||||||
public logLevel: number = 0;
|
public logLevel: number = 0;
|
||||||
public maxLogFileSize: number = 104850000;
|
public maxLogFileSize: number = 104850000;
|
||||||
|
|
Loading…
Reference in a new issue