Skip to content

Commit

Permalink
Notifications implementation and general improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
everoddandeven committed Oct 18, 2024
1 parent 68927d3 commit 5996037
Show file tree
Hide file tree
Showing 17 changed files with 347 additions and 181 deletions.
44 changes: 40 additions & 4 deletions app/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions, IpcMainInvokeEvent } from 'electron';
import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions, IpcMainInvokeEvent, Notification, NotificationConstructorOptions } from 'electron';
import { ChildProcessWithoutNullStreams, exec, ExecException, spawn } from 'child_process';
import * as path from 'path';
import * as fs from 'fs';
Expand Down Expand Up @@ -248,22 +248,46 @@ function getMonerodVersion(monerodFilePath: string): void {
})
}

function checkValidMonerodPath(monerodPath: string): void {
let foundUsage: boolean = false;
const monerodProcess = spawn(monerodPath, ['--help']);

monerodProcess.stderr.on('data', (data) => {
win?.webContents.send('on-check-valid-monerod-path', false);
});

monerodProcess.stdout.on('data', (data) => {
if (`${data}`.includes('monerod [options|settings] [daemon_command...]')) {
foundUsage = true;
}
});

monerodProcess.on('close', (code: number) => {
win?.webContents.send('on-check-valid-monerod-path', foundUsage);
})

}

let moneroFirstStdout: boolean = true;

function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStreams {
const monerodPath = commandOptions.shift();

if (!monerodPath) {
win?.webContents.send('monero-stderr', `Invalid monerod path provided: ${monerodPath}`);
const error = `Invalid monerod path provided: ${monerodPath}`;
win?.webContents.send('monero-stderr', error);
throw new Error("Invalid monerod path provided");
}

if (monerodProcess != null) {
win?.webContents.send('monero-stderr', 'Monerod already started');
const error: string = 'Monero daemon already started';
win?.webContents.send('monero-stderr', error);
throw new Error("Monerod already started");
}

console.log("Starting monerod daemon with options: " + commandOptions.join(" "));
const message: string = "Starting monerod daemon with options: " + commandOptions.join(" ");

console.log(message);

moneroFirstStdout = true;

Expand Down Expand Up @@ -471,6 +495,10 @@ const extractTarBz2 = (filePath: string, destination: string): Promise<string> =
});
};

function showNotification(options?: NotificationConstructorOptions): void {
new Notification(options).show();
}

try {
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
Expand Down Expand Up @@ -587,6 +615,14 @@ try {
monitorMonerod();
});

ipcMain.handle('check-valid-monerod-path', (event: IpcMainInvokeEvent, path: string) => {
checkValidMonerodPath(path);
})

ipcMain.handle('show-notification', (event: IpcMainInvokeEvent, options?: NotificationConstructorOptions) => {
showNotification(options);
});

} catch (e) {
// Catch Error
console.error(e);
Expand Down
9 changes: 9 additions & 0 deletions app/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ contextBridge.exposeInMainWorld('electronAPI', {
onDownloadProgress: (callback) => {
ipcRenderer.on('download-progress', callback);
},
checkValidMonerodPath: (path) => {
ipcRenderer.invoke('check-valid-monerod-path', path);
},
onCheckValidMonerodPath: (callback) => {
ipcRenderer.on('on-check-valid-monerod-path', callback);
},
selectFolder: () => {
ipcRenderer.invoke('select-folder')
},
Expand All @@ -70,6 +76,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
gotOsType: (callback) => {
ipcRenderer.on('got-os-type', callback);
},
showNotification: (options) => {
ipcRenderer.invoke('show-notification', options);
},
quit: () => {
ipcRenderer.invoke('quit');
}
Expand Down
42 changes: 9 additions & 33 deletions src/app/core/services/daemon/daemon-data.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EventEmitter, Injectable, NgZone } from '@angular/core';
import { DaemonService } from './daemon.service';
import { BlockCount, BlockHeader, Chain, Connection, CoreIsBusyError, DaemonInfo, MinerData, MiningStatus, NetStats, NetStatsHistory, PeerInfo, ProcessStats, PublicNode, SyncInfo, TxBacklogEntry, TxPool } from '../../../../common';
import { BlockCount, BlockHeader, Chain, Connection, CoreIsBusyError, DaemonInfo, MinerData, MiningStatus, NetStats, NetStatsHistory, PeerInfo, ProcessStats, PublicNode, SyncInfo, TimeUtils, TxBacklogEntry, TxPool } from '../../../../common';

@Injectable({
providedIn: 'root'
Expand Down Expand Up @@ -332,36 +332,6 @@ export class DaemonDataService {
public syncDisabledByWifiPolicy: boolean = false;
public syncDisabledByPeriodPolicy: boolean = false;

private isInTimeRange(fromHours: string, toHours: string): boolean {
const now = new Date();

// Estraiamo l'ora e i minuti dalla stringa in formato hh:mm
const [fromHour, fromMinute] = fromHours.split(":").map(Number);
const [toHour, toMinute] = toHours.split(":").map(Number);

// Otteniamo l'ora corrente in ore e minuti
const currentHour = now.getHours();
const currentMinute = now.getMinutes();

// Creiamo oggetti Date per le ore 'from', 'to', e l'ora attuale
const currentTime = new Date();
currentTime.setHours(currentHour, currentMinute, 0, 0);

const fromTime = new Date();
fromTime.setHours(fromHour, fromMinute, 0, 0);

const toTime = new Date();
toTime.setHours(toHour, toMinute, 0, 0);

// Gestione del caso in cui la fascia oraria attraversi la mezzanotte
if (fromTime > toTime) {
// Se l'ora attuale è dopo 'fromTime' o prima di 'toTime'
return currentTime >= fromTime || currentTime <= toTime;
} else {
// Caso normale: la fascia oraria è nello stesso giorno
return currentTime >= fromTime && currentTime <= toTime;
}
}

private async refresh(): Promise<void> {
if (this.refreshing || this.tooEarlyForRefresh) {
Expand Down Expand Up @@ -407,14 +377,20 @@ export class DaemonDataService {
this.syncDisabledByWifiPolicy = false;
}

if (!syncAlreadyDisabled && !this.syncDisabledByPeriodPolicy && settings.syncPeriodEnabled && !this.isInTimeRange(settings.syncPeriodFrom, settings.syncPeriodTo)) {
if (!syncAlreadyDisabled && !this.syncDisabledByWifiPolicy && !this.syncDisabledByPeriodPolicy && settings.syncPeriodEnabled && !TimeUtils.isInTimeRange(settings.syncPeriodFrom, settings.syncPeriodTo)) {
await this.daemonService.disableSync();
this.syncDisabledByPeriodPolicy = true;
}
else if (syncAlreadyDisabled && this.syncDisabledByPeriodPolicy && settings.syncPeriodEnabled && this.isInTimeRange(settings.syncPeriodFrom, settings.syncPeriodTo)) {
else if (syncAlreadyDisabled && !this.syncDisabledByWifiPolicy && this.syncDisabledByPeriodPolicy && settings.syncPeriodEnabled && TimeUtils.isInTimeRange(settings.syncPeriodFrom, settings.syncPeriodTo)) {
await this.daemonService.enableSync();
this.syncDisabledByPeriodPolicy = false;
}
else if (syncAlreadyDisabled && !this.syncDisabledByWifiPolicy && settings.syncPeriodEnabled && !TimeUtils.isInTimeRange(settings.syncPeriodFrom, settings.syncPeriodTo)) {
this.syncDisabledByPeriodPolicy = true;
}
else {
this.syncDisabledByPeriodPolicy = false;
}

this.syncStart.emit({ first: this._firstRefresh });

Expand Down
105 changes: 64 additions & 41 deletions src/app/core/services/daemon/daemon.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ import { TxInfo } from '../../../../common/TxInfo';
import { DaemonSettings } from '../../../../common/DaemonSettings';
import { MethodNotFoundError } from '../../../../common/error/MethodNotFoundError';
import { openDB, IDBPDatabase } from "idb"
import { PeerInfo, ProcessStats, TxPool } from '../../../../common';
import { PeerInfo, ProcessStats, TimeUtils, TxPool } from '../../../../common';
import { MoneroInstallerService } from '../monero-installer/monero-installer.service';

@Injectable({
Expand Down Expand Up @@ -124,6 +124,7 @@ export class DaemonService {
public readonly onDaemonStatusChanged: EventEmitter<boolean> = new EventEmitter<boolean>();
public readonly onDaemonStopStart: EventEmitter<void> = new EventEmitter<void>();
public readonly onDaemonStopEnd: EventEmitter<void> = new EventEmitter<void>();
public readonly onSavedSettings: EventEmitter<DaemonSettings> = new EventEmitter<DaemonSettings>();

private isRunningPromise?: Promise<boolean>;

Expand Down Expand Up @@ -169,6 +170,12 @@ export class DaemonService {
public async disableSync(): Promise<void> {
this.disablingSync = true;

window.electronAPI.showNotification({
title: 'Disabling sync',
body: 'Node sync is about to be disabled',
closeButtonText: 'Dismiss'
});

try {
const running: boolean = await this.isRunning();

Expand All @@ -185,9 +192,21 @@ export class DaemonService {
this.settings.noSync = true;

await this.startDaemon(this.settings);

window.electronAPI.showNotification({
title: 'Sync disabled',
body: 'Node sync disabled successfully',
closeButtonText: 'Dismiss'
});

}
catch(error: any) {
console.error(error);
window.electronAPI.showNotification({
title: 'Error',
body: 'An error occurred while disabling sync',
closeButtonText: 'Dimiss'
})
}

this.disablingSync = false;
Expand Down Expand Up @@ -246,6 +265,7 @@ export class DaemonService {
public async saveSettings(settings: DaemonSettings, restartDaemon: boolean = true): Promise<void> {
const db = await this.openDbPromise;
await db.put(this.storeName, { id: 1, ...settings });
this.onSavedSettings.emit(settings);

if (restartDaemon) {
const running = await this.isRunning();
Expand All @@ -263,6 +283,22 @@ export class DaemonService {
}
}

public async checkValidMonerodPath(path: string): Promise<boolean> {
if (path == null || path == undefined || path.replace(' ', '') == '') {
return false;
}

const checkPromise = new Promise<boolean>((resolve) => {
window.electronAPI.onCheckValidMonerodPath((event: any, valid: boolean) => {
resolve(valid);
});
});

window.electronAPI.checkValidMonerodPath(path);

return await checkPromise;
}

public async getSettings(): Promise<DaemonSettings> {
const db = await this.openDbPromise;
const result = await db.get(this.storeName, 1);
Expand Down Expand Up @@ -359,26 +395,36 @@ export class DaemonService {

this.settings.noSync = true;
}
else if (!this.settings.noSync && !this.settings.syncOnWifi && !await this.isWifiConnected()) {
console.log("Enabling sync ...");
else if (!this.settings.noSync && this.settings.syncPeriodEnabled && !TimeUtils.isInTimeRange(this.settings.syncPeriodFrom, this.settings.syncPeriodTo)) {
console.log("Disabling sync ...");

this.settings.noSync = false;
this.settings.noSync = true;
}

const startPromise = new Promise<void>((resolve, reject) => {
window.electronAPI.onMonerodStarted((event: any, started: boolean) => {
console.debug(event);

if (started) {
console.log("Daemon started");
console.log("monerod started");
this.delay(3000).then(() => {
this.isRunning(true).then((running: boolean) => {
window.electronAPI.showNotification({
title: 'Daemon started',
body: 'Successfully started daemon',
closeButtonText: 'Dismiss'
});
this.onDaemonStatusChanged.emit(running);
this.startedAt = new Date();
this.starting = false;
resolve();
}).catch((error: any) => {
console.error(error);
window.electronAPI.showNotification({
title: 'Daemon error',
body: 'An error occurred while checking daemon status',
closeButtonText: 'Dismiss'
});
this.onDaemonStatusChanged.emit(false);
this.startedAt = undefined;
this.starting = false;
Expand All @@ -391,12 +437,15 @@ export class DaemonService {
}
else {
console.log("Daemon not started");
window.electronAPI.showNotification({
title: 'Daemon Error',
body: 'Could not start monerod'
});
this.onDaemonStatusChanged.emit(false);
this.startedAt = undefined;
this.starting = false;
reject('Could not start daemon');
}

})
});

Expand Down Expand Up @@ -706,33 +755,19 @@ export class DaemonService {
}
else if (dontUseRpc) {
const monerodPath: string = (await this.getSettings()).monerodPath;
const wdw = (window as any);

if (monerodPath == '') {
throw new Error("Daemon not configured");
}

return new Promise<DaemonVersion>((resolve, reject) => {
if (this.electronService.isElectron) {
this.electronService.ipcRenderer.on('on-monerod-version', (event, version: string) => {
resolve(DaemonVersion.parse(version));
});

this.electronService.ipcRenderer.on('on-monerod-version-error', (event, version: string) => {
reject(version);
});

this.electronService.ipcRenderer.send('get-monerod-version', monerodPath);
}
else if (wdw.electronAPI && wdw.electronAPI.getMoneroVersion) {
wdw.electronAPI.onMoneroVersion((event: any, version: string) => {
resolve(DaemonVersion.parse(version));
})
wdw.electronAPI.onMoneroVersionError((event: any, error: string) => {
reject(error);
});
wdw.electronAPI.getMoneroVersion(monerodPath);
}
window.electronAPI.onMoneroVersion((event: any, version: string) => {
resolve(DaemonVersion.parse(version));
})
window.electronAPI.onMoneroVersionError((event: any, error: string) => {
reject(error);
});
window.electronAPI.getMoneroVersion(monerodPath);
});
}

Expand Down Expand Up @@ -946,16 +981,6 @@ export class DaemonService {
}

throw new Error('Could not stop daemon');

/*
if (this.electronService.isElectron) {
return;
}
this.daemonRunning = false;
this.onDaemonStatusChanged.emit(false);
this.onDaemonStopEnd.emit();
*/
}

public async setLimit(limitDown: number, limitUp: number): Promise<{ limitDown: number, limitUp: number }> {
Expand Down Expand Up @@ -1073,10 +1098,8 @@ export class DaemonService {
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);
const destination = settings.downloadUpgradePath; // Aggiorna con il percorso desiderato
const moneroFolder = await this.installer.downloadMonero(destination, settings.monerodPath != '');

settings.monerodPath = `${moneroFolder}/monerod`;

Expand Down
Loading

0 comments on commit 5996037

Please sign in to comment.