From 7613b0ff26d81737de4403f251aa6d03df76d328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Sun, 22 Mar 2026 12:31:25 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=90=9B=20=E8=AE=BE=E5=A4=87=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=85=8D=E7=BD=AE=E6=94=B9=E7=94=A8=20chrome.storage.?= =?UTF-8?q?local=EF=BC=8C=E9=81=BF=E5=85=8D=E8=B7=A8=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=AF=BC=E8=87=B4=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SystemConfig 支持双 storage(sync/local)+ 懒迁移 - 云同步前预检 OAuth token,无 token 不弹窗 - AuthVerify 加 mutex 防止并发弹窗 - 删除 changetime 死代码 close #1296 fix #1261 --- packages/filesystem/auth.ts | 20 ++- src/app/service/service_worker/synchronize.ts | 12 +- src/pkg/config/config.test.ts | 159 ++++++++++++++++++ src/pkg/config/config.ts | 78 ++++++--- 4 files changed, 248 insertions(+), 21 deletions(-) create mode 100644 src/pkg/config/config.test.ts diff --git a/packages/filesystem/auth.ts b/packages/filesystem/auth.ts index a15e55fa7..4569cf4d2 100644 --- a/packages/filesystem/auth.ts +++ b/packages/filesystem/auth.ts @@ -74,7 +74,25 @@ export type Token = { createtime: number; }; -export async function AuthVerify(netDiskType: NetDiskType, invalid?: boolean) { +// OAuth 弹窗锁,确保同一时间只有一个 OAuth 弹窗 +// key: netDiskType, value: 正在进行的认证 Promise +const authLocks = new Map>(); + +export async function AuthVerify(netDiskType: NetDiskType, invalid?: boolean): Promise { + // 如果已有相同类型的认证在进行中,等待其完成 + const existing = authLocks.get(netDiskType); + if (existing && !invalid) { + return existing; + } + + const authPromise: Promise = doAuthVerify(netDiskType, invalid).finally(() => { + authLocks.delete(netDiskType); + }); + authLocks.set(netDiskType, authPromise); + return authPromise; +} + +async function doAuthVerify(netDiskType: NetDiskType, invalid?: boolean): Promise { let token: Token | undefined = undefined; const localStorageDAO = new LocalStorageDAO(); const key = `netdisk:token:${netDiskType}`; diff --git a/src/app/service/service_worker/synchronize.ts b/src/app/service/service_worker/synchronize.ts index 9d2c00a7f..5a4473c06 100644 --- a/src/app/service/service_worker/synchronize.ts +++ b/src/app/service/service_worker/synchronize.ts @@ -14,7 +14,8 @@ import type { FileInfo } from "@Packages/filesystem/filesystem"; import type FileSystem from "@Packages/filesystem/filesystem"; import ZipFileSystem from "@Packages/filesystem/zip/zip"; import FileSystemFactory, { type FileSystemType } from "@Packages/filesystem/factory"; -import { isWarpTokenError } from "@Packages/filesystem/error"; +import { isWarpTokenError, WarpTokenError } from "@Packages/filesystem/error"; +import { HasNetDiskToken, netDiskTypeMap } from "@Packages/filesystem/auth"; import type { Group } from "@Packages/message/server"; import type { MessageSend } from "@Packages/message/types"; import { type IMessageQueue } from "@Packages/message/message_queue"; @@ -302,6 +303,15 @@ export class SynchronizeService { async buildFileSystem(config: CloudSyncConfig) { let fs: FileSystem; try { + // 对 OAuth 类型的 filesystem,先检查 token 是否存在 + // 避免在未登录时自动弹出 OAuth 窗口(尤其是多脚本同步时会弹出大量窗口) + const netDiskType = netDiskTypeMap[config.filesystem]; + if (netDiskType) { + const hasToken = await HasNetDiskToken(netDiskType); + if (!hasToken) { + throw new WarpTokenError(new Error(`${config.filesystem} token not found, please login first`)); + } + } fs = await FileSystemFactory.create(config.filesystem, config.params[config.filesystem]); // 创建base目录 await FileSystemFactory.mkdirAll(fs, "ScriptCat/sync"); diff --git a/src/pkg/config/config.test.ts b/src/pkg/config/config.test.ts new file mode 100644 index 000000000..b4e18c390 --- /dev/null +++ b/src/pkg/config/config.test.ts @@ -0,0 +1,159 @@ +import { describe, expect, it, beforeEach } from "vitest"; +import { SystemConfig } from "./config"; +import { MessageQueue } from "@Packages/message/message_queue"; + +describe("SystemConfig 双 storage 与懒迁移", () => { + let mq: MessageQueue; + let config: SystemConfig; + + beforeEach(() => { + // 清空 storage 数据 + chrome.storage.sync.clear(); + chrome.storage.local.clear(); + mq = new MessageQueue(); + config = new SystemConfig(mq); + }); + + describe("local key 读写", () => { + it("cloud_sync 应写入 local storage 而非 sync", async () => { + const cloudSync = { + enable: true, + syncDelete: false, + syncStatus: true, + filesystem: "onedrive" as const, + params: { token: "test" }, + }; + config.setCloudSync(cloudSync); + + const result = await config.getCloudSync(); + expect(result).toEqual(cloudSync); + + // 验证值在 local 中 + const localData = await chrome.storage.local.get("system_cloud_sync"); + expect(localData["system_cloud_sync"]).toEqual(cloudSync); + + // 验证值不在 sync 中 + const syncData = await chrome.storage.sync.get("system_cloud_sync"); + expect(syncData["system_cloud_sync"]).toBeUndefined(); + }); + + it("language 应写入 local storage", async () => { + config.setLanguage("zh-CN"); + + // 通过 storage 验证写入位置 + const localData = await chrome.storage.local.get("system_language"); + expect(localData["system_language"]).toBe("zh-CN"); + + const syncData = await chrome.storage.sync.get("system_language"); + expect(syncData["system_language"]).toBeUndefined(); + }); + + it("vscode_url 应写入 local storage", async () => { + config.setVscodeUrl("ws://localhost:9999"); + + const localData = await chrome.storage.local.get("system_vscode_url"); + expect(localData["system_vscode_url"]).toBe("ws://localhost:9999"); + + const syncData = await chrome.storage.sync.get("system_vscode_url"); + expect(syncData["system_vscode_url"]).toBeUndefined(); + }); + + it("enable_script 应写入 local storage", async () => { + config.setEnableScript(false); + + const localData = await chrome.storage.local.get("system_enable_script"); + expect(localData["system_enable_script"]).toBe(false); + + const syncData = await chrome.storage.sync.get("system_enable_script"); + expect(syncData["system_enable_script"]).toBeUndefined(); + }); + }); + + describe("sync key 读写", () => { + it("check_script_update_cycle 应写入 sync storage", async () => { + config.setCheckScriptUpdateCycle(3600); + + const syncData = await chrome.storage.sync.get("system_check_script_update_cycle"); + expect(syncData["system_check_script_update_cycle"]).toBe(3600); + + const localData = await chrome.storage.local.get("system_check_script_update_cycle"); + expect(localData["system_check_script_update_cycle"]).toBeUndefined(); + }); + + it("enable_eslint 应写入 sync storage", async () => { + config.setEnableEslint(false); + + const syncData = await chrome.storage.sync.get("system_enable_eslint"); + expect(syncData["system_enable_eslint"]).toBe(false); + + const localData = await chrome.storage.local.get("system_enable_eslint"); + expect(localData["system_enable_eslint"]).toBeUndefined(); + }); + }); + + describe("懒迁移:sync → local", () => { + it("local key 的旧数据应从 sync 迁移到 local", async () => { + // 模拟旧版本数据在 sync 中 + const oldCloudSync = { + enable: true, + syncDelete: false, + syncStatus: true, + filesystem: "webdav" as const, + params: { url: "https://example.com" }, + }; + await chrome.storage.sync.set({ system_cloud_sync: oldCloudSync }); + + // 读取时应自动迁移 + const result = await config.getCloudSync(); + expect(result).toEqual(oldCloudSync); + + // 验证已迁移到 local + const localData = await chrome.storage.local.get("system_cloud_sync"); + expect(localData["system_cloud_sync"]).toEqual(oldCloudSync); + + // 验证已从 sync 中删除 + const syncData = await chrome.storage.sync.get("system_cloud_sync"); + expect(syncData["system_cloud_sync"]).toBeUndefined(); + }); + + it("local 有值时不应回退到 sync", async () => { + const localValue = "zh-CN"; + const syncValue = "en-US"; + await chrome.storage.local.set({ system_language: localValue }); + await chrome.storage.sync.set({ system_language: syncValue }); + + const result = await config.getLanguage(); + expect(result).toBe(localValue); + + // sync 中的值不应被删除(因为 local 有值,不触发迁移) + const syncData = await chrome.storage.sync.get("system_language"); + expect(syncData["system_language"]).toBe(syncValue); + }); + + it("sync 和 local 都没有值时返回默认值", async () => { + const result = await config.getCloudSync(); + expect(result).toEqual({ + enable: false, + syncDelete: false, + syncStatus: true, + filesystem: "webdav", + params: {}, + }); + }); + + it("迁移后再次读取应走缓存", async () => { + await chrome.storage.sync.set({ system_vscode_url: "ws://old:8642" }); + + // 第一次读取触发迁移 + const first = await config.getVscodeUrl(); + expect(first).toBe("ws://old:8642"); + + // 修改 local storage(模拟外部写入),验证缓存生效 + await chrome.storage.local.set({ system_vscode_url: "ws://new:9999" }); + + // 第二次读取应返回缓存值 + const second = await config.getVscodeUrl(); + expect(second).toBe("ws://old:8642"); + }); + }); +}); diff --git a/src/pkg/config/config.ts b/src/pkg/config/config.ts index 4215fb516..a92edccc4 100644 --- a/src/pkg/config/config.ts +++ b/src/pkg/config/config.ts @@ -73,7 +73,34 @@ export type SystemConfigValueType = export class SystemConfig { private readonly cache = new Map(); - private readonly storage = new ChromeStorage("system", true); + // 跨设备同步的配置项,使用 chrome.storage.sync + private readonly syncStorage = new ChromeStorage("system", true); + // 设备相关的配置项,使用 chrome.storage.local(不跨设备同步) + private readonly localStorage = new ChromeStorage("system", false); + + // 设备相关的配置项,存储在 chrome.storage.local 而非 sync + // 这些配置不应跨设备同步(如云同步认证、VSCode 连接、UI 布局等) + private static readonly LOCAL_KEYS: Set = new Set([ + "cloud_sync", // 云同步配置(token 存在本地,不应跨设备同步) + "backup", // 备份配置(含设备相关 filesystem params) + "cat_file_storage", // CAT 文件存储配置 + "vscode_url", // VSCode 连接地址(设备相关) + "vscode_reconnect", // VSCode 自动重连 + "language", // 语言偏好(可能因设备不同) + "script_list_column_width", // UI 列宽(取决于屏幕尺寸) + "check_update", // 更新检查状态(含设备 version) + "enable_script", // 全局脚本开关(设备独立) + "enable_script_incognito", // 隐身模式开关(浏览器级别) + ]); + + private isLocalKey(key: string): boolean { + return SystemConfig.LOCAL_KEYS.has(key); + } + + // 获取 key 对应的主 storage + private getStorage(key: string): ChromeStorage { + return this.isLocalKey(key) ? this.localStorage : this.syncStorage; + } private EE: EventEmitter = new EventEmitter(); @@ -108,21 +135,41 @@ export class SystemConfig { return this.addListener(key, callback); } + private resolveDefault(defaultValue: WithAsyncValue>): T | Promise { + //@ts-ignore + return (defaultValue?.asyncValue?.() || defaultValue) as T | Promise; + } + private _get( key: SystemConfigKey, defaultValue: WithAsyncValue> ): Promise { if (this.cache.has(key)) { - let val = this.cache.get(key); - //@ts-ignore - val = (val === undefined ? defaultValue?.asyncValue?.() || defaultValue : val) as T | Promise; - return Promise.resolve(val); + const val = this.cache.get(key); + return Promise.resolve(val === undefined ? this.resolveDefault(defaultValue) : (val as T)); } - return this.storage.get(key).then((val) => { + const storage = this.getStorage(key); + return storage.get(key).then((val) => { + if (val !== undefined) { + this.cache.set(key, val); + return val as T; + } + // 对 local key,回退读取 sync storage(兼容旧版本数据迁移) + if (this.isLocalKey(key)) { + return this.syncStorage.get(key).then((syncVal) => { + if (syncVal !== undefined) { + // 迁移到 local storage 并从 sync 中删除 + this.localStorage.set(key, syncVal); + this.syncStorage.remove(key); + this.cache.set(key, syncVal); + return syncVal as T; + } + this.cache.set(key, undefined); + return this.resolveDefault(defaultValue); + }); + } this.cache.set(key, val); - //@ts-ignore - val = (val === undefined ? defaultValue?.asyncValue?.() || defaultValue : val) as T | Promise; - return val; + return this.resolveDefault(defaultValue); }); } @@ -150,12 +197,13 @@ export class SystemConfig { private _set(key: T, value: SystemConfigValueType | undefined) { const prev = this.cache.get(key); + const storage = this.getStorage(key); if (value === undefined) { this.cache.delete(key); - this.storage.remove(key); + storage.remove(key); } else { this.cache.set(key, value); - this.storage.set(key, value); + storage.set(key, value); } // 发送消息通知更新 this.mq.publish>(SystemConfigChange, { @@ -165,14 +213,6 @@ export class SystemConfig { }); } - public getChangetime() { - return this._get("changetime", 0); - } - - public setChangetime(n: number) { - this._set("changetime", n); - } - defaultCheckScriptUpdateCycle() { return 86400; } From 3ac77f6360c6b9a8be3ede053126de7c73366c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Sun, 22 Mar 2026 12:44:10 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=94=A5=20=E7=A7=BB=E9=99=A4=20token?= =?UTF-8?q?=20=E9=A2=84=E6=A3=80=E5=92=8C=20OAuth=20=E5=8A=A0=E9=94=81?= =?UTF-8?q?=EF=BC=88=E9=85=8D=E7=BD=AE=E8=BF=81=E7=A7=BB=E5=90=8E=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E9=9C=80=E8=A6=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/filesystem/auth.ts | 20 +------------------ src/app/service/service_worker/synchronize.ts | 12 +---------- src/pkg/config/config.ts | 2 +- 3 files changed, 3 insertions(+), 31 deletions(-) diff --git a/packages/filesystem/auth.ts b/packages/filesystem/auth.ts index 4569cf4d2..a15e55fa7 100644 --- a/packages/filesystem/auth.ts +++ b/packages/filesystem/auth.ts @@ -74,25 +74,7 @@ export type Token = { createtime: number; }; -// OAuth 弹窗锁,确保同一时间只有一个 OAuth 弹窗 -// key: netDiskType, value: 正在进行的认证 Promise -const authLocks = new Map>(); - -export async function AuthVerify(netDiskType: NetDiskType, invalid?: boolean): Promise { - // 如果已有相同类型的认证在进行中,等待其完成 - const existing = authLocks.get(netDiskType); - if (existing && !invalid) { - return existing; - } - - const authPromise: Promise = doAuthVerify(netDiskType, invalid).finally(() => { - authLocks.delete(netDiskType); - }); - authLocks.set(netDiskType, authPromise); - return authPromise; -} - -async function doAuthVerify(netDiskType: NetDiskType, invalid?: boolean): Promise { +export async function AuthVerify(netDiskType: NetDiskType, invalid?: boolean) { let token: Token | undefined = undefined; const localStorageDAO = new LocalStorageDAO(); const key = `netdisk:token:${netDiskType}`; diff --git a/src/app/service/service_worker/synchronize.ts b/src/app/service/service_worker/synchronize.ts index 5a4473c06..9d2c00a7f 100644 --- a/src/app/service/service_worker/synchronize.ts +++ b/src/app/service/service_worker/synchronize.ts @@ -14,8 +14,7 @@ import type { FileInfo } from "@Packages/filesystem/filesystem"; import type FileSystem from "@Packages/filesystem/filesystem"; import ZipFileSystem from "@Packages/filesystem/zip/zip"; import FileSystemFactory, { type FileSystemType } from "@Packages/filesystem/factory"; -import { isWarpTokenError, WarpTokenError } from "@Packages/filesystem/error"; -import { HasNetDiskToken, netDiskTypeMap } from "@Packages/filesystem/auth"; +import { isWarpTokenError } from "@Packages/filesystem/error"; import type { Group } from "@Packages/message/server"; import type { MessageSend } from "@Packages/message/types"; import { type IMessageQueue } from "@Packages/message/message_queue"; @@ -303,15 +302,6 @@ export class SynchronizeService { async buildFileSystem(config: CloudSyncConfig) { let fs: FileSystem; try { - // 对 OAuth 类型的 filesystem,先检查 token 是否存在 - // 避免在未登录时自动弹出 OAuth 窗口(尤其是多脚本同步时会弹出大量窗口) - const netDiskType = netDiskTypeMap[config.filesystem]; - if (netDiskType) { - const hasToken = await HasNetDiskToken(netDiskType); - if (!hasToken) { - throw new WarpTokenError(new Error(`${config.filesystem} token not found, please login first`)); - } - } fs = await FileSystemFactory.create(config.filesystem, config.params[config.filesystem]); // 创建base目录 await FileSystemFactory.mkdirAll(fs, "ScriptCat/sync"); diff --git a/src/pkg/config/config.ts b/src/pkg/config/config.ts index a92edccc4..6b8b2bf93 100644 --- a/src/pkg/config/config.ts +++ b/src/pkg/config/config.ts @@ -88,7 +88,7 @@ export class SystemConfig { "vscode_reconnect", // VSCode 自动重连 "language", // 语言偏好(可能因设备不同) "script_list_column_width", // UI 列宽(取决于屏幕尺寸) - "check_update", // 更新检查状态(含设备 version) + "check_update", // 更新检查状态(各设备独立检查更新) "enable_script", // 全局脚本开关(设备独立) "enable_script_incognito", // 隐身模式开关(浏览器级别) ]); From e00891ac4dd60d2d503e5f6a7758ad085a700e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Sun, 22 Mar 2026 12:45:48 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=93=9D=20=E4=BF=AE=E6=AD=A3=20check?= =?UTF-8?q?=5Fupdate=20=E6=B3=A8=E9=87=8A=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pkg/config/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/config/config.ts b/src/pkg/config/config.ts index 6b8b2bf93..1fbe97b33 100644 --- a/src/pkg/config/config.ts +++ b/src/pkg/config/config.ts @@ -88,7 +88,7 @@ export class SystemConfig { "vscode_reconnect", // VSCode 自动重连 "language", // 语言偏好(可能因设备不同) "script_list_column_width", // UI 列宽(取决于屏幕尺寸) - "check_update", // 更新检查状态(各设备独立检查更新) + "check_update", // 扩展更新通知及已读状态(各设备已读状态独立) "enable_script", // 全局脚本开关(设备独立) "enable_script_incognito", // 隐身模式开关(浏览器级别) ]); From dd3720781a503048e0b3bc9abdaa6a1e64249fa6 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sun, 22 Mar 2026 14:31:56 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=E5=88=86=E7=A6=BB=20const?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pkg/config/config.ts | 18 ++---------------- src/pkg/config/consts.ts | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 src/pkg/config/consts.ts diff --git a/src/pkg/config/config.ts b/src/pkg/config/config.ts index 1fbe97b33..1014aa6af 100644 --- a/src/pkg/config/config.ts +++ b/src/pkg/config/config.ts @@ -8,6 +8,7 @@ import { ExtVersion } from "@App/app/const"; import defaultTypeDefinition from "@App/template/scriptcat.d.tpl"; import { toCamelCase } from "../utils/utils"; import EventEmitter from "eventemitter3"; +import { STORAGE_LOCAL_KEYS } from "./consts"; export const SystemConfigChange = "systemConfigChange"; @@ -78,23 +79,8 @@ export class SystemConfig { // 设备相关的配置项,使用 chrome.storage.local(不跨设备同步) private readonly localStorage = new ChromeStorage("system", false); - // 设备相关的配置项,存储在 chrome.storage.local 而非 sync - // 这些配置不应跨设备同步(如云同步认证、VSCode 连接、UI 布局等) - private static readonly LOCAL_KEYS: Set = new Set([ - "cloud_sync", // 云同步配置(token 存在本地,不应跨设备同步) - "backup", // 备份配置(含设备相关 filesystem params) - "cat_file_storage", // CAT 文件存储配置 - "vscode_url", // VSCode 连接地址(设备相关) - "vscode_reconnect", // VSCode 自动重连 - "language", // 语言偏好(可能因设备不同) - "script_list_column_width", // UI 列宽(取决于屏幕尺寸) - "check_update", // 扩展更新通知及已读状态(各设备已读状态独立) - "enable_script", // 全局脚本开关(设备独立) - "enable_script_incognito", // 隐身模式开关(浏览器级别) - ]); - private isLocalKey(key: string): boolean { - return SystemConfig.LOCAL_KEYS.has(key); + return STORAGE_LOCAL_KEYS.has(key); } // 获取 key 对应的主 storage diff --git a/src/pkg/config/consts.ts b/src/pkg/config/consts.ts new file mode 100644 index 000000000..6fa6bf5db --- /dev/null +++ b/src/pkg/config/consts.ts @@ -0,0 +1,14 @@ +// 设备相关的配置项,存储在 chrome.storage.local 而非 sync +// 这些配置不应跨设备同步(如云同步认证、VSCode 连接、UI 布局等) +export const STORAGE_LOCAL_KEYS: Set = new Set([ + "cloud_sync", // 云同步配置(token 存在本地,不应跨设备同步) + "backup", // 备份配置(含设备相关 filesystem params) + "cat_file_storage", // CAT 文件存储配置 + "vscode_url", // VSCode 连接地址(设备相关) + "vscode_reconnect", // VSCode 自动重连 + "language", // 语言偏好(可能因设备不同) + "script_list_column_width", // UI 列宽(取决于屏幕尺寸) + "check_update", // 扩展更新通知及已读状态(各设备已读状态独立) + "enable_script", // 全局脚本开关(设备独立) + "enable_script_incognito", // 隐身模式开关(浏览器级别) +]); From 4e85e1221f00ff05be79f21996bc04736fd503b8 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sun, 22 Mar 2026 14:44:17 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=BC=82=E6=AD=A5Storage?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pkg/config/config.ts | 45 ++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/pkg/config/config.ts b/src/pkg/config/config.ts index 1014aa6af..73e075b94 100644 --- a/src/pkg/config/config.ts +++ b/src/pkg/config/config.ts @@ -126,6 +126,22 @@ export class SystemConfig { return (defaultValue?.asyncValue?.() || defaultValue) as T | Promise; } + private async transferSyncToLocal( + key: SystemConfigKey, + defaultValue: WithAsyncValue> + ): Promise { + const syncVal = await this.syncStorage.get(key); + if (syncVal === undefined) { + this.cache.set(key, undefined); + return this.resolveDefault(defaultValue); + } + // 迁移到 local storage 并从 sync 中删除 + await this.syncStorage.remove(key); // 先删除 + await this.localStorage.set(key, syncVal); // 删除成功后储回本地 + this.cache.set(key, syncVal); + return syncVal as T; + } + private _get( key: SystemConfigKey, defaultValue: WithAsyncValue> @@ -142,17 +158,7 @@ export class SystemConfig { } // 对 local key,回退读取 sync storage(兼容旧版本数据迁移) if (this.isLocalKey(key)) { - return this.syncStorage.get(key).then((syncVal) => { - if (syncVal !== undefined) { - // 迁移到 local storage 并从 sync 中删除 - this.localStorage.set(key, syncVal); - this.syncStorage.remove(key); - this.cache.set(key, syncVal); - return syncVal as T; - } - this.cache.set(key, undefined); - return this.resolveDefault(defaultValue); - }); + return this.transferSyncToLocal(key, defaultValue); } this.cache.set(key, val); return this.resolveDefault(defaultValue); @@ -184,18 +190,21 @@ export class SystemConfig { private _set(key: T, value: SystemConfigValueType | undefined) { const prev = this.cache.get(key); const storage = this.getStorage(key); + let asyncOp; if (value === undefined) { this.cache.delete(key); - storage.remove(key); + asyncOp = storage.remove(key); } else { this.cache.set(key, value); - storage.set(key, value); + asyncOp = storage.set(key, value); } - // 发送消息通知更新 - this.mq.publish>(SystemConfigChange, { - key, - value, - prev, + asyncOp.then(() => { + // 发送消息通知更新 + this.mq.publish>(SystemConfigChange, { + key, + value, + prev, + }); }); }