data sync

This commit is contained in:
Gabe Yuan
2023-07-31 03:10:09 +08:00
parent 497084fe8a
commit 2aef159d9d
12 changed files with 14333 additions and 9971 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@
/node_modules
/.pnp
.pnp.js
.yarn
# testing
/coverage

1
.yarnrc.yml Normal file
View File

@@ -0,0 +1 @@
nodeLinker: node-modules

79
src/apis/data.js Normal file
View File

@@ -0,0 +1,79 @@
import { fetchPolyfill } from "../libs/fetch";
import {
KV_HEADER_KEY,
KV_RULES_KEY,
KV_SETTING_KEY,
STOKEY_RULES,
STOKEY_SETTING,
STOKEY_RULES_UPDATE_AT,
} from "../config";
import { getSetting, getRules } from "../libs";
import storage from "../libs/storage";
/**
* 同步数据
* @param {*} param0
* @returns
*/
const apiSyncData = async ({ key, value, updateAt }) => {
const { syncUrl, syncKey } = await getSetting();
if (!syncUrl || !syncKey) {
console.log("data sync should set the api and key");
return;
}
return fetchPolyfill(syncUrl, {
headers: {
"Content-type": "application/json",
[KV_HEADER_KEY]: syncKey,
},
method: "POST",
body: JSON.stringify({ key, value, updateAt }),
});
};
/**
* 同步rules
* @param {*} value
* @param {*} updateAt
*/
export const apiSyncRules = async (value, updateAt) => {
const res = await apiSyncData({
key: KV_RULES_KEY,
value,
updateAt,
});
console.log("res", res);
if (res && res.updateAt > updateAt) {
await storage.setObj(STOKEY_RULES, res.value);
await storage.setObj(STOKEY_RULES_UPDATE_AT, res.updateAt);
}
};
/**
* 同步setting
* @param {*} value
* @param {*} updateAt
*/
export const apiSyncSetting = async (value, updateAt) => {
const res = await apiSyncData({
key: KV_SETTING_KEY,
value,
updateAt,
});
console.log("res", res);
if (res && res.updateAt > updateAt) {
await storage.setObj(STOKEY_SETTING, res.value);
}
};
/**
* 同步全部数据
*/
export const apiSyncAll = async () => {
const setting = await getSetting();
const rules = await getRules();
const settingUpdateAt = setting.updateAt;
const rulesUpdateAt = (await storage.getObj(STOKEY_RULES_UPDATE_AT)) || 1;
await apiSyncSetting(setting, settingUpdateAt);
await apiSyncRules(rules, rulesUpdateAt);
};

View File

@@ -11,6 +11,7 @@ import {
import { fetchData, setFetchLimit } from "./libs/fetch";
import storage from "./libs/storage";
import { getSetting } from "./libs";
import { apiSyncAll } from "./apis/data";
/**
* 插件安装
@@ -26,6 +27,15 @@ browser.runtime.onInstalled.addListener(() => {
*/
browser.runtime.onStartup.addListener(async () => {
console.log("onStartup");
// 同步数据
try {
await apiSyncAll();
} catch (err) {
console.log("[sync all]", err);
}
// 清除缓存
const { clearCache } = await getSetting();
if (clearCache) {
caches.delete(CACHE_NAME);

View File

@@ -206,4 +206,12 @@ export const I18N = {
zh: `重启浏览器时清除缓存`,
en: `Clear cache when restarting browser`,
},
data_sync_url: {
zh: `数据同步接口`,
en: `Data Sync API`,
},
data_sync_key: {
zh: `数据同步密钥`,
en: `Data Sync Key`,
},
};

View File

@@ -8,6 +8,11 @@ export const APP_LCNAME = APP_NAME.toLowerCase();
export const STOKEY_MSAUTH = `${APP_NAME}_msauth`;
export const STOKEY_SETTING = `${APP_NAME}_setting`;
export const STOKEY_RULES = `${APP_NAME}_rules`;
export const STOKEY_RULES_UPDATE_AT = `${APP_NAME}_rules_update_at`;
export const KV_HEADER_KEY = "X-KISS-PSK";
export const KV_RULES_KEY = "KT_RULES";
export const KV_SETTING_KEY = "KT_SETTING";
export const CACHE_NAME = `${APP_NAME}_cache`;
@@ -130,6 +135,9 @@ export const DEFAULT_SETTING = {
openaiKey: "",
openaiModel: "gpt-4",
openaiPrompt: `You will be provided with a sentence in ${PROMPT_PLACE_FROM}, and your task is to translate it into ${PROMPT_PLACE_TO}.`,
syncUrl: "", // 数据同步接口
syncKey: "", // 数据同步密钥
updateAt: 1, // 更新时间
};
export const DEFAULT_RULES = [

View File

@@ -4,10 +4,12 @@ import {
OPT_STYLE_ALL,
OPT_LANGS_FROM,
OPT_LANGS_TO,
STOKEY_RULES_UPDATE_AT,
} from "../config";
import storage from "../libs/storage";
import { useStorages } from "./Storage";
import { matchValue } from "../libs/utils";
import { apiSyncRules } from "../apis/data";
/**
* 匹配规则增删改查 hook
@@ -17,6 +19,17 @@ export function useRules() {
const storages = useStorages();
const list = storages?.[STOKEY_RULES] || [];
const update = async (rules) => {
const now = Date.now();
await storage.setObj(STOKEY_RULES, rules);
await storage.setObj(STOKEY_RULES_UPDATE_AT, now);
try {
await apiSyncRules(rules, now);
} catch (err) {
console.log("[sync rules]", err);
}
};
const add = async (rule) => {
const rules = [...list];
if (rule.pattern === "*") {
@@ -26,7 +39,7 @@ export function useRules() {
return;
}
rules.unshift(rule);
await storage.setObj(STOKEY_RULES, rules);
await update(rules);
};
const del = async (pattern) => {
@@ -35,7 +48,7 @@ export function useRules() {
return;
}
rules = rules.filter((item) => item.pattern !== pattern);
await storage.setObj(STOKEY_RULES, rules);
await update(rules);
};
const put = async (pattern, obj) => {
@@ -45,13 +58,13 @@ export function useRules() {
}
const rule = rules.find((r) => r.pattern === pattern);
rule && Object.assign(rule, obj);
await storage.setObj(STOKEY_RULES, rules);
await update(rules);
};
const merge = async (newRules) => {
const rules = [...list];
const fromLangs = OPT_LANGS_FROM.map((item) => item[0]);
const toLangs = OPT_LANGS_TO.map((item) => item[0]);
const rules = [...list];
newRules
.filter(
({ pattern, selector }) =>
@@ -89,7 +102,7 @@ export function useRules() {
rules.unshift(newRule);
}
});
await storage.setObj(STOKEY_RULES, rules);
await update(rules);
};
return { list, add, del, put, merge };

View File

@@ -1,3 +1,4 @@
import { useCallback } from "react";
import { STOKEY_SETTING } from "../config";
import storage from "../libs/storage";
import { useStorages } from "./Storage";
@@ -16,7 +17,7 @@ export function useSetting() {
* @returns
*/
export function useSettingUpdate() {
return async (obj) => {
await storage.putObj(STOKEY_SETTING, obj);
};
return useCallback(async (obj) => {
await storage.putObj(STOKEY_SETTING, { ...obj, updateAt: Date.now() });
}, []);
}

View File

@@ -6,6 +6,7 @@ import {
STOKEY_MSAUTH,
DEFAULT_SETTING,
DEFAULT_RULES,
STOKEY_RULES_UPDATE_AT,
} from "../config";
import storage from "../libs/storage";
@@ -16,6 +17,7 @@ export const defaultStorage = {
[STOKEY_MSAUTH]: null,
[STOKEY_SETTING]: DEFAULT_SETTING,
[STOKEY_RULES]: DEFAULT_RULES,
[STOKEY_RULES_UPDATE_AT]: 1,
};
const StoragesContext = createContext(null);

View File

@@ -9,12 +9,22 @@ import { useSetting, useSettingUpdate } from "../../hooks/Setting";
import { limitNumber } from "../../libs/utils";
import { useI18n } from "../../hooks/I18n";
import { UI_LANGS } from "../../config";
import { apiSyncAll } from "../../apis/data";
import { useCallback } from "react";
export default function Settings() {
const i18n = useI18n();
const setting = useSetting();
const updateSetting = useSettingUpdate();
const handleSyncBlur = useCallback(async () => {
try {
await apiSyncAll();
} catch (err) {
console.log("sync data", err);
}
}, []);
if (!setting) {
return;
}
@@ -28,6 +38,8 @@ export default function Settings() {
openaiModel,
openaiPrompt,
clearCache,
syncUrl,
syncKey,
} = setting;
return (
@@ -102,6 +114,7 @@ export default function Settings() {
<TextField
size="small"
type="password"
label={i18n("openai_key")}
defaultValue={openaiKey}
onChange={(e) => {
@@ -135,6 +148,31 @@ export default function Settings() {
minRows={2}
maxRows={10}
/>
<TextField
size="small"
label={i18n("data_sync_url")}
defaultValue={syncUrl}
onChange={(e) => {
updateSetting({
syncUrl: e.target.value,
});
}}
onBlur={handleSyncBlur}
/>
<TextField
size="small"
type="password"
label={i18n("data_sync_key")}
defaultValue={syncKey}
onChange={(e) => {
updateSetting({
syncKey: e.target.value,
});
}}
onBlur={handleSyncBlur}
/>
</Stack>
</Box>
);

24119
yarn.lock

File diff suppressed because it is too large Load Diff