Skip to content

Commit

Permalink
Upgrade monerod implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
everoddandeven committed Oct 9, 2024
1 parent d066b7c commit f9d8789
Show file tree
Hide file tree
Showing 10 changed files with 329 additions and 178 deletions.
103 changes: 22 additions & 81 deletions app/main.ts
Original file line number Diff line number Diff line change
@@ -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 * as path from 'path';
import * as fs from 'fs';
Expand Down Expand Up @@ -35,9 +35,10 @@ function createWindow(): BrowserWindow {
nodeIntegration: false,
allowRunningInsecureContent: (serve),
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();
Expand Down Expand Up @@ -72,45 +73,6 @@ function createWindow(): BrowserWindow {
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 {
const monerodProcess = spawn(getMonerodPath(), [ '--version' ]);

Expand Down Expand Up @@ -160,36 +122,6 @@ function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStr
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> => {
return new Promise((resolve, reject) => {
const request = (url: string) => {
Expand Down Expand Up @@ -246,8 +178,6 @@ const downloadFile = (url: string, destinationDir: string, onProgress: (progress
});
};



// Funzione per scaricare e verificare l'hash
const downloadAndVerifyHash = async (hashUrl: string, fileName: string, filePath: string): Promise<boolean> => {
//const hashFilePath = path.join(app.getPath('temp'), 'monero_hashes.txt');
Expand Down Expand Up @@ -366,28 +296,39 @@ try {
const hashUrl = 'https://www.getmonero.org/downloads/hashes.txt';

// 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
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
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);

// Estrai il file
event.sender.send('download-progress', { progress: 100, status: 'Extracting...' });
await extractTarBz2(`${destination}${fileName}`, destination);
const fPath = `${destination}/${fileName}`;
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) {
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 Error
Expand Down
6 changes: 6 additions & 0 deletions app/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,11 @@ contextBridge.exposeInMainWorld('electronAPI', {
},
onDownloadProgress: (callback) => {
ipcRenderer.on('download-progress', callback);
},
selectFolder: () => {
ipcRenderer.invoke('select-folder')
},
onSelectedFolder: (callback) => {
ipcRenderer.on('selected-folder', callback);
}
});
69 changes: 46 additions & 23 deletions src/app/core/services/monero-installer/monero-installer.service.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,59 @@
import { Injectable } from '@angular/core';
import { ElectronService } from '../electron/electron.service';
import { Injectable, NgZone } from '@angular/core';

@Injectable({
providedIn: 'root'
})
export class MoneroInstallerService {
constructor(private electronService: ElectronService) {}

public downloadMonero(downloadUrl: string, destination: string): Promise<void> {
return new Promise((resolve, reject) => {
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 }) => {
console.log(`Progress: ${progress}% - ${status}`);
// Qui puoi aggiornare lo stato di progresso nel tuo componente
});
}
else {
const wdw = (window as any);
private _upgrading: boolean = false;
private _progress: { progress: number, status: string } = { progress: 0, status: 'Starting upgrade' }

public get upgrading(): boolean {
return this._upgrading;
}

public get progress(): { progress: number, status: string } {
return this._progress;
}

constructor(private ngZone: NgZone) {}

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);

if (wdw.electronAPI && wdw.electronAPI.onDownloadProgress && wdw.electronAPI.downloadMonerod) {
wdw.electronAPI.onDownloadProgress((event: any, progress: any) => {
console.log(`Download progress: ${progress}`);
});
wdw.electronAPI.onDownloadProgress((event: any, progress: { progress: number, status: string }) => {
//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);
}
}
});

this._upgrading = false;
return result;
}
catch (error) {
console.error(error);
this._upgrading = false;

throw error;
}

});
}
}
32 changes: 31 additions & 1 deletion src/app/pages/settings/settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,20 @@ <h1 class="h2">Settings</h1>
</div>

<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>&nbsp;&nbsp;
<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>&nbsp;&nbsp;
<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="row g-5 p-2">
<div class="col-md-7 col-lg-10">
Expand All @@ -32,6 +45,23 @@ <h4 class="mb-3">Node</h4>
<small class="text-body-secondary">Path to monerod executable</small>
</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>
Expand Down
51 changes: 49 additions & 2 deletions src/app/pages/settings/settings.component.ts
Original file line number Diff line number Diff line change
@@ -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 { DaemonSettings } from '../../../common/DaemonSettings';
import { DaemonService } from '../../core/services/daemon/daemon.service';
Expand All @@ -16,13 +16,15 @@ export class SettingsComponent implements AfterViewInit {
public currentSettings: DaemonSettings;

public savingChanges: boolean = false;
public savingChangesError = ``;
public savingChangesSuccess: boolean = false;
public rpcLoginUser: string;
public rpcLoginPassword: string;
public loading: boolean;

public networkType: 'mainnet' | 'testnet' | 'stagenet' = 'mainnet';

constructor(private daemonService: DaemonService) {
constructor(private daemonService: DaemonService, private ngZone: NgZone) {
this.loading = true;

this.navbarLinks = [
Expand Down Expand Up @@ -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> {
if (!this.modified) {
return;
Expand All @@ -149,12 +160,21 @@ export class SettingsComponent implements AfterViewInit {
this.savingChanges = true;

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);

this.originalSettings = this.currentSettings.clone();

this.savingChangesError = ``;
this.savingChangesSuccess = true;
}
catch(error) {
console.error(error);
this.savingChangesError = `${error}`;
this.savingChangesSuccess = false;
}

this.savingChanges = false;
Expand All @@ -168,6 +188,33 @@ export class SettingsComponent implements AfterViewInit {
}

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 {
Expand Down
Loading

0 comments on commit f9d8789

Please sign in to comment.