Automatic upgrade and disable sync on wifi implementation

This commit is contained in:
everoddandeven 2024-10-14 23:08:02 +02:00
parent 10f771f890
commit c95017f4d9
10 changed files with 336 additions and 96 deletions

View file

@ -111,6 +111,7 @@ Maybe you only want to execute the application in the browser with hot reload? J
| `npm run ng:serve` | Execute the app in the web browser (DEV mode) | | `npm run ng:serve` | Execute the app in the web browser (DEV mode) |
| `npm run web:build` | Build the app that can be used directly in the web browser. Your built files are in the /dist folder. | | `npm run web:build` | Build the app that can be used directly in the web browser. Your built files are in the /dist folder. |
| `npm run electron:local` | Builds your application and start electron locally | | `npm run electron:local` | Builds your application and start electron locally |
| `npm run electron:local:dev` | Builds your application and start electron locally (DEV MODE) |
| `npm run electron:build` | Builds your application and creates an app consumable based on your operating system | | `npm run electron:build` | Builds your application and creates an app consumable based on your operating system |
**Your application is optimised. Only /dist folder and NodeJS dependencies are included in the final bundle.** **Your application is optimised. Only /dist folder and NodeJS dependencies are included in the final bundle.**

View file

@ -1,5 +1,5 @@
import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions } from 'electron'; import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions } from 'electron';
import { ChildProcessWithoutNullStreams, spawn } from 'child_process'; import { ChildProcessWithoutNullStreams, exec, ExecException, spawn } from 'child_process';
import * as path from 'path'; import * as path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
import * as https from 'https'; import * as https from 'https';
@ -21,7 +21,13 @@ const args = process.argv.slice(1),
function createWindow(): BrowserWindow { function createWindow(): BrowserWindow {
const size = screen.getPrimaryDisplay().workAreaSize; const size = screen.getPrimaryDisplay().workAreaSize;
const wdwIcon = path.join(__dirname, 'assets/icons/monero-symbol-on-white-480.png'); let dirname = __dirname;
if (dirname.endsWith('/app')) {
dirname = dirname.replace('/app', '/src')
}
const wdwIcon = path.join(dirname, 'assets/icons/monero-symbol-on-white-480.png');
const trayMenuTemplate: MenuItemConstructorOptions[] = [ const trayMenuTemplate: MenuItemConstructorOptions[] = [
{ {
@ -128,14 +134,19 @@ function createWindow(): BrowserWindow {
return win; return win;
} }
function isWifiConnected() { function isWifiConnectedOld() {
console.log("isWifiConnected()");
const networkInterfaces = os.networkInterfaces(); const networkInterfaces = os.networkInterfaces();
console.log(`isWifiConnected(): network interfaces ${networkInterfaces}`);
console.log(networkInterfaces);
for (const interfaceName in networkInterfaces) { for (const interfaceName in networkInterfaces) {
const networkInterface = networkInterfaces[interfaceName]; const networkInterface = networkInterfaces[interfaceName];
if (networkInterface) { if (networkInterface) {
for (const network of networkInterface) { for (const network of networkInterface) {
console.log(network);
if (network.family === 'IPv4' && !network.internal && network.mac !== '00:00:00:00:00:00') { if (network.family === 'IPv4' && !network.internal && network.mac !== '00:00:00:00:00:00') {
if (interfaceName.toLowerCase().includes('wifi') || interfaceName.toLowerCase().includes('wlan')) { if (interfaceName.toLowerCase().includes('wifi') || interfaceName.toLowerCase().includes('wlan')) {
return true; return true;
@ -147,6 +158,62 @@ function isWifiConnected() {
return false; return false;
} }
function isConnectedToWiFi(): Promise<boolean> {
return new Promise((resolve, reject) => {
const platform = os.platform(); // Use os to get the platform
let command = '';
if (platform === 'win32') {
// Windows: Use 'netsh' command to check the Wi-Fi status
command = 'netsh wlan show interfaces';
} else if (platform === 'darwin') {
// macOS: Use 'airport' command to check the Wi-Fi status
command = "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | grep 'state: running'";
} else if (platform === 'linux') {
// Linux: Use 'nmcli' to check for Wi-Fi connectivity
command = 'nmcli dev status';
} else {
resolve(false); // Unsupported platform
}
// Execute the platform-specific command
if (command) {
exec(command, (error: ExecException | null, stdout: string, stderr: string) => {
if (error) {
console.error(error);
reject(stderr);
resolve(false); // In case of error, assume not connected to Wi-Fi
} else {
// Check if the output indicates a connected status
if (stdout) {
const components: string[] = stdout.split("\n");
console.log(components);
components.forEach((component: string) => {
if (component.includes('wifi') && !component.includes('--')) {
resolve(true);
}
});
resolve(false);
} else {
resolve(false);
}
}
});
}
});
}
function isWifiConnected() {
isConnectedToWiFi().then((connected: boolean) => {
win?.webContents.send('is-wifi-connected-result', connected);
}).catch((error: any) => {
console.error(error);
win?.webContents.send('is-wifi-connected-result', false);
});
}
function getMonerodVersion(monerodFilePath: string): void { function getMonerodVersion(monerodFilePath: string): void {
const monerodProcess = spawn(monerodFilePath, [ '--version' ]); const monerodProcess = spawn(monerodFilePath, [ '--version' ]);
@ -159,6 +226,8 @@ function getMonerodVersion(monerodFilePath: string): void {
}) })
} }
let moneroFirstStdout: boolean = true;
function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStreams { function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStreams {
const monerodPath = commandOptions.shift(); const monerodPath = commandOptions.shift();
@ -169,25 +238,40 @@ function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStr
console.log("Starting monerod daemon with options: " + commandOptions.join(" ")); console.log("Starting monerod daemon with options: " + commandOptions.join(" "));
moneroFirstStdout = true;
// Avvia il processo usando spawn // Avvia il processo usando spawn
const monerodProcess = spawn(monerodPath, commandOptions); const monerodProcess = spawn(monerodPath, commandOptions);
// Gestisci l'output di stdout in streaming // Gestisci l'output di stdout in streaming
monerodProcess.stdout.on('data', (data) => { monerodProcess.stdout.on('data', (data) => {
//console.log(`monerod stdout: ${data}`); //console.log(`monerod stdout: ${data}`);
const pattern = '**********************************************************************';
if (moneroFirstStdout && data.includes(pattern)) {
win?.webContents.send('monerod-started', true);
moneroFirstStdout = false;
}
win?.webContents.send('monero-stdout', `${data}`); win?.webContents.send('monero-stdout', `${data}`);
// Puoi anche inviare i log all'interfaccia utente tramite IPC // Puoi anche inviare i log all'interfaccia utente tramite IPC
}); });
// Gestisci gli errori in stderr // Gestisci gli errori in stderr
monerodProcess.stderr.on('data', (data) => { monerodProcess.stderr.on('data', (data) => {
//console.error(`monerod stderr: ${data}`); console.error(`monerod error: ${data}`);
if (moneroFirstStdout) {
win?.webContents.send('monerod-started', false);
moneroFirstStdout = false;
}
win?.webContents.send('monero-stderr', `${data}`); win?.webContents.send('monero-stderr', `${data}`);
}); });
// Gestisci la chiusura del processo // Gestisci la chiusura del processo
monerodProcess.on('close', (code) => { monerodProcess.on('close', (code: number) => {
console.log(`monerod chiuso con codice: ${code}`); console.log(`monerod exited with code: ${code}`);
win?.webContents.send('monero-stdout', `monerod exited with code: ${code}`); win?.webContents.send('monero-stdout', `monerod exited with code: ${code}`);
win?.webContents.send('monero-close', code); win?.webContents.send('monero-close', code);
}); });
@ -421,7 +505,8 @@ try {
}); });
ipcMain.handle('is-wifi-connected', async (event) => { ipcMain.handle('is-wifi-connected', async (event) => {
win?.webContents.send('is-wifi-connected-result', isWifiConnected()); isWifiConnected();
//win?.webContents.send('is-wifi-connected-result', isWifiConnected());
}); });
ipcMain.handle('get-os-type', (event) => { ipcMain.handle('get-os-type', (event) => {

View file

@ -6,6 +6,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
startMonerod: (args) => { startMonerod: (args) => {
ipcRenderer.invoke('start-monerod', args); ipcRenderer.invoke('start-monerod', args);
}, },
onMonerodStarted: (callback) => {
ipcRenderer.on('monerod-started', callback);
},
onMoneroStdout: (callback) => { onMoneroStdout: (callback) => {
ipcRenderer.on('monero-stdout', callback); ipcRenderer.on('monero-stdout', callback);
}, },

View file

@ -38,6 +38,7 @@
"electron:serve-tsc": "tsc -p tsconfig.serve.json", "electron:serve-tsc": "tsc -p tsconfig.serve.json",
"electron:serve": "wait-on tcp:4200 && npm run electron:serve-tsc && electron . --serve", "electron:serve": "wait-on tcp:4200 && npm run electron:serve-tsc && electron . --serve",
"electron:local": "npm run build:prod && electron .", "electron:local": "npm run build:prod && electron .",
"electron:local:dev": "npm run build:dev && electron .",
"electron:build": "npm run build:prod && electron-builder build --publish=never", "electron:build": "npm run build:prod && electron-builder build --publish=never",
"test": "ng test --watch=false", "test": "ng test --watch=false",
"test:watch": "ng test", "test:watch": "ng test",

View file

@ -60,7 +60,7 @@ export class DaemonDataService {
private _txPoolBacklog: TxBacklogEntry[] = []; private _txPoolBacklog: TxBacklogEntry[] = [];
private _gettingTxPoolBackLog: boolean = false; private _gettingTxPoolBackLog: boolean = false;
public readonly syncStart: EventEmitter<void> = new EventEmitter<void>(); public readonly syncStart: EventEmitter<{ first: boolean }> = new EventEmitter<{ first: boolean }>();
public readonly syncEnd: EventEmitter<void> = new EventEmitter<void>(); public readonly syncEnd: EventEmitter<void> = new EventEmitter<void>();
public readonly syncError: EventEmitter<Error> = new EventEmitter<Error>(); public readonly syncError: EventEmitter<Error> = new EventEmitter<Error>();
@ -91,7 +91,7 @@ export class DaemonDataService {
} }
public get running(): boolean { public get running(): boolean {
return this._daemonRunning; return this._daemonRunning
} }
public get starting(): boolean { public get starting(): boolean {
@ -239,11 +239,17 @@ export class DaemonDataService {
throw new Error("Loop already started"); throw new Error("Loop already started");
} }
this._firstRefresh = true; this._firstRefresh = true;
this.refreshInterval = setInterval(() => {
this.refresh().then().catch((error: any) => { this.refresh().then(() => {
console.error(error); this.refreshInterval = setInterval(() => {
}); this.refresh().then().catch((error: any) => {
},this.refreshTimeoutMs); console.error(error);
});
},this.refreshTimeoutMs);
}).catch((error: any) => {
console.error(error);
this._refreshing = false;
});
} }
private stopLoop(): void { private stopLoop(): void {
@ -320,7 +326,31 @@ export class DaemonDataService {
} }
this._refreshing = true; this._refreshing = true;
this.syncStart.emit();
const settings = await this.daemonService.getSettings();
const updateInfo = await this.daemonService.checkUpdate()
if (updateInfo.update) {
await this.daemonService.upgrade();
return;
}
const syncAlreadyDisabled = this.daemonService.settings.noSync;
const wifiConnected = await this.daemonService.isWifiConnected();
if (!settings.noSync && !syncAlreadyDisabled && !settings.syncOnWifi && wifiConnected) {
console.log("Disabling sync ...");
await this.daemonService.disableSync();
}
else if (!settings.noSync && syncAlreadyDisabled && !settings.syncOnWifi && !wifiConnected) {
console.log("Enabling sync ...");
await this.daemonService.enableSync();
}
this.syncStart.emit({ first: this._firstRefresh });
try { try {
const firstRefresh = this._firstRefresh; const firstRefresh = this._firstRefresh;
@ -337,6 +367,11 @@ export class DaemonDataService {
this._daemonInfo = await this.daemonService.getInfo(); this._daemonInfo = await this.daemonService.getInfo();
this._gettingDaemonInfo = false; this._gettingDaemonInfo = false;
if (this.daemonService.settings.upgradeAutomatically && this._daemonInfo.updateAvailable) {
await this.daemonService.upgrade();
return;
}
this._gettingSyncInfo = true; this._gettingSyncInfo = true;
this.syncInfoRefreshStart.emit(); this.syncInfoRefreshStart.emit();
this._syncInfo = await this.daemonService.syncInfo(); this._syncInfo = await this.daemonService.syncInfo();

View file

@ -79,6 +79,7 @@ import { DaemonSettings } from '../../../../common/DaemonSettings';
import { MethodNotFoundError } from '../../../../common/error/MethodNotFoundError'; import { MethodNotFoundError } from '../../../../common/error/MethodNotFoundError';
import { openDB, IDBPDatabase } from "idb" import { openDB, IDBPDatabase } from "idb"
import { PeerInfo, TxPool } from '../../../../common'; import { PeerInfo, TxPool } from '../../../../common';
import { MoneroInstallerService } from '../monero-installer/monero-installer.service';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -100,6 +101,9 @@ export class DaemonService {
public stopping: boolean = false; public stopping: boolean = false;
public starting: boolean = false; public starting: boolean = false;
public restarting: boolean = false; public restarting: boolean = false;
public disablingSync: boolean = false;
public enablingSync: boolean = false;
public readonly onDaemonStatusChanged: EventEmitter<boolean> = new EventEmitter<boolean>(); public readonly onDaemonStatusChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
public readonly onDaemonStopStart: EventEmitter<void> = new EventEmitter<void>(); public readonly onDaemonStopStart: EventEmitter<void> = new EventEmitter<void>();
public readonly onDaemonStopEnd: EventEmitter<void> = new EventEmitter<void>(); public readonly onDaemonStopEnd: EventEmitter<void> = new EventEmitter<void>();
@ -111,9 +115,10 @@ export class DaemonService {
"Access-Control-Allow-Methods": 'POST,GET' // this states the allowed methods "Access-Control-Allow-Methods": 'POST,GET' // this states the allowed methods
}; };
constructor(private httpClient: HttpClient, private electronService: ElectronService) { constructor(private installer: MoneroInstallerService, private httpClient: HttpClient, private electronService: ElectronService) {
this.openDbPromise = this.openDatabase(); this.openDbPromise = this.openDatabase();
this.settings = this.loadSettings(); this.settings = new DaemonSettings();
const wdw = (window as any); const wdw = (window as any);
if (this.electronService.isElectron) { if (this.electronService.isElectron) {
@ -132,6 +137,85 @@ export class DaemonService {
} }
} }
public async isWifiConnected(): Promise<boolean> {
try {
return new Promise<boolean>((resolve, reject) => {
try {
window.electronAPI.onIsWifiConnectedResponse((event: any, connected: boolean) => {
console.debug(event);
resolve(connected);
});
window.electronAPI.isWifiConnected();
}
catch(error: any) {
reject(error);
}
});
}
catch(error: any) {
console.error(error);
}
return false;
}
public async disableSync(): Promise<void> {
this.disablingSync = true;
try {
const running: boolean = await this.isRunning();
if (!running) {
throw new Error("Daemon not running");
}
if (this.settings.noSync) {
throw new Error("Daemon already not syncing");
}
await this.stopDaemon();
this.settings.noSync = true;
await this.startDaemon(this.settings);
}
catch(error: any) {
console.error(error);
}
this.disablingSync = false;
}
public async enableSync(): Promise<void> {
this.enablingSync = true;
try {
const running: boolean = await this.isRunning();
if (!running) {
throw new Error("Daemon not running");
}
if (!this.settings.noSync) {
throw new Error("Daemon already not syncing");
}
await this.stopDaemon();
this.settings.noSync = false;
await this.startDaemon(this.settings);
}
catch(error: any) {
console.error(error);
}
this.enablingSync = false;
}
private onClose(): void { private onClose(): void {
this.daemonRunning = false; this.daemonRunning = false;
this.stopping = false; this.stopping = false;
@ -156,7 +240,6 @@ export class DaemonService {
public async saveSettings(settings: DaemonSettings, restartDaemon: boolean = true): Promise<void> { public async saveSettings(settings: DaemonSettings, restartDaemon: boolean = true): Promise<void> {
const db = await this.openDbPromise; const db = await this.openDbPromise;
await db.put(this.storeName, { id: 1, ...settings }); await db.put(this.storeName, { id: 1, ...settings });
this.settings = settings;
if (restartDaemon) { if (restartDaemon) {
const running = await this.isRunning(); const running = await this.isRunning();
@ -178,14 +261,12 @@ export class DaemonService {
const db = await this.openDbPromise; const db = await this.openDbPromise;
const result = await db.get(this.storeName, 1); const result = await db.get(this.storeName, 1);
if (result) { if (result) {
this.settings = DaemonSettings.parse(result); return DaemonSettings.parse(result);
} }
else else
{ {
this.settings = new DaemonSettings(); return new DaemonSettings();
} }
return this.settings;
} }
public async deleteSettings(): Promise<void> { public async deleteSettings(): Promise<void> {
@ -193,32 +274,7 @@ export class DaemonService {
await db.delete(this.storeName, 1); await db.delete(this.storeName, 1);
} }
private loadSettings(): DaemonSettings {
/*
const args = [
'--testnet',
'--fast-block-sync', '1',
'--prune-blockchain',
'--sync-pruned-blocks',
'--confirm-external-bind',
'--max-concurrency', '1',
'--log-level', '1',
'--rpc-access-control-origins=*'
];
*/
const settings = new DaemonSettings();
settings.testnet = true;
settings.fastBlockSync = true;
settings.pruneBlockchain = true;
settings.syncPrunedBlocks = true;
settings.confirmExternalBind = true;
settings.logLevel = 1;
settings.rpcAccessControlOrigins = "*";
return settings;
}
private raiseRpcError(error: RpcError): void { private raiseRpcError(error: RpcError): void {
if (error.code == -9) { if (error.code == -9) {
throw new CoreIsBusyError(); throw new CoreIsBusyError();
} }
@ -229,7 +285,6 @@ export class DaemonService {
{ {
throw new Error(error.message); throw new Error(error.message);
} }
} }
private async delay(ms: number = 0): Promise<void> { private async delay(ms: number = 0): Promise<void> {
@ -281,36 +336,65 @@ export class DaemonService {
} }
} }
public async startDaemon(): Promise<void> { public async startDaemon(customSettings?: DaemonSettings): Promise<void> {
if (await this.isRunning()) { await new Promise<void>(async (resolve, reject) => {
console.warn("Daemon already running"); if (await this.isRunning()) {
return; console.warn("Daemon already running");
} return;
}
this.starting = true; this.starting = true;
console.log("Starting daemon"); console.log("Starting daemon");
const settings = await this.getSettings();
if (this.electronService.ipcRenderer) this.electronService.ipcRenderer.send('start-monerod', settings.toCommandOptions()); this.settings = customSettings ? customSettings : await this.getSettings();
else {
(window as any).electronAPI.startMonerod(settings.toCommandOptions());
}
await this.delay(3000); if (!this.settings.noSync && !this.settings.syncOnWifi) {
const wifiConnected = await this.isWifiConnected();
if (await this.isRunning(true)) { if (wifiConnected) {
console.log("Daemon started"); console.log("Disabling sync ...");
this.onDaemonStatusChanged.emit(true);
} this.settings.noSync = true;
else }
{ }
console.log("Daemon not started"); else if (!this.settings.noSync && !this.settings.syncOnWifi) {
this.onDaemonStatusChanged.emit(false); const wifiConnected = await this.isWifiConnected();
}
if (!wifiConnected) {
console.log("Enabling sync ...");
this.settings.noSync = false;
}
}
window.electronAPI.onMonerodStarted((event: any, started: boolean) => {
console.debug(event);
if (started) {
console.log("Daemon started");
this.onDaemonStatusChanged.emit(true);
resolve();
}
else {
console.log("Daemon not started");
this.onDaemonStatusChanged.emit(false);
reject('Could not start daemon');
}
})
window.electronAPI.startMonerod(this.settings.toCommandOptions());
});
this.starting = false; this.starting = false;
const isRunning: boolean = await this.isRunning(true);
if (!isRunning) {
throw new Error("Daemon started but not running");
}
} }
public async restartDaemon(): Promise<void> { public async restartDaemon(): Promise<void> {
@ -965,6 +1049,25 @@ export class DaemonService {
return response.height; return response.height;
} }
public async upgrade(): Promise<void> {
const settings = await this.getSettings();
if (settings.upgradeAutomatically) {
throw new Error('Monero Daemon will upgrade automatically');
}
if (settings.downloadUpgradePath == '') {
throw new Error("Download path not configured");
}
//const downloadUrl = 'https://downloads.getmonero.org/cli/linux64'; // Cambia in base al sistema
const destination = settings.downloadUpgradePath; // Aggiorna con il percorso desiderato
const moneroFolder = await this.installer.downloadMonero(destination);
settings.monerodPath = `${moneroFolder}/monerod`;
await this.saveSettings(settings);
}
public async update(command: 'check' | 'download', path: string = ''): Promise<UpdateInfo> { public async update(command: 'check' | 'download', path: string = ''): Promise<UpdateInfo> {
const response = await this.callRpc(new UpdateRequest(command, path)); const response = await this.callRpc(new UpdateRequest(command, path));

View file

@ -1,15 +1,16 @@
import { Component, AfterViewInit, NgZone } from '@angular/core'; import { Component, AfterViewInit, NgZone, OnDestroy } from '@angular/core';
import { Peer } from '../../../common/Peer'; import { Peer } from '../../../common/Peer';
import { NavbarLink } from '../../shared/components/navbar/navbar.model'; import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { NavbarService } from '../../shared/components/navbar/navbar.service'; import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { DaemonService, DaemonDataService } from '../../core/services'; import { DaemonService, DaemonDataService } from '../../core/services';
import { Subscription } from 'rxjs';
@Component({ @Component({
selector: 'app-detail', selector: 'app-detail',
templateUrl: './detail.component.html', templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss'] styleUrls: ['./detail.component.scss']
}) })
export class DetailComponent implements AfterViewInit { export class DetailComponent implements AfterViewInit, OnDestroy {
public get daemonRunning(): boolean { public get daemonRunning(): boolean {
return this.daemonData.running; return this.daemonData.running;
@ -107,6 +108,8 @@ export class DetailComponent implements AfterViewInit {
public cards: Card[]; public cards: Card[];
private subscriptions: Subscription[] = [];
constructor( constructor(
private daemonService: DaemonService, private daemonService: DaemonService,
private navbarService: NavbarService, private navbarService: NavbarService,
@ -121,7 +124,18 @@ export class DetailComponent implements AfterViewInit {
this.cards = this.createCards(); this.cards = this.createCards();
this.daemonData.syncInfoRefreshEnd.subscribe(() => { this.subscriptions.push(this.daemonData.syncStart.subscribe((info) => {
if(!info.first) {
return;
}
this.ngZone.run(() => {
this.cards = this.createLoadingCards();
});
}));
this.subscriptions.push(this.daemonData.syncInfoRefreshEnd.subscribe(() => {
const $table = $('#table'); const $table = $('#table');
//$table.bootstrapTable({}); //$table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', { $table.bootstrapTable('refreshOptions', {
@ -135,10 +149,11 @@ export class DetailComponent implements AfterViewInit {
} }
this.cards = this.createCards(); this.cards = this.createCards();
}) }));
} }
ngAfterViewInit(): void { public ngAfterViewInit(): void {
console.log('DetailComponent AFTER VIEW INIT'); console.log('DetailComponent AFTER VIEW INIT');
this.navbarService.setLinks(this.navbarLinks); this.navbarService.setLinks(this.navbarLinks);
this.ngZone.run(() => { this.ngZone.run(() => {
@ -155,6 +170,11 @@ export class DetailComponent implements AfterViewInit {
}); });
} }
public ngOnDestroy(): void {
this.subscriptions.forEach((sub) => sub.unsubscribe());
this.subscriptions = [];
}
private createLoadingCards(): Card[] { private createLoadingCards(): Card[] {
return [ return [
new Card('Connection Status', this.connectionStatus, true), new Card('Connection Status', this.connectionStatus, true),

View file

@ -4,6 +4,7 @@ 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 { DaemonDataService, ElectronService, MoneroInstallerService } from '../../core/services'; import { DaemonDataService, ElectronService, MoneroInstallerService } from '../../core/services';
import { DaemonSettings } from '../../../common';
@Component({ @Component({
selector: 'app-version', selector: 'app-version',
@ -15,6 +16,7 @@ export class VersionComponent implements AfterViewInit {
public cards: SimpleBootstrapCard[]; public cards: SimpleBootstrapCard[];
public currentVersion?: DaemonVersion; public currentVersion?: DaemonVersion;
public latestVersion?: DaemonVersion; public latestVersion?: DaemonVersion;
public settings: DaemonSettings = new DaemonSettings();
public get buttonDisabled(): boolean { public get buttonDisabled(): boolean {
const title = this.buttonTitle; const title = this.buttonTitle;
@ -23,7 +25,7 @@ export class VersionComponent implements AfterViewInit {
return false; return false;
} }
const configured = this.daemonService.settings.monerodPath != ''; const configured = this.settings.monerodPath != '';
const updateAvailable = this.daemonData.info ? this.daemonData.info.updateAvailable : false; const updateAvailable = this.daemonData.info ? this.daemonData.info.updateAvailable : false;
if (title == 'Upgrade' && configured && updateAvailable) { if (title == 'Upgrade' && configured && updateAvailable) {
@ -40,7 +42,7 @@ export class VersionComponent implements AfterViewInit {
return 'Upgrade'; return 'Upgrade';
} }
const notConfigured = this.daemonService.settings.monerodPath == ''; const notConfigured = this.settings.monerodPath == '';
if (notConfigured) { if (notConfigured) {
return 'Install'; return 'Install';
@ -87,6 +89,7 @@ export class VersionComponent implements AfterViewInit {
} }
public async load(): Promise<void> { public async load(): Promise<void> {
this.settings = await this.daemonService.getSettings();
const isElectron = this.electronService.isElectron || (window as any).electronAPI != null; const isElectron = this.electronService.isElectron || (window as any).electronAPI != null;
const version = await this.daemonService.getVersion(isElectron); const version = await this.daemonService.getVersion(isElectron);
const latestVersion = await this.daemonService.getLatestVersion(); const latestVersion = await this.daemonService.getLatestVersion();
@ -109,22 +112,7 @@ export class VersionComponent implements AfterViewInit {
this.upgrading = true; this.upgrading = true;
try { try {
const settings = await this.daemonService.getSettings(); await this.daemonService.upgrade();
if (settings.upgradeAutomatically) {
throw new Error('Monero Daemon will upgrade automatically');
}
if (settings.downloadUpgradePath == '') {
throw new Error("Download path not configured");
}
//const downloadUrl = 'https://downloads.getmonero.org/cli/linux64'; // Cambia in base al sistema
const destination = settings.downloadUpgradePath; // Aggiorna con il percorso desiderato
const moneroFolder = await this.moneroInstaller.downloadMonero(destination);
settings.monerodPath = `${moneroFolder}/monerod`;
await this.daemonService.saveSettings(settings);
this.upgradeError = ''; this.upgradeError = '';
this.upgradeSuccess = true; this.upgradeSuccess = true;

View file

@ -58,10 +58,14 @@ import 'bootstrap-table';
declare global { declare global {
interface Window { interface Window {
electronAPI: { electronAPI: {
startMonerod: (args: string[]) => void; startMonerod: (options: string[]) => void;
onMonerodStarted: (callback: (event: any, started: boolean) => void) => void;
isWifiConnected: () => void;
onIsWifiConnectedResponse: (callback: (event: any, connected: boolean) => void) => void;
getOsType: () => void; getOsType: () => void;
gotOsType: (callback: (event: any, osType: { platform: string, arch: string }) => void) => void; gotOsType: (callback: (event: any, osType: { platform: string, arch: string }) => void) => void;
quit: () => void; quit: () => void;
}; };
} }
} }