diff --git a/src/main/events/autoupdater/check-for-updates.ts b/src/main/events/autoupdater/check-for-updates.ts index 9a7c9d20..7ea60d0b 100644 --- a/src/main/events/autoupdater/check-for-updates.ts +++ b/src/main/events/autoupdater/check-for-updates.ts @@ -1,49 +1,8 @@ -import type { AppUpdaterEvent } from "@types"; import { registerEvent } from "../register-event"; -import updater, { UpdateInfo } from "electron-updater"; -import { logger, WindowManager } from "@main/services"; -import { app } from "electron"; -import { publishNotificationUpdateReadyToInstall } from "@main/services/notifications"; - -const { autoUpdater } = updater; - -const sendEvent = (event: AppUpdaterEvent) => { - WindowManager.mainWindow?.webContents.send("autoUpdaterEvent", event); -}; - -const sendEventsForDebug = false; - -const isAutoInstallAvailable = - process.platform !== "darwin" && process.env.PORTABLE_EXECUTABLE_FILE == null; - -const mockValuesForDebug = () => { - sendEvent({ type: "update-available", info: { version: "1.3.0" } }); - sendEvent({ type: "update-downloaded" }); -}; - -const newVersionInfo = { version: "" }; +import { UpdateManager } from "@main/services/update-manager"; const checkForUpdates = async (_event: Electron.IpcMainInvokeEvent) => { - autoUpdater - .once("update-available", (info: UpdateInfo) => { - sendEvent({ type: "update-available", info }); - newVersionInfo.version = info.version; - }) - .once("update-downloaded", () => { - sendEvent({ type: "update-downloaded" }); - publishNotificationUpdateReadyToInstall(newVersionInfo.version); - }); - - if (app.isPackaged) { - autoUpdater.autoDownload = isAutoInstallAvailable; - autoUpdater.checkForUpdates().then((result) => { - logger.log(`Check for updates result: ${result}`); - }); - } else if (sendEventsForDebug) { - mockValuesForDebug(); - } - - return isAutoInstallAvailable; + return UpdateManager.checkForUpdates(); }; registerEvent("checkForUpdates", checkForUpdates); diff --git a/src/main/services/main-loop.ts b/src/main/services/main-loop.ts index a1c2b449..12b6e3a7 100644 --- a/src/main/services/main-loop.ts +++ b/src/main/services/main-loop.ts @@ -2,6 +2,7 @@ import { sleep } from "@main/helpers"; import { DownloadManager } from "./download"; import { watchProcesses } from "./process-watcher"; import { AchievementWatcherManager } from "./achievements/achievement-watcher-manager"; +import { UpdateManager } from "./update-manager"; export const startMainLoop = async () => { // eslint-disable-next-line no-constant-condition @@ -11,6 +12,7 @@ export const startMainLoop = async () => { DownloadManager.watchDownloads(), AchievementWatcherManager.watchAchievements(), DownloadManager.getSeedStatus(), + UpdateManager.checkForUpdatePeriodically(), ]); await sleep(1500); diff --git a/src/main/services/update-manager.ts b/src/main/services/update-manager.ts new file mode 100644 index 00000000..963ecf2b --- /dev/null +++ b/src/main/services/update-manager.ts @@ -0,0 +1,60 @@ +import updater, { UpdateInfo } from "electron-updater"; +import { logger, WindowManager } from "@main/services"; +import { AppUpdaterEvent } from "@types"; +import { app } from "electron"; +import { publishNotificationUpdateReadyToInstall } from "@main/services/notifications"; + +const isAutoInstallAvailable = + process.platform !== "darwin" && process.env.PORTABLE_EXECUTABLE_FILE == null; + +const { autoUpdater } = updater; +const sendEventsForDebug = false; + +export class UpdateManager { + private static hasNotified = false; + private static newVersion = ""; + private static checkTick = 0; + + private static mockValuesForDebug() { + this.sendEvent({ type: "update-available", info: { version: "1.3.0" } }); + this.sendEvent({ type: "update-downloaded" }); + } + + private static sendEvent(event: AppUpdaterEvent) { + WindowManager.mainWindow?.webContents.send("autoUpdaterEvent", event); + } + + public static async checkForUpdates() { + autoUpdater + .once("update-available", (info: UpdateInfo) => { + this.sendEvent({ type: "update-available", info }); + this.newVersion = info.version; + }) + .once("update-downloaded", () => { + this.sendEvent({ type: "update-downloaded" }); + + if (!this.hasNotified) { + this.hasNotified = true; + publishNotificationUpdateReadyToInstall(this.newVersion); + } + }); + + if (app.isPackaged) { + autoUpdater.autoDownload = isAutoInstallAvailable; + autoUpdater.checkForUpdates().then((result) => { + logger.log(`Check for updates result: ${result}`); + }); + } else if (sendEventsForDebug) { + this.mockValuesForDebug(); + } + + return isAutoInstallAvailable; + } + + public static async checkForUpdatePeriodically() { + if (this.checkTick % 2000 == 0) { + this.checkForUpdates(); + } + this.checkTick++; + } +} diff --git a/src/renderer/src/components/header/auto-update-sub-header.tsx b/src/renderer/src/components/header/auto-update-sub-header.tsx index 5cf4d119..005cdfda 100644 --- a/src/renderer/src/components/header/auto-update-sub-header.tsx +++ b/src/renderer/src/components/header/auto-update-sub-header.tsx @@ -1,16 +1,13 @@ import { useTranslation } from "react-i18next"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { SyncIcon } from "@primer/octicons-react"; import { Link } from "../link/link"; import * as styles from "./header.css"; import type { AppUpdaterEvent } from "@types"; -import { minutesToMilliseconds } from "date-fns"; export const releasesPageUrl = "https://github.com/hydralauncher/hydra/releases/latest"; -const CHECK_FOR_UPDATES_INTERVAL = minutesToMilliseconds(60); - export function AutoUpdateSubHeader() { const [isReadyToInstall, setIsReadyToInstall] = useState(false); const [newVersion, setNewVersion] = useState(null); @@ -35,28 +32,15 @@ export function AutoUpdateSubHeader() { } ); + window.electron.checkForUpdates().then((isAutoInstallAvailable) => { + setIsAutoInstallAvailable(isAutoInstallAvailable); + }); + return () => { unsubscribe(); }; }, []); - const checkForUpdates = useCallback(() => { - window.electron.checkForUpdates().then((isAutoInstallAvailable) => { - setIsAutoInstallAvailable(isAutoInstallAvailable); - }); - }, []); - - useEffect(() => { - checkForUpdates(); - const checkInterval = setInterval(() => { - checkForUpdates(); - }, CHECK_FOR_UPDATES_INTERVAL); - - return () => { - clearInterval(checkInterval); - }; - }, [checkForUpdates]); - if (!newVersion) return null; if (!isAutoInstallAvailable) {