diff --git a/app/main.ts b/app/main.ts index 067a39e..f3e38a6 100644 --- a/app/main.ts +++ b/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 * as path from 'path'; import * as fs from 'fs'; @@ -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(); @@ -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' ]); @@ -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 => { - 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 => { return new Promise((resolve, reject) => { const request = (url: string) => { @@ -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 => { //const hashFilePath = path.join(app.getPath('temp'), 'monero_hashes.txt'); @@ -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 diff --git a/app/preload.js b/app/preload.js index 9551ee4..906c446 100644 --- a/app/preload.js +++ b/app/preload.js @@ -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); } }); diff --git a/src/app/core/services/monero-installer/monero-installer.service.ts b/src/app/core/services/monero-installer/monero-installer.service.ts index bd5ea46..b6200b1 100644 --- a/src/app/core/services/monero-installer/monero-installer.service.ts +++ b/src/app/core/services/monero-installer/monero-installer.service.ts @@ -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) {} + private _upgrading: boolean = false; + private _progress: { progress: number, status: string } = { progress: 0, status: 'Starting upgrade' } - public downloadMonero(downloadUrl: string, destination: string): Promise { - return new Promise((resolve, reject) => { - if (this.electronService.isElectron) { - this.electronService.ipcRenderer.invoke('download-monero', downloadUrl, destination) - .then(() => resolve()) - .catch((error) => reject(error)); + public get upgrading(): boolean { + return this._upgrading; + } - 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 { + public get progress(): { progress: number, status: string } { + return this._progress; + } + + constructor(private ngZone: NgZone) {} + + public async downloadMonero(downloadUrl: string, destination: string): Promise { + this._upgrading = true; + + try { + const result = await new Promise((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; + } - }); } } diff --git a/src/app/pages/settings/settings.component.html b/src/app/pages/settings/settings.component.html index e16c836..4d5f025 100644 --- a/src/app/pages/settings/settings.component.html +++ b/src/app/pages/settings/settings.component.html @@ -14,7 +14,20 @@
- + + + +
@@ -32,6 +45,23 @@ Path to monerod executable
+
+ + +
+ Upgrade monerod automatically when a new version is available +
+ +
+ +
+ + +
+ + Folder where to save updates +
+
diff --git a/src/app/pages/settings/settings.component.ts b/src/app/pages/settings/settings.component.ts index 899defb..be68777 100644 --- a/src/app/pages/settings/settings.component.ts +++ b/src/app/pages/settings/settings.component.ts @@ -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'; @@ -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 = [ @@ -141,6 +143,15 @@ export class SettingsComponent implements AfterViewInit { } } + public onMonerodDownloadPathChange(): void { + if (document) { + const element = document.getElementById('general-download-monerod-path'); + if (element.files) { + this.currentSettings.downloadUpgradePath = element.files[0].path; + } + } + } + public async OnSave(): Promise { if (!this.modified) { return; @@ -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; @@ -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 { diff --git a/src/app/pages/version/version.component.html b/src/app/pages/version/version.component.html index 5fe5dc9..8241a86 100644 --- a/src/app/pages/version/version.component.html +++ b/src/app/pages/version/version.component.html @@ -2,44 +2,65 @@

Version

-
- @for(card of cards; track card.header) { - @if(card.loading) { -