From be4834688d635ac29c0e1a98a48eab7aab4ecbe4 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Fri, 30 Jun 2023 00:26:03 +0800 Subject: [PATCH] feat: close #2190 improve app auto updater --- app/components/settings.tsx | 32 ++++-------------- app/config/build.ts | 28 ++++++++++++---- app/constant.ts | 1 + app/store/update.ts | 66 ++++++++++++++++++++++++++++++++----- 4 files changed, 87 insertions(+), 40 deletions(-) diff --git a/app/components/settings.tsx b/app/components/settings.tsx index 47d76496..1ee7316a 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -40,7 +40,7 @@ import Locale, { } from "../locales"; import { copyToClipboard } from "../utils"; import Link from "next/link"; -import { Path, UPDATE_URL } from "../constant"; +import { Path, RELEASE_URL, UPDATE_URL } from "../constant"; import { Prompt, SearchService, usePromptStore } from "../store/prompt"; import { ErrorBoundary } from "./error"; import { InputRange } from "./input-range"; @@ -310,19 +310,6 @@ function SyncItems() { ); } -function formatVersionDate(t: string) { - const d = new Date(+t); - const year = d.getUTCFullYear(); - const month = d.getUTCMonth() + 1; - const day = d.getUTCDate(); - - return [ - year.toString(), - month.toString().padStart(2, "0"), - day.toString().padStart(2, "0"), - ].join(""); -} - export function Settings() { const navigate = useNavigate(); const [showEmojiPicker, setShowEmojiPicker] = useState(false); @@ -332,9 +319,10 @@ export function Settings() { const updateStore = useUpdateStore(); const [checkingUpdate, setCheckingUpdate] = useState(false); - const currentVersion = formatVersionDate(updateStore.version); - const remoteId = formatVersionDate(updateStore.remoteVersion); + const currentVersion = updateStore.formatVersion(updateStore.version); + const remoteId = updateStore.formatVersion(updateStore.remoteVersion); const hasNewVersion = currentVersion !== remoteId; + const updateUrl = getClientConfig()?.isApp ? RELEASE_URL : UPDATE_URL; function checkUpdate(force = false) { setCheckingUpdate(true); @@ -342,14 +330,8 @@ export function Settings() { setCheckingUpdate(false); }); - console.log( - "[Update] local version ", - new Date(+updateStore.version).toLocaleString(), - ); - console.log( - "[Update] remote version ", - new Date(+updateStore.remoteVersion).toLocaleString(), - ); + console.log("[Update] local version ", updateStore.version); + console.log("[Update] remote version ", updateStore.remoteVersion); } const usage = { @@ -460,7 +442,7 @@ export function Settings() { {checkingUpdate ? ( ) : hasNewVersion ? ( - + {Locale.Settings.Update.GoToUpdate} ) : ( diff --git a/app/config/build.ts b/app/config/build.ts index 2009b5f3..20237b5f 100644 --- a/app/config/build.ts +++ b/app/config/build.ts @@ -1,3 +1,5 @@ +import tauriConfig from "../../src-tauri/tauri.conf.json"; + export const getBuildConfig = () => { if (typeof process === "undefined") { throw Error( @@ -5,23 +7,37 @@ export const getBuildConfig = () => { ); } - const COMMIT_ID: string = (() => { + const buildMode = process.env.BUILD_MODE ?? "standalone"; + const isApp = !!process.env.BUILD_APP; + const version = tauriConfig.package.version; + + const commitInfo = (() => { try { const childProcess = require("child_process"); - return childProcess + const commitDate: string = childProcess .execSync('git log -1 --format="%at000" --date=unix') .toString() .trim(); + const commitHash: string = childProcess + .execSync('git log --pretty=format:"%H" -n 1') + .toString() + .trim(); + + return { commitDate, commitHash }; } catch (e) { console.error("[Build Config] No git or not from git repo."); - return "unknown"; + return { + commitDate: "unknown", + commitHash: "unknown", + }; } })(); return { - commitId: COMMIT_ID, - buildMode: process.env.BUILD_MODE ?? "standalone", - isApp: !!process.env.BUILD_APP, + version, + ...commitInfo, + buildMode, + isApp, }; }; diff --git a/app/constant.ts b/app/constant.ts index a0e2887c..b01fd788 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -3,6 +3,7 @@ export const REPO = "ChatGPT-Next-Web"; export const REPO_URL = `https://github.com/${OWNER}/${REPO}`; export const ISSUE_URL = `https://github.com/${OWNER}/${REPO}/issues`; export const UPDATE_URL = `${REPO_URL}#keep-updated`; +export const RELEASE_URL = `${REPO_URL}/releases`; export const FETCH_COMMIT_URL = `https://api.github.com/repos/${OWNER}/${REPO}/commits?per_page=1`; export const FETCH_TAG_URL = `https://api.github.com/repos/${OWNER}/${REPO}/tags?per_page=1`; export const RUNTIME_CONFIG_DOM = "danger-runtime-config"; diff --git a/app/store/update.ts b/app/store/update.ts index ca2ae70a..c336f03f 100644 --- a/app/store/update.ts +++ b/app/store/update.ts @@ -1,48 +1,96 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; -import { FETCH_COMMIT_URL, StoreKey } from "../constant"; +import { FETCH_COMMIT_URL, FETCH_TAG_URL, StoreKey } from "../constant"; import { api } from "../client/api"; import { getClientConfig } from "../config/client"; export interface UpdateStore { + versionType: "date" | "tag"; lastUpdate: number; + version: string; remoteVersion: string; used?: number; subscription?: number; lastUpdateUsage: number; - version: string; getLatestVersion: (force?: boolean) => Promise; updateUsage: (force?: boolean) => Promise; + + formatVersion: (version: string) => string; } const ONE_MINUTE = 60 * 1000; +function formatVersionDate(t: string) { + const d = new Date(+t); + const year = d.getUTCFullYear(); + const month = d.getUTCMonth() + 1; + const day = d.getUTCDate(); + + return [ + year.toString(), + month.toString().padStart(2, "0"), + day.toString().padStart(2, "0"), + ].join(""); +} + +async function getVersion(type: "date" | "tag") { + if (type === "date") { + const data = (await (await fetch(FETCH_COMMIT_URL)).json()) as { + commit: { + author: { name: string; date: string }; + }; + sha: string; + }[]; + const remoteCommitTime = data[0].commit.author.date; + const remoteId = new Date(remoteCommitTime).getTime().toString(); + return remoteId; + } else if (type === "tag") { + const data = (await (await fetch(FETCH_TAG_URL)).json()) as { + commit: { sha: string; url: string }; + name: string; + }[]; + return data.at(0)?.name; + } +} + export const useUpdateStore = create()( persist( (set, get) => ({ + versionType: "tag", lastUpdate: 0, + version: "unknown", remoteVersion: "", lastUpdateUsage: 0, - version: "unknown", + formatVersion(version: string) { + if (get().versionType === "date") { + version = formatVersionDate(version); + } + return version; + }, async getLatestVersion(force = false) { - set(() => ({ version: getClientConfig()?.commitId ?? "unknown" })); + const versionType = get().versionType; + let version = + versionType === "date" + ? getClientConfig()?.commitDate + : getClientConfig()?.version; - const overTenMins = Date.now() - get().lastUpdate > 10 * ONE_MINUTE; - if (!force && !overTenMins) return; + set(() => ({ version })); + + const shouldCheck = + Date.now() - get().lastUpdate > 24 * 60 * ONE_MINUTE; + if (!force && !shouldCheck) return; set(() => ({ lastUpdate: Date.now(), })); try { - const data = await (await fetch(FETCH_COMMIT_URL)).json(); - const remoteCommitTime = data[0].commit.committer.date; - const remoteId = new Date(remoteCommitTime).getTime().toString(); + const remoteId = await getVersion(versionType); set(() => ({ remoteVersion: remoteId, }));