update.ts 4.5 KB

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