update.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import {
  2. FETCH_COMMIT_URL,
  3. FETCH_TAG_URL,
  4. ModelProvider,
  5. StoreKey,
  6. } from "../constant";
  7. import { getClientConfig } from "../config/client";
  8. import { createPersistStore } from "../utils/store";
  9. import ChatGptIcon from "../icons/chatgpt.png";
  10. import Locale from "../locales";
  11. import { use } from "react";
  12. import { useAppConfig } from ".";
  13. import { ClientApi } from "../client/api";
  14. const ONE_MINUTE = 60 * 1000;
  15. const isApp = !!getClientConfig()?.isApp;
  16. function formatVersionDate(t: string) {
  17. const d = new Date(+t);
  18. const year = d.getUTCFullYear();
  19. const month = d.getUTCMonth() + 1;
  20. const day = d.getUTCDate();
  21. return [
  22. year.toString(),
  23. month.toString().padStart(2, "0"),
  24. day.toString().padStart(2, "0"),
  25. ].join("");
  26. }
  27. type VersionType = "date" | "tag";
  28. async function getVersion(type: VersionType) {
  29. if (type === "date") {
  30. const data = (await (await fetch(FETCH_COMMIT_URL)).json()) as {
  31. commit: {
  32. author: { name: string; date: string };
  33. };
  34. sha: string;
  35. }[];
  36. const remoteCommitTime = data[0].commit.author.date;
  37. const remoteId = new Date(remoteCommitTime).getTime().toString();
  38. return remoteId;
  39. } else if (type === "tag") {
  40. const data = (await (await fetch(FETCH_TAG_URL)).json()) as {
  41. commit: { sha: string; url: string };
  42. name: string;
  43. }[];
  44. return data.at(0)?.name;
  45. }
  46. }
  47. export const useUpdateStore = createPersistStore(
  48. {
  49. versionType: "tag" as VersionType,
  50. lastUpdate: 0,
  51. version: "unknown",
  52. remoteVersion: "",
  53. used: 0,
  54. subscription: 0,
  55. lastUpdateUsage: 0,
  56. },
  57. (set, get) => ({
  58. formatVersion(version: string) {
  59. if (get().versionType === "date") {
  60. version = formatVersionDate(version);
  61. }
  62. return version;
  63. },
  64. async getLatestVersion(force = false) {
  65. const versionType = get().versionType;
  66. let version =
  67. versionType === "date"
  68. ? getClientConfig()?.commitDate
  69. : getClientConfig()?.version;
  70. set(() => ({ version }));
  71. const shouldCheck = Date.now() - get().lastUpdate > 2 * 60 * ONE_MINUTE;
  72. if (!force && !shouldCheck) return;
  73. set(() => ({
  74. lastUpdate: Date.now(),
  75. }));
  76. try {
  77. const remoteId = await getVersion(versionType);
  78. set(() => ({
  79. remoteVersion: remoteId,
  80. }));
  81. if (window.__TAURI__?.notification && isApp) {
  82. // Check if notification permission is granted
  83. await window.__TAURI__?.notification
  84. .isPermissionGranted()
  85. .then((granted: any) => {
  86. if (!granted) {
  87. return;
  88. } else {
  89. // Request permission to show notifications
  90. window.__TAURI__?.notification
  91. .requestPermission()
  92. .then((permission: any) => {
  93. if (permission === "granted") {
  94. if (version === remoteId) {
  95. // Show a notification using Tauri
  96. window.__TAURI__?.notification.sendNotification({
  97. title: "NextChat",
  98. body: `${Locale.Settings.Update.IsLatest}`,
  99. icon: `${ChatGptIcon.src}`,
  100. sound: "Default",
  101. });
  102. } else {
  103. const updateMessage =
  104. Locale.Settings.Update.FoundUpdate(`${remoteId}`);
  105. // Show a notification for the new version using Tauri
  106. window.__TAURI__?.notification.sendNotification({
  107. title: "NextChat",
  108. body: updateMessage,
  109. icon: `${ChatGptIcon.src}`,
  110. sound: "Default",
  111. });
  112. }
  113. }
  114. });
  115. }
  116. });
  117. }
  118. console.log("[Got Upstream] ", remoteId);
  119. } catch (error) {
  120. console.error("[Fetch Upstream Commit Id]", error);
  121. }
  122. },
  123. async updateUsage(force = false) {
  124. // only support openai for now
  125. const overOneMinute = Date.now() - get().lastUpdateUsage >= ONE_MINUTE;
  126. if (!overOneMinute && !force) return;
  127. set(() => ({
  128. lastUpdateUsage: Date.now(),
  129. }));
  130. try {
  131. const api = new ClientApi(ModelProvider.GPT);
  132. const usage = await api.llm.usage();
  133. if (usage) {
  134. set(() => ({
  135. used: usage.used,
  136. subscription: usage.total,
  137. }));
  138. }
  139. } catch (e) {
  140. console.error((e as Error).message);
  141. }
  142. },
  143. }),
  144. {
  145. name: StoreKey.Update,
  146. version: 1,
  147. },
  148. );