From 1b2608da28cb6bb0bc27e6dd242ee42b06c65cfe Mon Sep 17 00:00:00 2001 From: terwer Date: Wed, 11 Oct 2023 13:27:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20#773=20=E5=81=8F=E5=A5=BD=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E6=95=B0=E6=8D=AE=E6=8C=81=E4=B9=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...commonStorage.ts => commonStorageAsync.ts} | 6 +- src/stores/common/jsonStorage.ts | 125 ++++++++++++++++++ src/stores/common/useCommonLocalStorage.ts | 73 ++++++++++ src/stores/common/useCommonStorageAsync.ts | 4 +- src/stores/usePublishPreferenceSetting.ts | 10 +- src/stores/useSiyuanSetting.ts | 6 +- 6 files changed, 213 insertions(+), 11 deletions(-) rename src/stores/common/{commonStorage.ts => commonStorageAsync.ts} (97%) create mode 100644 src/stores/common/jsonStorage.ts create mode 100644 src/stores/common/useCommonLocalStorage.ts diff --git a/src/stores/common/commonStorage.ts b/src/stores/common/commonStorageAsync.ts similarity index 97% rename from src/stores/common/commonStorage.ts rename to src/stores/common/commonStorageAsync.ts index b51fe344..3c126df7 100644 --- a/src/stores/common/commonStorage.ts +++ b/src/stores/common/commonStorageAsync.ts @@ -37,7 +37,7 @@ import { SiyuanDevice } from "zhi-device" * @version 0.9.0 * @since 0.9.0 */ -class CommonStorage implements StorageLikeAsync { +class CommonStorageAsync implements StorageLikeAsync { private readonly logger private readonly storageViaSiyuanApi private readonly kernelApi @@ -112,7 +112,7 @@ class CommonStorage implements StorageLikeAsync { * @returns 一个 Promise,在设置值后解析。 */ public async setItem(key: string, value: string): Promise { - // this.logger.debug(`Setting value for '${key}' in CommonStorage to '${value}'.`) + // this.logger.debug(`Setting value for '${key}' in CommonStorageAsync to '${value}'.`) if (this.storageViaSiyuanApi) { // 如果当前运行在思源笔记中,则直接返回空字符串 await this.kernelApi.saveTextData(key, value) @@ -125,4 +125,4 @@ class CommonStorage implements StorageLikeAsync { } } -export default CommonStorage +export default CommonStorageAsync diff --git a/src/stores/common/jsonStorage.ts b/src/stores/common/jsonStorage.ts new file mode 100644 index 00000000..ad6ae43b --- /dev/null +++ b/src/stores/common/jsonStorage.ts @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2023, Terwer . All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Terwer designates this + * particular file as subject to the "Classpath" exception as provided + * by Terwer in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Terwer, Shenzhen, Guangdong, China, youweics@163.com + * or visit www.terwer.space if you need additional information or have any + * questions. + */ + +import { StorageLike } from "@vueuse/core" +import { createAppLogger } from "~/src/utils/appLogger.ts" +import { SiyuanDevice } from "zhi-device" +import { JsonUtil } from "zhi-common" + +/** + * JSON 同步存储实现,实现了 `StorageLikeAsync` 接口。 + * https://github.com/vueuse/vueuse/blob/main/packages/core/ssr-handlers.ts#L11 + * + * @author terwer + * @version 1.7.0 + * @since 1.7.0 + */ +class JsonStorage implements StorageLike { + private readonly logger: any + private readonly fs: any + private readonly path: any + private readonly filePath: string + + constructor(filePath: string) { + this.logger = createAppLogger("json-storage") + + // 动态导入依赖 + const win = SiyuanDevice.siyuanWindow() + this.fs = win.require("fs") + this.path = win.require("path") + + // 确保文件存在 + const basePath = win?.siyuan.config.system.dataDir + this.filePath = this.path.join(basePath, filePath) + const storeDir = this.path.dirname(this.filePath) + this.logger.info("store dir =>", storeDir) + // 确保有目录 + if (!this.fs.existsSync(storeDir)) { + this.fs.mkdirSync(storeDir) + } + // 确保文件已经初始化 + if (!this.fs.existsSync(this.filePath)) { + this.writeFile({}) + } + this.logger.info("ininted json local storage in =>", this.filePath) + } + + /** + * 获取存储中的项目 + * + * @param {string} key - 存储项的键名 + * @returns {string | null} - 如果找到存储项,将返回其值;否则返回 null + */ + public getItem(key: string): string | null { + // this.logger.info("get item from json") + return this.getStoredItems()[key] || null + } + + /** + * 设置存储项的值 + * + * @param {string} key - 存储项的键名 + * @param {string} value - 要存储的值 + */ + public setItem(key: string, value: string): void { + // this.logger.info("set item from json") + const obj = this.getStoredItems() + obj[key] = value + this.writeFile(obj) + } + + /** + * 从存储中移除指定的项 + * + * @param {string} key - 要移除的存储项的键名 + */ + public removeItem(key: string): void { + // this.logger.info("removeItem item from json") + const obj = this.getStoredItems() + delete obj[key] + this.writeFile(obj) + } + + // ================ + // private methods + // ================ + private getStoredItems() { + return JsonUtil.safeParse(this.readFile(), {}) + } + + private readFile() { + return this.fs.readFileSync(this.filePath, this.getFileOptions()) + } + + private writeFile(obj) { + return this.fs.writeFileSync(this.filePath, JSON.stringify(obj), this.getFileOptions()) + } + + private getFileOptions() { + return { encoding: "utf8" } as any + } +} + +export default JsonStorage diff --git a/src/stores/common/useCommonLocalStorage.ts b/src/stores/common/useCommonLocalStorage.ts new file mode 100644 index 00000000..16f799e2 --- /dev/null +++ b/src/stores/common/useCommonLocalStorage.ts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023, Terwer . All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Terwer designates this + * particular file as subject to the "Classpath" exception as provided + * by Terwer in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Terwer, Shenzhen, Guangdong, China, youweics@163.com + * or visit www.terwer.space if you need additional information or have any + * questions. + */ +import type {MaybeRefOrGetter, RemovableRef} from "@vueuse/shared" +import type {StorageLike, UseStorageOptions} from "@vueuse/core" +import {defaultWindow, useStorage} from "@vueuse/core" +import JsonStorage from "~/src/stores/common/jsonStorage.ts" +import {createAppLogger} from "~/src/utils/appLogger.ts" +import {useSiyuanDevice} from "~/src/composables/useSiyuanDevice.ts" + +const logger = createAppLogger("use-common-local-storage") + +/** + * 通用响应式的 LocalStorage. + * + * @see https://vueuse.org/useCommonLocalStorage + * @param filePath json文件存储位置,可选,浏览器环境忽略此参数 + * @param key key + * @param initialValue 初始值 + * @param options 选项 + */ +const useCommonLocalStorage = ( + filePath: string, + key: string, + initialValue: MaybeRefOrGetter, + options: UseStorageOptions = {} +): RemovableRef => { + const localStorageAdaptor: StorageLike = getLocalStorageAdaptor(filePath, options) + return useStorage(key, initialValue, localStorageAdaptor, options) +} + +/** + * Electron环境使用json保存数据,否则使用浏览器存储 + * + * @author terwer + * @since 0.6.8 + */ +const getLocalStorageAdaptor = (filePath: string, options: UseStorageOptions = {}): StorageLike => { + let localStorageAdaptor: StorageLike + const { isInSiyuanOrSiyuanNewWin } = useSiyuanDevice() + if (isInSiyuanOrSiyuanNewWin()) { + localStorageAdaptor = new JsonStorage(filePath) + logger.info("using JsonStorage for localStorage") + } else { + const { window = defaultWindow } = options + localStorageAdaptor = window?.localStorage + logger.info("using window.localStorage for localStorage") + } + return localStorageAdaptor +} + +export default useCommonLocalStorage diff --git a/src/stores/common/useCommonStorageAsync.ts b/src/stores/common/useCommonStorageAsync.ts index 519976f7..e2dc9d07 100644 --- a/src/stores/common/useCommonStorageAsync.ts +++ b/src/stores/common/useCommonStorageAsync.ts @@ -23,7 +23,7 @@ * questions. */ -import CommonStorage from "~/src/stores/common/commonStorage.ts" +import CommonStorageAsync from "~/src/stores/common/commonStorageAsync.ts" import { StorageSerializers, toValue } from "@vueuse/core" import { createAppLogger } from "~/src/utils/appLogger.ts" import { ObjectUtil } from "zhi-common" @@ -39,7 +39,7 @@ export const useCommonStorageAsync = { const logger = createAppLogger("common-storage-async") - const commonStorage = new CommonStorage(storageKey) + const commonStorage = new CommonStorageAsync(storageKey) // 获取 initialValue 类型对应的序列化器,如果不存在则使用默认序列化器 const rawInit: T = toValue(initialValue) diff --git a/src/stores/usePublishPreferenceSetting.ts b/src/stores/usePublishPreferenceSetting.ts index 2f73ba86..4a9219b5 100644 --- a/src/stores/usePublishPreferenceSetting.ts +++ b/src/stores/usePublishPreferenceSetting.ts @@ -23,17 +23,19 @@ * questions. */ -import { RemovableRef, StorageSerializers, useLocalStorage } from "@vueuse/core" +import { RemovableRef, StorageSerializers } from "@vueuse/core" import { PublishPreferenceCfg } from "~/src/models/publishPreferenceCfg.ts" import { readonly } from "vue" -import {SiyuanDevice} from "zhi-device"; -import {createAppLogger} from "~/src/utils/appLogger.ts"; +import { SiyuanDevice } from "zhi-device" +import { createAppLogger } from "~/src/utils/appLogger.ts" +import useCommonLocalStorage from "~/src/stores/common/useCommonLocalStorage.ts" /** * 使用发布偏好设置的自定义钩子 */ const usePublishPreferenceSetting = () => { // 存储键 + const filePath = "storage/syp/publish-preference-cfg.json" const storageKey = "publish-preference-cfg" const logger = createAppLogger("use-publish-pref") @@ -46,7 +48,7 @@ const usePublishPreferenceSetting = () => { */ const getPublishPreferenceSetting = (): RemovableRef => { const initialValue = new PublishPreferenceCfg() - const prefConfig = useLocalStorage(storageKey, initialValue, { + const prefConfig = useCommonLocalStorage(filePath, storageKey, initialValue, { serializer: StorageSerializers.object, }) diff --git a/src/stores/useSiyuanSetting.ts b/src/stores/useSiyuanSetting.ts index f2f5bde8..cf3d1019 100644 --- a/src/stores/useSiyuanSetting.ts +++ b/src/stores/useSiyuanSetting.ts @@ -24,10 +24,11 @@ */ import { SiyuanConfig } from "zhi-siyuan-api" -import { RemovableRef, StorageSerializers, useLocalStorage } from "@vueuse/core" +import { RemovableRef, StorageSerializers } from "@vueuse/core" import { readonly } from "vue" import { SiyuanDevice } from "zhi-device" import { useSiyuanDevice } from "~/src/composables/useSiyuanDevice.ts" +import useCommonLocalStorage from "~/src/stores/common/useCommonLocalStorage.ts" /** * 思源笔记设置 @@ -37,6 +38,7 @@ import { useSiyuanDevice } from "~/src/composables/useSiyuanDevice.ts" * @since 1.8.0 */ const useSiyuanSetting = () => { + const filePath = "storage/syp/siyuan-cfg.json" const storageKey = "siyuan-cfg" const { isInSiyuanOrSiyuanNewWin } = useSiyuanDevice() @@ -59,7 +61,7 @@ const useSiyuanSetting = () => { const initialValue = new SiyuanConfig(origin ?? baseUrl, token) initialValue.middlewareUrl = middlewareUrl - const siyuanConfig = useLocalStorage(storageKey, initialValue, { + const siyuanConfig = useCommonLocalStorage(filePath, storageKey, initialValue, { serializer: StorageSerializers.object, })