mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2025-01-05 10:29:27 +00:00
Automatic upgrade and disable sync on wifi implementation
This commit is contained in:
parent
10f771f890
commit
c95017f4d9
10 changed files with 336 additions and 96 deletions
|
@ -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.**
|
||||||
|
|
99
app/main.ts
99
app/main.ts
|
@ -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) => {
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue