import utils from "@whitesev/utils"; import type { UtilsDictionary } from "@whitesev/utils/dist/types/src/Dictionary.js"; import { GM_addValueChangeListener, GM_deleteValue, GM_getValue, GM_removeValueChangeListener, GM_setValue, } from "ViteGM"; /** * 监听的值 */ type ListenerData = { id: number; key: string; callback: (key: string, newValue: any, oldValue: any) => IPromise; }; class StorageUtils { /** 存储的键名 */ storageKey: string; /** 监听的数据 */ private listenerData: UtilsDictionary; /** 缓存数据 */ private cacheData: any; /** 取消监听的回调 */ private callbacks: (() => void)[] = []; /** * 存储的键名,可以是多层的,如:a.b.c * * 那就是 * { * "a": { * "b": { * "c": { * ...你的数据 * } * } * } * } * @param key */ constructor(key: string) { if (typeof key === "string") { const trimKey = key.trim(); if (trimKey == "") { throw new Error("key can not be empty string"); } this.storageKey = trimKey; } else { throw new TypeError("key must be a string"); } this.listenerData = new utils.Dictionary(); this.getLocalValue = this.getLocalValue.bind(this); this.setLocalValue = this.setLocalValue.bind(this); this.destory = this.destory.bind(this); this.set = this.set.bind(this); this.get = this.get.bind(this); this.getAll = this.getAll.bind(this); this.delete = this.delete.bind(this); this.has = this.has.bind(this); this.keys = this.keys.bind(this); this.values = this.values.bind(this); this.clear = this.clear.bind(this); this.addValueChangeListener = this.addValueChangeListener.bind(this); this.removeValueChangeListener = this.removeValueChangeListener.bind(this); this.emitValueChangeListener = this.emitValueChangeListener.bind(this); } [Symbol.dispose]() { this.destory(); } async [Symbol.asyncDispose]() { this.destory(); } /** * 销毁 */ private destory() { this.cacheData = null; for (let index = this.callbacks.length - 1; index >= 0; index--) { const cb = this.callbacks[index]; cb(); this.callbacks.splice(index, 1); } } /** * 获取本地值 */ private getLocalValue(): any { if (this.cacheData == null) { let localValue = GM_getValue(this.storageKey); if (localValue == null) { localValue = {}; this.setLocalValue(localValue); } // 清空旧的 this.destory(); // 缓存数据 this.cacheData = localValue; const listenerId = GM_addValueChangeListener(this.storageKey, (name, oldValue, newValue) => { this.cacheData = null; this.cacheData = newValue; }); this.callbacks.push(() => { GM_removeValueChangeListener(listenerId); }); return localValue; } else { return this.cacheData; } } /** * 设置本地值 * @param value */ private setLocalValue(value: any) { this.cacheData = null; this.cacheData = value; GM_setValue(this.storageKey, value); } /** * 设置值 * @param key 键 * @param value 值 */ set(key: string, value: any) { const oldValue = this.get(key); const localValue = this.getLocalValue(); Reflect.set(localValue, key, value); this.setLocalValue(localValue); this.emitValueChangeListener(key, value, oldValue); } /** * 获取值 * @param key 键 * @param defaultValue 默认值 */ get(key: string, defaultValue?: T): T { const localValue = this.getLocalValue(); return Reflect.get(localValue, key) ?? defaultValue; } /** * 获取所有值 */ getAll(): T { const localValue = this.getLocalValue(); return localValue; } /** * 删除值 * @param key 键 */ delete(key: string) { const oldValue = this.get(key); const localValue = this.getLocalValue(); Reflect.deleteProperty(localValue, key); this.setLocalValue(localValue); this.emitValueChangeListener(key, void 0, oldValue); } /** * 判断是否存在该值 */ has(key: string) { const localValue = this.getLocalValue(); return Reflect.has(localValue, key); } /** * 获取所有键 */ keys() { const localValue = this.getLocalValue(); return Reflect.ownKeys(localValue); } /** * 获取所有值 */ values() { const localValue = this.getLocalValue(); return Reflect.ownKeys(localValue).map((key) => Reflect.get(localValue, key)); } /** * 清空所有值 */ clear() { this.destory(); GM_deleteValue(this.storageKey); } /** * 监听值改变 * + .set * + .delete * @param key 监听的键 * @param callback 值改变的回调函数 */ addValueChangeListener(key: string, callback: (key: string, newValue: T, oldValue: T) => void) { const listenerId = Math.random(); const listenerData = this.listenerData.get(key) || []; listenerData.push({ id: listenerId, key, callback, }); this.listenerData.set(key, listenerData); return listenerId; } /** * 移除监听 * @param listenerId 监听的id或键名 */ removeValueChangeListener(listenerId: number | string) { let flag = false; for (const [key, listenerData] of this.listenerData.entries()) { for (let index = 0; index < listenerData.length; index++) { const value = listenerData[index]; if ( (typeof listenerId === "string" && value.key === listenerId) || (typeof listenerId === "number" && value.id === listenerId) ) { listenerData.splice(index, 1); index--; flag = true; } } this.listenerData.set(key, listenerData); } return flag; } /** * 主动触发监听器 * @param key 键 * @param newValue 新值 * @param oldValue 旧值 */ emitValueChangeListener(key: string, newValue: any, oldValue: any): Promise; async emitValueChangeListener(...args: any[]) { const [key, newValue, oldValue] = args; if (!this.listenerData.has(key)) { return; } const listenerData = this.listenerData.get(key)!; for (let index = 0; index < listenerData.length; index++) { const data = listenerData[index]; if (typeof data.callback === "function") { // let value = this.get(key); let __newValue; let __oldValue; if (args.length === 1) { // [key] } else if (args.length === 2) { // [key, newValue] __newValue = newValue; } else if (args.length === 3) { // [key, newValue, oldValue] __newValue = newValue; __oldValue = oldValue; } await data.callback(key, __newValue, __oldValue); } } } } export { StorageUtils, type ListenerData };