update.ts 4.6 KB

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