Browse Source

feat: close #2190 improve app auto updater

Yidadaa 1 year ago
parent
commit
be4834688d
4 changed files with 87 additions and 40 deletions
  1. 7 25
      app/components/settings.tsx
  2. 22 6
      app/config/build.ts
  3. 1 0
      app/constant.ts
  4. 57 9
      app/store/update.ts

+ 7 - 25
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 ? (
               <LoadingIcon />
             ) : hasNewVersion ? (
-              <Link href={UPDATE_URL} target="_blank" className="link">
+              <Link href={updateUrl} target="_blank" className="link">
                 {Locale.Settings.Update.GoToUpdate}
               </Link>
             ) : (

+ 22 - 6
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,
   };
 };
 

+ 1 - 0
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";

+ 57 - 9
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<void>;
   updateUsage: (force?: boolean) => Promise<void>;
+
+  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<UpdateStore>()(
   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;
+
+        set(() => ({ version }));
 
-        const overTenMins = Date.now() - get().lastUpdate > 10 * ONE_MINUTE;
-        if (!force && !overTenMins) return;
+        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,
           }));