This commit is contained in:
Gabe Yuan
2023-09-20 17:47:23 +08:00
parent 01ebc184ad
commit 489bc9534b
10 changed files with 117 additions and 153 deletions

View File

@@ -21,7 +21,7 @@ import { sha256 } from "../libs/utils";
* @param {*} data
* @returns
*/
export const apiSyncData = async (url, key, data, isBg = false) =>
export const apiSyncData = async (url, key, data) =>
fetchPolyfill(url, {
headers: {
"Content-type": "application/json",
@@ -29,16 +29,14 @@ export const apiSyncData = async (url, key, data, isBg = false) =>
},
method: "POST",
body: JSON.stringify(data),
isBg,
});
/**
* 下载数据
* @param {*} url
* @param {*} isBg
* @returns
*/
export const apiFetch = (url, isBg = false) => fetchPolyfill(url, { isBg });
export const apiFetch = (url) => fetchPolyfill(url);
/**
* 谷歌翻译

View File

@@ -32,7 +32,7 @@ browser.runtime.onStartup.addListener(async () => {
console.log("browser onStartup");
// 同步数据
await trySyncSettingAndRules(true);
await trySyncSettingAndRules();
// 清除缓存
const setting = await getSettingWithDefault();
@@ -41,7 +41,7 @@ browser.runtime.onStartup.addListener(async () => {
}
// 同步订阅规则
trySyncAllSubRules(setting, true);
trySyncAllSubRules(setting);
});
/**

View File

@@ -302,10 +302,11 @@ export const DEFAULT_SYNC = {
syncUrl: "", // 数据同步接口
syncUser: "", // 数据同步用户名
syncKey: "", // 数据同步密钥
settingUpdateAt: 0,
settingSyncAt: 0,
rulesUpdateAt: 0,
rulesSyncAt: 0,
syncMeta: {}, // 数据更新及同步信息
// settingUpdateAt: 0,
// settingSyncAt: 0,
// rulesUpdateAt: 0,
// rulesSyncAt: 0,
subRulesSyncAt: 0, // 订阅规则同步时间
dataCaches: {}, // 缓存同步时间
};

View File

@@ -1,8 +1,9 @@
import { STOKEY_RULES, DEFAULT_RULES } from "../config";
import { STOKEY_RULES, DEFAULT_RULES, KV_RULES_KEY } from "../config";
import { useStorage } from "./Storage";
import { trySyncRules } from "../libs/sync";
import { checkRules } from "../libs/rules";
import { useCallback } from "react";
import { useSyncMeta } from "./Sync";
/**
* 规则 hook
@@ -10,13 +11,15 @@ import { useCallback } from "react";
*/
export function useRules() {
const { data: list, save } = useStorage(STOKEY_RULES, DEFAULT_RULES);
const { updateSyncMeta } = useSyncMeta();
const updateRules = useCallback(
async (rules) => {
await save(rules);
trySyncRules(false, true);
await updateSyncMeta(KV_RULES_KEY);
trySyncRules();
},
[save]
[save, updateSyncMeta]
);
const add = useCallback(

View File

@@ -1,8 +1,9 @@
import { STOKEY_SETTING, DEFAULT_SETTING } from "../config";
import { STOKEY_SETTING, DEFAULT_SETTING, KV_SETTING_KEY } from "../config";
import { useStorage } from "./Storage";
import { trySyncSetting } from "../libs/sync";
import { createContext, useCallback, useContext, useMemo } from "react";
import { debounce } from "../libs/utils";
import { useSyncMeta } from "./Sync";
const SettingContext = createContext({
setting: null,
@@ -12,11 +13,12 @@ const SettingContext = createContext({
export function SettingProvider({ children }) {
const { data, update, reload } = useStorage(STOKEY_SETTING, DEFAULT_SETTING);
const { updateSyncMeta } = useSyncMeta();
const syncSetting = useMemo(
() =>
debounce(() => {
trySyncSetting(false, true);
trySyncSetting();
}, [2000]),
[]
);
@@ -24,9 +26,10 @@ export function SettingProvider({ children }) {
const updateSetting = useCallback(
async (obj) => {
await update(obj);
await updateSyncMeta(KV_SETTING_KEY);
syncSetting();
},
[update, syncSetting]
[update, syncSetting, updateSyncMeta]
);
if (!data) {

View File

@@ -11,6 +11,23 @@ export function useSync() {
return { sync: data, updateSync: update, reloadSync: reload };
}
/**
* update syncmeta hook
* @returns
*/
export function useSyncMeta() {
const { sync, updateSync } = useSync();
const updateSyncMeta = useCallback(
async (key) => {
const syncMeta = sync?.syncMeta || {};
syncMeta[key] = { ...(syncMeta[key] || {}), updateAt: Date.now() };
await updateSync({ syncMeta });
},
[sync, updateSync]
);
return { updateSyncMeta };
}
/**
* caches sync hook
* @param {*} url

View File

@@ -13,6 +13,7 @@ import {
DEFAULT_FETCH_LIMIT,
} from "../config";
import { msAuth } from "./auth";
import { isBg } from "./browser";
/**
* 油猴脚本的请求封装
@@ -176,13 +177,13 @@ export const fetchData = async (
* @param {*} opts
* @returns
*/
export const fetchPolyfill = async (input, { isBg = false, ...opts } = {}) => {
export const fetchPolyfill = async (input, opts) => {
if (!input.trim()) {
throw new Error("URL is empty");
}
// 插件
if (isExt && !isBg) {
if (isExt && !isBg()) {
const res = await sendBgMsg(MSG_FETCH, { input, opts });
if (res.error) {
throw new Error(res.error);

View File

@@ -149,5 +149,5 @@ export const saveRule = async (newRule) => {
rules.unshift(newRule);
}
await setRules(rules);
trySyncRules(false, true);
trySyncRules();
};

View File

@@ -25,8 +25,8 @@ const updateSyncDataCache = async (url) => {
* @param {*} url
* @returns
*/
export const syncSubRules = async (url, isBg = false) => {
const res = await apiFetch(url, isBg);
export const syncSubRules = async (url) => {
const res = await apiFetch(url);
const rules = checkRules(res).filter(
({ pattern }) => !isAllchar(pattern, GLOBAL_KEY)
);
@@ -41,10 +41,10 @@ export const syncSubRules = async (url, isBg = false) => {
* @param {*} url
* @returns
*/
export const syncAllSubRules = async (subrulesList, isBg = false) => {
export const syncAllSubRules = async (subrulesList) => {
for (let subrules of subrulesList) {
try {
await syncSubRules(subrules.url, isBg);
await syncSubRules(subrules.url);
await updateSyncDataCache(subrules.url);
} catch (err) {
console.log(`[sync subrule error]: ${subrules.url}`, err);
@@ -57,14 +57,14 @@ export const syncAllSubRules = async (subrulesList, isBg = false) => {
* @param {*} url
* @returns
*/
export const trySyncAllSubRules = async ({ subrulesList }, isBg = false) => {
export const trySyncAllSubRules = async ({ subrulesList }) => {
try {
const { subRulesSyncAt } = await getSyncWithDefault();
const now = Date.now();
const interval = 24 * 60 * 60 * 1000; // 间隔一天
if (now - subRulesSyncAt > interval) {
// 同步订阅规则
await syncAllSubRules(subrulesList, isBg);
await syncAllSubRules(subrulesList);
await updateSync({ subRulesSyncAt: now });
// 同步修复规则

View File

@@ -26,117 +26,90 @@ getPatcher().patch("request", (opts) => {
});
});
const syncByWebdav = async ({
key,
value,
syncUrl,
syncUser,
syncKey,
updateAt = 0,
syncAt = 0,
isForce = false,
}) => {
const syncByWebdav = async (data, { syncUrl, syncUser, syncKey }) => {
const client = createClient(syncUrl, {
username: syncUser,
password: syncKey,
});
const pathname = `/${APP_LCNAME}`;
const filename = `/${APP_LCNAME}/${key}`;
const data = JSON.stringify(value, null, " ");
const filename = `/${APP_LCNAME}/${data.key}`;
if ((await client.exists(pathname)) === false) {
await client.createDirectory(pathname);
}
const isExist = await client.exists(filename);
if (isExist && !isForce) {
const { lastmod } = await client.stat(filename);
const fileUpdateAt = Date.parse(lastmod);
if (syncAt === 0 || fileUpdateAt > updateAt) {
const data = await client.getFileContents(filename, { format: "text" });
return { updateAt: fileUpdateAt, value: JSON.parse(data) };
if (isExist) {
const cont = await client.getFileContents(filename, { format: "text" });
const webData = JSON.parse(cont);
if (webData.updateAt >= data.updateAt) {
return webData;
}
}
await client.putFileContents(filename, data);
const { lastmod } = await client.stat(filename);
const fileUpdateAt = Date.parse(lastmod);
return { updateAt: fileUpdateAt, value };
await client.putFileContents(filename, JSON.stringify(data, null, " "));
return data;
};
const syncByWorker = async ({
key,
value,
const syncByWorker = async (data, { syncUrl, syncKey }) => {
return await apiSyncData(`${syncUrl}/sync`, syncKey, data);
};
const syncData = async (key, valueFn) => {
const {
syncType,
syncUrl,
syncUser,
syncKey,
updateAt = 0,
syncAt = 0,
isBg = false,
isForce = false,
}) => {
if (isForce) {
updateAt = Date.now();
syncMeta = {},
} = await getSyncWithDefault();
if (!syncUrl || !syncKey || (syncType === OPT_SYNCTYPE_WEBDAV && !syncUser)) {
throw new Error("sync setting err");
}
return await apiSyncData(
`${syncUrl}/sync`,
syncKey,
{
let { updateAt = 0, syncAt = 0 } = syncMeta[key] || {};
syncAt === 0 && (updateAt = 0);
const value = await valueFn();
const data = {
key,
value,
updateAt: syncAt === 0 ? 0 : updateAt,
},
isBg
);
value: JSON.stringify(value),
updateAt,
};
const args = {
syncUrl,
syncUser,
syncKey,
};
const res =
syncType === OPT_SYNCTYPE_WEBDAV
? await syncByWebdav(data, args)
: await syncByWorker(data, args);
syncMeta[key] = {
updateAt: res.updateAt,
syncAt: Date.now(),
};
await updateSync({ syncMeta });
return [JSON.parse(res.value), res.updateAt > updateAt];
};
/**
* 同步设置
* @returns
*/
const syncSetting = async (isBg = false, isForce = false) => {
const {
syncType,
syncUrl,
syncUser,
syncKey,
settingUpdateAt = 0,
settingSyncAt = 0,
} = await getSyncWithDefault();
if (!syncUrl || !syncKey || (syncType === OPT_SYNCTYPE_WEBDAV && !syncUser)) {
return;
const syncSetting = async () => {
const [value, isNew] = await syncData(KV_SETTING_KEY, getSettingWithDefault);
if (isNew) {
await setSetting(value);
}
const setting = await getSettingWithDefault();
const args = {
key: KV_SETTING_KEY,
value: setting,
syncUrl,
syncUser,
syncKey,
updateAt: settingUpdateAt,
syncAt: settingSyncAt,
isBg,
isForce,
};
const res =
syncType === OPT_SYNCTYPE_WEBDAV
? await syncByWebdav(args)
: await syncByWorker(args);
if (res.updateAt > settingUpdateAt) {
await setSetting(res.value);
}
await updateSync({
settingUpdateAt: res.updateAt,
settingSyncAt: Date.now(),
});
return res.value;
};
export const trySyncSetting = async (isBg = false, isForce = false) => {
export const trySyncSetting = async () => {
try {
return await syncSetting(isBg, isForce);
await syncSetting();
} catch (err) {
console.log("[sync setting]", err);
}
@@ -146,50 +119,16 @@ export const trySyncSetting = async (isBg = false, isForce = false) => {
* 同步规则
* @returns
*/
const syncRules = async (isBg = false, isForce = false) => {
const {
syncType,
syncUrl,
syncUser,
syncKey,
rulesUpdateAt = 0,
rulesSyncAt = 0,
} = await getSyncWithDefault();
if (!syncUrl || !syncKey || (syncType === OPT_SYNCTYPE_WEBDAV && !syncUser)) {
return;
const syncRules = async () => {
const [value, isNew] = await syncData(KV_RULES_KEY, getRulesWithDefault);
if (isNew) {
await setRules(value);
}
const rules = await getRulesWithDefault();
const args = {
key: KV_RULES_KEY,
value: rules,
syncUrl,
syncUser,
syncKey,
updateAt: rulesUpdateAt,
syncAt: rulesSyncAt,
isBg,
isForce,
};
const res =
syncType === OPT_SYNCTYPE_WEBDAV
? await syncByWebdav(args)
: await syncByWorker(args);
if (res.updateAt > rulesUpdateAt) {
await setRules(res.value);
}
await updateSync({
rulesUpdateAt: res.updateAt,
rulesSyncAt: Date.now(),
});
return res.value;
};
export const trySyncRules = async (isBg = false, isForce = false) => {
export const trySyncRules = async () => {
try {
return await syncRules(isBg, isForce);
await syncRules();
} catch (err) {
console.log("[sync user rules]", err);
}
@@ -219,10 +158,12 @@ export const syncShareRules = async ({ rules, syncUrl, syncKey }) => {
* 同步个人设置和规则
* @returns
*/
export const syncSettingAndRules = async (isBg = false) => {
return [await syncSetting(isBg), await syncRules(isBg)];
export const syncSettingAndRules = async () => {
await syncSetting();
await syncRules();
};
export const trySyncSettingAndRules = async (isBg = false) => {
return [await trySyncSetting(isBg), await trySyncRules(isBg)];
export const trySyncSettingAndRules = async () => {
await trySyncSetting();
await trySyncRules();
};