diff --git a/client/src/components/WelcomeLogo.tsx b/client/src/components/WelcomeLogo.tsx index 3a52d534..c8fbae34 100644 --- a/client/src/components/WelcomeLogo.tsx +++ b/client/src/components/WelcomeLogo.tsx @@ -19,7 +19,15 @@ function useConnectionAddress() { export const WelcomeLogo = ({className}: {className?: string}) => { const connectionAddress = useConnectionAddress(); const clientData = useClientData(); - + const [updateText, setUpdateText] = useState(""); + useEffect(() => { + window.thorium?.registerUpdateHandler(message => { + setUpdateText(message); + }); + return () => { + window.thorium?.registerUpdateHandler(() => {}); + }; + }, []); return (
@@ -32,9 +40,16 @@ export const WelcomeLogo = ({className}: {className?: string}) => {

Thorium Nova

- - Version {packageJson.version} - + {updateText ? ( + updateText + ) : ( + + Version {packageJson.version} + + )}

diff --git a/client/src/main.tsx b/client/src/main.tsx index c389094e..595223aa 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -13,6 +13,7 @@ declare global { thorium: { getAddress: () => Promise; getHostSecret: () => Promise; + registerUpdateHandler: (handler: (update: string) => void) => void; }; } } diff --git a/desktop/main/electron.ts b/desktop/main/electron.ts index e1646f54..02e1d5da 100644 --- a/desktop/main/electron.ts +++ b/desktop/main/electron.ts @@ -8,6 +8,9 @@ import { stopThoriumServer, } from "./helpers/startThoriumServer"; import {ipcHandlers} from "./helpers/ipcHandlers"; +import {autoUpdater} from "electron-updater"; +import {initWin} from "./helpers/autoUpdate"; + let win: BrowserWindow | null = null; app.enableSandbox(); @@ -66,7 +69,7 @@ async function createWindow() { }, show: false, }); - + initWin(win); win.webContents.setWindowOpenHandler(({url}) => { shell.openExternal(url); return {action: "deny"}; @@ -90,6 +93,7 @@ async function createWindow() { } app.whenReady().then(() => { + autoUpdater.checkForUpdatesAndNotify(); createWindow(); }); diff --git a/desktop/main/helpers/autoUpdate.ts b/desktop/main/helpers/autoUpdate.ts new file mode 100644 index 00000000..a609f338 --- /dev/null +++ b/desktop/main/helpers/autoUpdate.ts @@ -0,0 +1,37 @@ +import {autoUpdater} from "electron-updater"; +import {BrowserWindow} from "electron"; + +let win: BrowserWindow | null = null; +export function initWin(newWin: BrowserWindow) { + win = newWin; +} +function sendStatusToWindow(text: string) { + win?.webContents.send("update-message", text); +} +autoUpdater.on("checking-for-update", () => { + sendStatusToWindow("Checking for update..."); +}); +autoUpdater.on("update-available", info => { + sendStatusToWindow("Update available."); +}); +autoUpdater.on("update-not-available", info => { + sendStatusToWindow(""); +}); +autoUpdater.on("error", err => { + sendStatusToWindow("Error in auto-updater. " + err); +}); +autoUpdater.on("download-progress", progressObj => { + let log_message = "Download speed: " + progressObj.bytesPerSecond; + log_message = log_message + " - Downloaded " + progressObj.percent + "%"; + log_message = + log_message + + " (" + + progressObj.transferred + + "/" + + progressObj.total + + ")"; + sendStatusToWindow(log_message); +}); +autoUpdater.on("update-downloaded", info => { + sendStatusToWindow("Update downloaded - restart to apply"); +}); diff --git a/desktop/main/preload.ts b/desktop/main/preload.ts index 29f58c99..86d896a2 100644 --- a/desktop/main/preload.ts +++ b/desktop/main/preload.ts @@ -1,5 +1,10 @@ import {ipcRenderer} from "electron"; +let updateHandler = (message: string) => {}; +ipcRenderer.on("update-message", (event, message) => { + updateHandler(message); +}); + const thorium = { getAddress: function () { return ipcRenderer.invoke("get-address"); @@ -7,6 +12,9 @@ const thorium = { getHostSecret: function () { return ipcRenderer.invoke("get-secret"); }, + registerUpdateHandler: function (handler: typeof updateHandler) { + updateHandler = handler; + }, }; window.thorium = thorium; diff --git a/desktop/package.json b/desktop/package.json index 53ca3658..2297404f 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -4,7 +4,7 @@ "description": "", "scripts": { "dev": "", - "start": "concurrently \"electron-esbuild dev\" \"copy-dir-cli resources ../dist/resources\"", + "start": "concurrently \"electron-esbuild dev\" \"npx copy-dir-cli resources ../dist/resources\"", "build": "electron-esbuild build", "typecheck": "tsc --noEmit" }, @@ -19,6 +19,7 @@ "bonjour": "^3.5.0", "electron-better-ipc": "^2.0.1", "electron-store": "^8.0.1", + "electron-updater": "^5.0.1", "electron-util": "^0.17.2" } } diff --git a/package-lock.json b/package-lock.json index 88d0b740..68ad4f7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -495,6 +495,7 @@ "bonjour": "^3.5.0", "electron-better-ipc": "^2.0.1", "electron-store": "^8.0.1", + "electron-updater": "^5.0.1", "electron-util": "^0.17.2" }, "devDependencies": { @@ -5161,6 +5162,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/semver": { + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz", + "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==" + }, "node_modules/@types/stack-utils": { "version": "2.0.1", "dev": true, @@ -6015,7 +6021,6 @@ }, "node_modules/argparse": { "version": "2.0.1", - "dev": true, "license": "Python-2.0" }, "node_modules/argv-formatter": { @@ -9222,6 +9227,79 @@ "version": "1.4.18", "license": "ISC" }, + "node_modules/electron-updater": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.0.1.tgz", + "integrity": "sha512-dNnXPCqYmergXy3jgg4UICuD50Orug9GQe/5xfHy+BE2Fy0icB0QE+y6iQWdCDf7yeONxwMBf4HgIkGG5pIaVg==", + "dependencies": { + "@types/semver": "^7.3.6", + "builder-util-runtime": "9.0.0", + "fs-extra": "^10.0.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "^7.3.5" + } + }, + "node_modules/electron-updater/node_modules/builder-util-runtime": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.0.0.tgz", + "integrity": "sha512-SkpEtSmTkREDHRJnxKEv43aAYp8sYWY8fxYBhGLBLOBIRXeaIp6Kv3lBgSD7uR8jQtC7CA659sqJrpSV6zNvSA==", + "dependencies": { + "debug": "^4.3.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/electron-updater/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-updater/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-updater/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-updater/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/electron-util": { "version": "0.17.2", "license": "MIT", @@ -11770,7 +11848,6 @@ }, "node_modules/graceful-fs": { "version": "4.2.8", - "devOptional": true, "license": "ISC" }, "node_modules/graceful-readlink": { @@ -15176,7 +15253,6 @@ }, "node_modules/js-yaml": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -15562,7 +15638,6 @@ }, "node_modules/lazy-val": { "version": "1.0.5", - "dev": true, "license": "MIT" }, "node_modules/less": { @@ -15811,7 +15886,6 @@ }, "node_modules/lodash.escaperegexp": { "version": "4.1.2", - "dev": true, "license": "MIT" }, "node_modules/lodash.forown": { @@ -15829,6 +15903,11 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, "node_modules/lodash.ismatch": { "version": "4.4.0", "dev": true, @@ -24126,7 +24205,6 @@ }, "node_modules/sax": { "version": "1.2.4", - "devOptional": true, "license": "ISC" }, "node_modules/saxes": { @@ -30354,6 +30432,11 @@ "version": "0.16.2", "dev": true }, + "@types/semver": { + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz", + "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==" + }, "@types/stack-utils": { "version": "2.0.1", "dev": true @@ -30877,8 +30960,7 @@ "version": "5.0.1" }, "argparse": { - "version": "2.0.1", - "dev": true + "version": "2.0.1" }, "argv-formatter": { "version": "1.0.0", @@ -31780,7 +31862,7 @@ "@dnd-kit/sortable": "^6.0.0", "@floating-ui/react-dom": "^0.6.0", "@geckos.io/snapshot-interpolation": "^1.1.0", - "@headlessui/react": "1.5.0", + "@headlessui/react": "^1.5.0", "@mdx-js/mdx": "^2.0.0-next.9", "@mdx-js/react": "^1.6.22", "@msgpack/msgpack": "^2.7.1", @@ -32808,6 +32890,7 @@ "electron-better-ipc": "^2.0.1", "electron-esbuild": "^3.0.0", "electron-store": "^8.0.1", + "electron-updater": "^5.0.1", "electron-util": "^0.17.2" }, "dependencies": { @@ -33405,6 +33488,64 @@ "electron-to-chromium": { "version": "1.4.18" }, + "electron-updater": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.0.1.tgz", + "integrity": "sha512-dNnXPCqYmergXy3jgg4UICuD50Orug9GQe/5xfHy+BE2Fy0icB0QE+y6iQWdCDf7yeONxwMBf4HgIkGG5pIaVg==", + "requires": { + "@types/semver": "^7.3.6", + "builder-util-runtime": "9.0.0", + "fs-extra": "^10.0.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "lodash.escaperegexp": "^4.1.2", + "lodash.isequal": "^4.5.0", + "semver": "^7.3.5" + }, + "dependencies": { + "builder-util-runtime": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.0.0.tgz", + "integrity": "sha512-SkpEtSmTkREDHRJnxKEv43aAYp8sYWY8fxYBhGLBLOBIRXeaIp6Kv3lBgSD7uR8jQtC7CA659sqJrpSV6zNvSA==", + "requires": { + "debug": "^4.3.2", + "sax": "^1.2.4" + } + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } + } + }, "electron-util": { "version": "0.17.2", "requires": { @@ -35060,8 +35201,7 @@ } }, "graceful-fs": { - "version": "4.2.8", - "devOptional": true + "version": "4.2.8" }, "graceful-readlink": { "version": "1.0.1", @@ -37304,7 +37444,6 @@ }, "js-yaml": { "version": "4.1.0", - "dev": true, "requires": { "argparse": "^2.0.1" } @@ -37579,8 +37718,7 @@ } }, "lazy-val": { - "version": "1.0.5", - "dev": true + "version": "1.0.5" }, "less": { "version": "4.1.2", @@ -37746,8 +37884,7 @@ "dev": true }, "lodash.escaperegexp": { - "version": "4.1.2", - "dev": true + "version": "4.1.2" }, "lodash.forown": { "version": "4.4.0", @@ -37761,6 +37898,11 @@ "version": "4.6.0", "dev": true }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, "lodash.ismatch": { "version": "4.4.0", "dev": true @@ -43142,8 +43284,7 @@ } }, "sax": { - "version": "1.2.4", - "devOptional": true + "version": "1.2.4" }, "saxes": { "version": "5.0.1",