diff --git a/README.md b/README.md index dc05e24..aa4071d 100644 --- a/README.md +++ b/README.md @@ -95,3 +95,9 @@ npm run storybook `npx @electron/asar extract app.asar ` can be used to determine the contents of asar `npm run package` followed by `mkdir outAsar` and `npx @electron/asar extract ./out/NiceNode-darwin-arm64/NiceNode.app/Contents/Resources/app.asar outAsar` on macOS + +## Debugging update server (macOS and Windows) +`curl https://update.electronjs.org/NiceNode/test-nice-node-updater/darwin-arm64/5.2.0-alpha` returns if there is an update detected by the update server. The end of the URL is -/. + +Also, NiceNode app auto update logs are in ../NiceNode/logs/autoUpdater*.log. + diff --git a/forge.config.ts b/forge.config.ts index 83c970f..a171276 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -30,6 +30,28 @@ const packagerConfig: ForgePackagerOptions = { // ignore: [ /stories/, /__tests__/, /.storybook/, /storybook/, /storybook-static/ ], }; +const commonLinuxConfig = { + icon: { + scalable: path.resolve(iconDir, 'icon.svg'), + // scalable: './assets/icons/icon.svg', + '1024x1024': path.resolve(iconDir, '1024x1024.png'), + '512x512': path.resolve(iconDir, '512x512.png'), + '256x256': path.resolve(iconDir, '256x256.png'), + '128x128': path.resolve(iconDir, '128x128.png'), + '96x96': path.resolve(iconDir, '96x96.png'), + '64x64': path.resolve(iconDir, '64x64.png'), + '48x48': path.resolve(iconDir, '48x48.png'), + '32x32': path.resolve(iconDir, '32x32.png'), + '16x16': path.resolve(iconDir, '16x16.png'), + }, + executableName: 'nice-node', + productName: 'NiceNode', + productDescription: "By running a node you become part of a global movement to decentralize a world of information. Prevent leaking your personal data to third party nodes. Ensure access when you need it, and don't be censored. Decentralization starts with you. Voice your choice, help your peers.", + maintainer: "NiceNode LLC ", + categories: ['Utility', 'System', 'Network', 'Development'], + mimeType: ['application/x-nice-node', 'x-scheme-handler/nice-node'], +} + // skip signing & notarizing on local builds console.log("process.env.CI: ", process.env.CI); if(process.env.CI && process.env.NO_CODE_SIGNING !== 'true') { @@ -67,31 +89,15 @@ const config: ForgeConfig = { }), }, new MakerZIP({}), - new MakerRpm({}, ['linux']), + { + name: '@electron-forge/maker-rpm', + platforms: ['linux'], + config: commonLinuxConfig + }, { name: '@electron-forge/maker-deb', platforms: ['linux'], - config: { - icon: { - scalable: path.resolve(iconDir, 'icon.svg'), - // scalable: './assets/icons/icon.svg', - '1024x1024': path.resolve(iconDir, '1024x1024.png'), - '512x512': path.resolve(iconDir, '512x512.png'), - '256x256': path.resolve(iconDir, '256x256.png'), - '128x128': path.resolve(iconDir, '128x128.png'), - '96x96': path.resolve(iconDir, '96x96.png'), - '64x64': path.resolve(iconDir, '64x64.png'), - '48x48': path.resolve(iconDir, '48x48.png'), - '32x32': path.resolve(iconDir, '32x32.png'), - '16x16': path.resolve(iconDir, '16x16.png'), - }, - executableName: 'nice-node', - productName: 'NiceNode', - productDescription: "By running a node you become part of a global movement to decentralize a world of information. Prevent leaking your personal data to third party nodes. Ensure access when you need it, and don't be censored. Decentralization starts with you. Voice your choice, help your peers.", - maintainer: "NiceNode LLC ", - categories: ['Utility', 'System', 'Network', 'Development'], - mimeType: ['application/x-nice-node', 'x-scheme-handler/nice-node'], - } + config: commonLinuxConfig }, new MakerDMG({ background: './assets/dmg-background.tiff', diff --git a/package-lock.json b/package-lock.json index 45cf8dc..3950dd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nice-node", - "version": "5.0.0-alpha", + "version": "5.5.2-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nice-node", - "version": "5.0.0-alpha", + "version": "5.5.2-alpha", "license": "MIT", "dependencies": { "@reduxjs/toolkit": "^1.9.3", @@ -39,6 +39,7 @@ "react-select": "^5.8.0", "systeminformation": "^5.21.24", "throttle-debounce": "^5.0.0", + "tiny-typed-emitter": "^2.1.0", "update-electron-app": "^3.0.0", "uuid": "^9.0.0", "winston": "^3.13.0", @@ -21003,6 +21004,11 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "dev": true }, + "node_modules/tiny-typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz", + "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==" + }, "node_modules/tinybench": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", diff --git a/package.json b/package.json index ddf39f0..df5711f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nice-node", - "version": "5.1.2-alpha", + "version": "5.5.2-alpha", "description": "Run a node at home, the easy way.", "homepage": "https://nicenode.xyz", "productName": "NiceNode", @@ -109,6 +109,7 @@ "react-select": "^5.8.0", "systeminformation": "^5.21.24", "throttle-debounce": "^5.0.0", + "tiny-typed-emitter": "^2.1.0", "update-electron-app": "^3.0.0", "uuid": "^9.0.0", "winston": "^3.13.0", diff --git a/src/main/main.ts b/src/main/main.ts index 3310a3b..d46c415 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -84,7 +84,7 @@ const RESOURCES_PATH = app.isPackaged : path.join(__dirname, '..', '..', 'assets'); // starting point: .vite/build/main.js const getAssetPath = (...paths: string[]): string => { - logger.log('RESOURCES_PATH: ', RESOURCES_PATH); + logger.info('RESOURCES_PATH: ', RESOURCES_PATH); return path.join(RESOURCES_PATH, ...paths); }; @@ -158,7 +158,12 @@ export const createWindow = async () => { // App auto updates updater.initialize(mainWindow); - // updater.checkForUpdates(false); + // disabled in dev env + if (!isDevelopment) { + updater.checkForUpdates(false); + } else { + logger.info('updater.checkForUpdates() skipped. Disabled in development env'); + } menuBuilder = new MenuBuilder(mainWindow); menuBuilder.buildMenu(); @@ -195,6 +200,10 @@ export const fullQuit = () => { app.quit(); }; +export const setFullQuitForNextQuit = (_isNextQuitAFullQuit: boolean) => { + isFullQuit = _isNextQuitAFullQuit; +}; + // Emitted on app.quit() after all windows have been closed app.on('will-quit', (e) => { // Remove dev env check to test background. This is to prevent diff --git a/src/main/nn-auto-updater/findPackageManager.ts b/src/main/nn-auto-updater/findPackageManager.ts new file mode 100644 index 0000000..31bb69a --- /dev/null +++ b/src/main/nn-auto-updater/findPackageManager.ts @@ -0,0 +1,66 @@ +import { exec as execCallback } from 'node:child_process'; +import { promisify } from 'node:util'; + +const exec = promisify(execCallback); + +export type PackageType = "deb" | "rpm"; +export type PackageManager = "dpkg" | "dnf" | "yum" | "zypper"; + +interface PackageManagerMap { + [key: string]: PackageManager; +} + +interface PackageManagerToTypeMap { + [key: string]: PackageType; +} + +const packageManagers: PackageManagerMap = { + "apt-get": "dpkg", // "deb (apt)", + dnf: "dnf", // "rpm (dnf)", + yum: "yum", // "rpm (yum)", + // pacman: "pacman", + zypper: "zypper", // "rpm (zypper)" +}; + +const packageTypes: PackageManagerToTypeMap = { + "apt-get": "deb", // "deb (apt)", + dnf: "rpm", // "rpm (dnf)", + yum: "rpm", // "rpm (yum)", + // pacman: "pacman", + zypper: "rpm", // "rpm (zypper)" +}; + +export const findPackageManager = async (): Promise => { + for (const pkgManager of Object.keys(packageManagers)) { + try { + const { stdout } = await exec(`command -v ${pkgManager}`); + if (stdout.trim()) { + return packageManagers[pkgManager]; + } + } catch (error) { + // Command not found, continue checking the next + } + } + // "Package manager not found."; + return null; +} + +export const findPackageType = async (): Promise => { + for (const pkgManager of Object.keys(packageManagers)) { + try { + const { stdout } = await exec(`command -v ${pkgManager}`); + if (stdout.trim()) { + return packageTypes[pkgManager]; + } + } catch (error) { + // Command not found, continue checking the next + } + } + // "Package manager not found."; + return null; +} + +// (async () => { +// const result = await findPackageManager(); +// console.log("+++++++++++++++++++++++++", result); +// })(); diff --git a/src/main/nn-auto-updater/githubReleases.ts b/src/main/nn-auto-updater/githubReleases.ts new file mode 100644 index 0000000..d259ac7 --- /dev/null +++ b/src/main/nn-auto-updater/githubReleases.ts @@ -0,0 +1,187 @@ +import { arch, platform } from 'node:process'; +import { app } from "electron"; +import type { AppUpdaterEvents } from './main'; +import { downloadFile } from '../downloadFile'; +import { getNNDirPath } from '../files'; +import { spawnSync } from 'node:child_process'; +import { setFullQuitForNextQuit } from '../main'; +import logger from '../logger'; +import { type PackageManager, type PackageType, findPackageManager, findPackageType } from './findPackageManager'; +import { find } from 'highcharts'; + +const repo = 'NiceNode/test-nice-node-updater'; +// const repo = 'NiceNode/nice-node'; + +let latestDownloadFilePath = ''; +export const getLatestVersion = async () => { + const res = await fetch(`https://api.github.com/repos/${repo}/releases/latest`); + const data = await res.json(); + // remove prefix 'v' from tag_name + return data.tag_name.replace(/^v/, ''); +} + +let localPackageType: PackageType | null = null; +let localPackageManager: PackageManager | null = null; + +export const checkForUpdates = async (emit: (e: any, args?: any) => void) => { + // if latest version is greater than current version + // download + emit('checking-for-update'); + const currentVersion = app.getVersion(); + logger.info(`currentVersion: ${currentVersion}`); + const latestVersion = await getLatestVersion(); + logger.info(`latestVersion: ${latestVersion}`); + + // if no github releases, return error + if(latestVersion === undefined) { + emit('error', new Error('No github releases found')); + return + } + // if versions equal, return no update + if(currentVersion === latestVersion) { + emit('update-not-available'); + return; + } + if(currentVersion < latestVersion) { + emit('update-available'); + // download + const res = await fetch(`https://api.github.com/repos/${repo}/releases/latest`); + const data = await res.json(); + + if(localPackageType === null) { + localPackageType = await findPackageType(); + if(localPackageType === null) { + emit('error', new Error('Local supported package type not found. Only deb and rpm currently supported.')); + return; + } + } + logger.info(`Looking for release package type : ${localPackageType}`); + + // loop over data.assets, check asset.name and parse out the ones we want to show in the UI. + // get asset.browser_download_url + let downloadUrl = ''; + let fileName = ''; + const arch = process.arch === 'x64' ? 'amd64' : 'arm64'; + const releaseNotes = data.body; + const releaseDate = data.published_at; + for(const val of data.assets) { + if(val.name.endsWith(`${arch}.${localPackageType}`)) { + downloadUrl = val.browser_download_url; + logger.info(`val.url: ${val.url}`); + fileName = val.name; + logger.info(`val.name: ${val.name}`); + break; + } + }; + + if(! downloadUrl || !fileName) { + emit('error', new Error('No github release found matching this architecture')); + return; + } + + latestDownloadFilePath = await downloadFile(downloadUrl, getNNDirPath()); + //latestDownloadFilePath = path.join(latestDownloadFilePath, fileName); + logger.info(`latestDownloadFilePath: ${latestDownloadFilePath}`); + emit('update-downloaded', [{}, releaseNotes, fileName, releaseDate, downloadUrl]); + // install downloaded and quit + // { + // url: 'https://api.github.com/repos/NiceNode/test-nice-node-updater/releases/assets/162903620', + // id: 162903620, + // node_id: 'RA_kwDOLvIOVs4JtbZE', + // name: 'NiceNode-linux-arm64-5.4.1-alpha.zip', + // label: '', + // uploader: [Object], + // content_type: 'application/zip', + // state: 'uploaded', + // size: 136035837, + // download_count: 0, + // created_at: '2024-04-18T17:12:26Z', + // updated_at: '2024-04-18T17:12:29Z', + // browser_download_url: 'https://github.com/NiceNode/test-nice-node-updater/releases/download/v5.4.1-alpha/NiceNode-linux-arm64-5.4.1-alpha.zip' + // }, + return; + } + +} +const wrapSudo = () => { + const installComment = `"${app.name} would like to update"` + const sudo = spawnSyncLog("which gksudo || which kdesudo || which pkexec || which beesu") + const command = [sudo] + if (/kdesudo/i.test(sudo)) { + command.push("--comment", installComment) + command.push("-c") + } else if (/gksudo/i.test(sudo)) { + command.push("--message", installComment) + } else if (/pkexec/i.test(sudo)) { + command.push("--disable-internal-agent") + } + return command.join(" ") +} + +const spawnSyncLog = (cmd: string, args: string[] = [], env = {}): string => { + logger.info(`Executing: ${cmd} with args: ${args}`) + const response = spawnSync(cmd, args, { + env: { ...process.env, ...env }, + encoding: "utf-8", + shell: true, + }) + return response.stdout.trim() +} + +export const quitAndInstall = async () => { + logger.info('quitAndInstall called') + // add quit handler, call quit, install in quitHandler + + // sudo dpkg -i /latestDownloadFilePath + const sudo = wrapSudo(); + logger.info(`sudo cmd ${sudo}`); + const wrapper = /pkexec/i.test(sudo) ? "" : `"` + if(localPackageManager === null) { + localPackageManager = await findPackageManager(); + if(localPackageManager === null) { + throw new Error('Local supported package manager not found. Only dpkg, yum, dnf and zypper currently supported.'); + } + } + logger.info(`Using release package manager : ${localPackageManager}`); + let cmd = null; + if(localPackageManager === 'dpkg') { + cmd = ["dpkg", "-i", latestDownloadFilePath, "||", "apt-get", "install", "-f", "-y"] + } else if(localPackageType === 'rpm') { + if(localPackageManager === 'dnf' || localPackageManager === 'yum') { + cmd = [localPackageManager, "-y", "remove", `'${app.name}'`, ";", localPackageManager, "-y", "install", latestDownloadFilePath] + } else { + // zypper + cmd = [ + localPackageManager, + "remove", + "-y", + `'${app.name}'`, + ";", + localPackageManager, + "clean", + "--all", + ";", + localPackageManager, + "--no-refresh", + "install", + "--allow-unsigned-rpm", + "-y", + "-f", + latestDownloadFilePath, + ] + } + } + logger.info(`quitAndInstall cmd: ${cmd.join(" ")}`); + spawnSyncLog(sudo, [`${wrapper}/bin/bash`, "-c", `'${cmd.join(" ")}'${wrapper}`]) + //if (options.isForceRunAfter) { + logger.info('quitAndInstall install done. relaunching '); + setFullQuitForNextQuit(true); + app.relaunch(); + app.quit(); + //} + // app.restart(); +} + + +console.log("CACHE DIR (sessionData): ", app.getPath("sessionData")); +console.log("TEMP DIR: ", app.getPath("temp")); diff --git a/src/main/nn-auto-updater/main.ts b/src/main/nn-auto-updater/main.ts new file mode 100644 index 0000000..c1f5427 --- /dev/null +++ b/src/main/nn-auto-updater/main.ts @@ -0,0 +1,92 @@ +import { checkForUpdates } from './../updater'; +import { autoUpdater as _autoUpdater, type AutoUpdater } from 'electron'; +import EventEmitter from 'node:events'; +import { TypedEmitter } from "tiny-typed-emitter" + +import { isLinux } from '../platform'; +import * as githubReleases from './githubReleases'; +import { findPackageManager } from './findPackageManager'; + +findPackageManager(); + +/** + * event Event + * releaseNotes string + * releaseName string + * releaseDate Date + * updateURL string + */ +type UpdateDownloadedData = [Event, string, string, Date, string]; + +export type AppUpdaterEvents = { + error: (error: Error, message?: string) => void + "checking-for-update": () => void + "update-not-available": () => void + "update-available": () => void + "update-downloaded": (...data: UpdateDownloadedData) => void + "download-progress": () => void + "update-cancelled": () => void +} + +let numTimeCalledConstructor = 0; + +export class nnAutoUpdater extends TypedEmitter implements AutoUpdater { + private readonly nativeUpdater: AutoUpdater = _autoUpdater; + private customUpdater: AutoUpdater | null = null; + + constructor() { + console.log("nnAutoUpdater constructor"); + numTimeCalledConstructor++; + if(numTimeCalledConstructor > 1) { + throw new Error("nnAutoUpdater constructor called more than once!"); + } + super(); + } + + emitCallback(e: any): void { + console.log("emitCallback e = ", e); + this.emit(e) + } + + checkForUpdates(): void { + // custom logic for linux as the native autoUpdater does not support linux + console.log("nnAutoUpdater checkForUpdates called"); + if(isLinux()) { + console.log("nnAutoUpdater checkForUpdates in linux!"); + this.emit('checking-for-update'); + githubReleases.checkForUpdates(this.emitCallback.bind(this)); + } else { + this.nativeUpdater.checkForUpdates(); + } + } + getFeedURL(): string { + console.log("nnAutoUpdater getFeedURL called"); + if(isLinux()) { + console.log("nnAutoUpdater getFeedURL in linux!"); + throw new Error('Method not implemented.'); + // biome-ignore lint/style/noUselessElse: + } else { + return this.nativeUpdater.getFeedURL(); + } + } + quitAndInstall(): void { + console.log("nnAutoUpdater quitAndInstall called"); + if(isLinux()) { + console.log("nnAutoUpdater quitAndInstall in linux!"); + githubReleases.quitAndInstall(); + } else { + this.nativeUpdater.quitAndInstall(); + } + } + setFeedURL(options: Electron.FeedURLOptions): void { + console.log("nnAutoUpdater setFeedURL called"); + if(isLinux()) { + console.log("nnAutoUpdater setFeedURL in linux!"); + + } else { + this.nativeUpdater.setFeedURL(options); + } + } +} + +export const autoUpdater = new nnAutoUpdater(); diff --git a/src/main/updater.ts b/src/main/updater.ts index f2be115..84398fc 100644 --- a/src/main/updater.ts +++ b/src/main/updater.ts @@ -1,92 +1,94 @@ -// import sleep from 'await-sleep'; -// import { type BrowserWindow, autoUpdater, dialog, FeedURLOptions } from 'electron'; -import type { BrowserWindow } from 'electron'; -// // const { updateElectronApp } = require('update-electron-app') -import { type IUpdateElectronAppOptions, updateElectronApp, UpdateSourceType } from 'update-electron-app'; -import logger, { autoUpdateLogger } from './logger'; -import log from 'electron-log/main'; -const updateLogger = log.scope('updater'); +import sleep from 'await-sleep'; +import { app, dialog, type BrowserWindow } from 'electron'; +import { autoUpdateLogger } from './logger'; -// import { reportEvent } from './events'; -// import i18nMain from './i18nMain'; -// // import logger, { autoUpdateLogger } from './logger'; -// import logger from './logger'; +import { autoUpdater } from './nn-auto-updater/main'; +import { reportEvent } from './events'; +import i18nMain from './i18nMain'; +import { setFullQuitForNextQuit } from './main'; // import { getSetIsPreReleaseUpdatesEnabled } from './state/settings'; -// let notifyUserIfNoUpdateAvailable: boolean; +let notifyUserIfNoUpdateAvailable: boolean; -// const t = i18nMain.getFixedT(null, 'updater'); +const t = i18nMain.getFixedT(null, 'updater'); -// const intiUpdateHandlers = (browserWindow: BrowserWindow) => { -// autoUpdater.on('error', (error) => { -// logger.error('autoUpdater:::::::::error', error); -// }); +const logger = autoUpdateLogger; -// autoUpdater.on('checking-for-update', () => { -// logger.info('autoUpdater:::::::::checking-for-update'); -// }); -// autoUpdater.on('update-available', async (info: any) => { -// logger.info('autoUpdater:::::::::update-available: ', info); -// // Quick fix to wait for window load before showing update prompt -// await sleep(5000); -// dialog -// .showMessageBox(browserWindow, { -// type: 'info', -// title: t('UpdateAvailable'), -// message: `${t('UpdateNiceNode')} ${info.version}.`, -// buttons: [t('Yes'), t('No')], -// }) -// .then(async (buttonIndex) => { -// if (buttonIndex.response === 0) { -// console.log('update accepted by user'); -// console.log('starting download'); -// autoUpdater.quitAndInstall(); -// dialog.showMessageBox(browserWindow, { -// type: 'info', -// title: t('UpdateAvailable'), -// message: t('DownloadingUpdate'), -// }); -// } else { -// console.log('update checkbox not checked'); -// } -// }) -// .catch((err) => { -// console.error('error in update available dialog: ', err); -// }); -// }); +const initUpdateHandlers = (browserWindow: BrowserWindow) => { + autoUpdater.on('error', (error) => { + logger.error('autoUpdater:::::::::error', error); + }); -// autoUpdater.on('update-not-available', () => { -// logger.info('autoUpdater:::::::::update-not-available'); -// if (notifyUserIfNoUpdateAvailable) { -// dialog.showMessageBox(browserWindow, { -// type: 'info', -// title: t('NoUpdateAvailable'), -// message: t('NoUpdateAvailable'), -// }); -// notifyUserIfNoUpdateAvailable = false; -// } -// }); + autoUpdater.on('checking-for-update', () => { + logger.info('autoUpdater:::::::::checking-for-update'); + }); + autoUpdater.on('update-available', async () => { + logger.info('autoUpdater:::::::::update-available: '); + // this is unused now, as the download starts automatically now. We could show the user + // that an update is downloading starting now. + // Quick fix to wait for window load before showing update prompt + // await sleep(5000); -// autoUpdater.on('update-downloaded', () => { -// logger.info('autoUpdater:::::::::update-downloaded'); -// logger.info('Calling autoUpdater.quitAndInstall()'); -// reportEvent('UpdatedNiceNode'); -// try { -// autoUpdater.quitAndInstall(); -// } catch (err) { -// logger.error('Error in: autoUpdater.quitAndInstall()'); -// logger.error(err); -// dialog.showErrorBox( -// t('ErrorUpdating'), -// t('UnableToInstallUpdate', { -// downloadLink: 'https://www.nicenode.xyz/#download', -// }), -// ); -// // todo: send error details -// reportEvent('ErrorUpdatingNiceNode'); -// } -// }); -// }; + }); + + autoUpdater.on('update-not-available', () => { + logger.info('autoUpdater:::::::::update-not-available'); + if (notifyUserIfNoUpdateAvailable) { + dialog.showMessageBox(browserWindow, { + type: 'info', + title: t('NoUpdateAvailable'), + message: t('NoUpdateAvailable'), + }); + notifyUserIfNoUpdateAvailable = false; + } + }); + + autoUpdater.on('update-downloaded', (...args) => { + logger.info('autoUpdater:::::::::update-downloaded args: ', args); + logger.info('Calling autoUpdater.quitAndInstall()'); + try { + const newVersion = args.length > 2 ? args[2] : 'latest version'; + dialog + .showMessageBox(browserWindow, { + type: 'info', + title: t('UpdateAvailable'), + message: `${t('UpdateNiceNode')} ${newVersion}.`, + buttons: [t('Yes'), t('No')], + }) + .then(async (buttonIndex) => { + if (buttonIndex.response === 0) { + logger.info('update accepted by user. quit and install.'); + reportEvent('UpdatedNiceNode'); + // todo: tell main that full quit incoming + setFullQuitForNextQuit(true); + autoUpdater.quitAndInstall(); + dialog.showMessageBox(browserWindow, { + type: 'info', + title: t('UpdateAvailable'), + message: t('DownloadingUpdate'), + }); + } else { + logger.info('update denied by user. install will take place on next quit.'); + } + }) + .catch((err) => { + console.error('error in update available dialog: ', err); + }); + // autoUpdater.quitAndInstall(); + } catch (err) { + logger.error('Error in: autoUpdater.quitAndInstall()'); + logger.error(err); + dialog.showErrorBox( + t('ErrorUpdating'), + t('UnableToInstallUpdate', { + downloadLink: 'https://www.nicenode.xyz/#download', + }), + ); + // todo: send error details + reportEvent('ErrorUpdatingNiceNode'); + } + }); +}; // export const initialize = (mainWindow: BrowserWindow) => { // // autoUpdater.logger = autoUpdateLogger; @@ -99,13 +101,15 @@ const updateLogger = log.scope('updater'); // // autoUpdater.setFeedURL({ url }); // // autoUpdater.allowPrerelease = isPreReleaseUpdatesEnabled; // notifyUserIfNoUpdateAvailable = false; -// intiUpdateHandlers(mainWindow); +// initUpdateHandlers(mainWindow); // }; export const checkForUpdates = (notifyIfNoUpdateAvailable: boolean) => { logger.info(`updater.checkForUpdates set to: ${notifyIfNoUpdateAvailable}`); - // notifyUserIfNoUpdateAvailable = notifyIfNoUpdateAvailable; - // autoUpdater.checkForUpdates(); + notifyUserIfNoUpdateAvailable = notifyIfNoUpdateAvailable; + // if linux + // call + autoUpdater.checkForUpdates(); }; export const setAllowPrerelease = (isAllowPrerelease: boolean) => { @@ -115,18 +119,13 @@ export const setAllowPrerelease = (isAllowPrerelease: boolean) => { }; export const initialize = (mainWindow: BrowserWindow) => { - updateLogger.info('initialize updater'); - - const options: IUpdateElectronAppOptions = { - updateSource: { - type: UpdateSourceType.ElectronPublicUpdateService, - repo: 'NiceNode/nice-node', - host: 'https://update.electronjs.org', - }, - updateInterval: '5 minutes', // testing - logger: updateLogger - } - - updateLogger.info('updater options: ', options); - updateElectronApp(options); + logger.info('initialize updater'); + const host = 'https://update.electronjs.org'; + const publicRepo = 'NiceNode/test-nice-node-updater'; + const currentAppVersion = app.getVersion(); // ex. 5.1.2-alpha + const feedUrl = `${host}/${publicRepo}/${process.platform}-${process.arch}/${currentAppVersion}` + logger.info(`electron.autoUpdater feedUrl set to ${feedUrl}`); + autoUpdater.setFeedURL({ url: feedUrl }); + notifyUserIfNoUpdateAvailable = false; + initUpdateHandlers(mainWindow); }