refactor: Optimize data and cache request logic
This commit is contained in:
@@ -1,49 +1,19 @@
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import { fetchData } from "../libs/fetch";
|
import { fetchData } from "../libs/fetch";
|
||||||
import {
|
import {
|
||||||
OPT_TRANS_GOOGLE,
|
|
||||||
OPT_TRANS_GOOGLE_2,
|
|
||||||
OPT_TRANS_MICROSOFT,
|
|
||||||
OPT_TRANS_DEEPL,
|
|
||||||
OPT_TRANS_DEEPLFREE,
|
|
||||||
OPT_TRANS_DEEPLX,
|
|
||||||
OPT_TRANS_NIUTRANS,
|
|
||||||
OPT_TRANS_BAIDU,
|
|
||||||
OPT_TRANS_TENCENT,
|
|
||||||
OPT_TRANS_VOLCENGINE,
|
|
||||||
OPT_TRANS_OPENAI,
|
|
||||||
OPT_TRANS_OPENAI_2,
|
|
||||||
OPT_TRANS_OPENAI_3,
|
|
||||||
OPT_TRANS_GEMINI,
|
|
||||||
OPT_TRANS_GEMINI_2,
|
|
||||||
OPT_TRANS_CLAUDE,
|
|
||||||
OPT_TRANS_CLOUDFLAREAI,
|
|
||||||
OPT_TRANS_OLLAMA,
|
|
||||||
OPT_TRANS_OLLAMA_2,
|
|
||||||
OPT_TRANS_OLLAMA_3,
|
|
||||||
OPT_TRANS_OPENROUTER,
|
|
||||||
OPT_TRANS_CUSTOMIZE,
|
|
||||||
OPT_TRANS_CUSTOMIZE_2,
|
|
||||||
OPT_TRANS_CUSTOMIZE_3,
|
|
||||||
OPT_TRANS_CUSTOMIZE_4,
|
|
||||||
OPT_TRANS_CUSTOMIZE_5,
|
|
||||||
URL_CACHE_TRAN,
|
URL_CACHE_TRAN,
|
||||||
KV_SALT_SYNC,
|
KV_SALT_SYNC,
|
||||||
URL_GOOGLE_TRAN,
|
URL_GOOGLE_TRAN,
|
||||||
URL_MICROSOFT_LANGDETECT,
|
|
||||||
URL_BAIDU_LANGDETECT,
|
|
||||||
URL_BAIDU_SUGGEST,
|
|
||||||
URL_BAIDU_TTS,
|
|
||||||
OPT_LANGS_BAIDU,
|
OPT_LANGS_BAIDU,
|
||||||
URL_TENCENT_TRANSMART,
|
|
||||||
OPT_LANGS_TENCENT,
|
OPT_LANGS_TENCENT,
|
||||||
OPT_LANGS_SPECIAL,
|
OPT_LANGS_SPECIAL,
|
||||||
OPT_LANGS_MICROSOFT,
|
OPT_LANGS_MICROSOFT,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { sha256 } from "../libs/utils";
|
import { sha256 } from "../libs/utils";
|
||||||
import interpreter from "../libs/interpreter";
|
|
||||||
import { msAuth } from "../libs/auth";
|
import { msAuth } from "../libs/auth";
|
||||||
import { kissLog } from "../libs/log";
|
import { kissLog } from "../libs/log";
|
||||||
|
import { genTransReq, parseTransRes } from "./trans";
|
||||||
|
import { getHttpCachePolyfill, putHttpCachePolyfill } from "../libs/cache";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步数据
|
* 同步数据
|
||||||
@@ -85,14 +55,19 @@ export const apiGoogleLangdetect = async (text) => {
|
|||||||
q: text,
|
q: text,
|
||||||
};
|
};
|
||||||
const input = `${URL_GOOGLE_TRAN}?${queryString.stringify(params)}`;
|
const input = `${URL_GOOGLE_TRAN}?${queryString.stringify(params)}`;
|
||||||
const res = await fetchData(input, {
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
},
|
},
|
||||||
useCache: true,
|
};
|
||||||
});
|
const res = await fetchData(input, init, { useCache: true });
|
||||||
|
|
||||||
|
if (res?.src) {
|
||||||
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return res.src;
|
return res.src;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,17 +77,26 @@ export const apiGoogleLangdetect = async (text) => {
|
|||||||
*/
|
*/
|
||||||
export const apiMicrosoftLangdetect = async (text) => {
|
export const apiMicrosoftLangdetect = async (text) => {
|
||||||
const [token] = await msAuth();
|
const [token] = await msAuth();
|
||||||
const res = await fetchData(URL_MICROSOFT_LANGDETECT, {
|
const input =
|
||||||
|
"https://api-edge.cognitive.microsofttranslator.com/detect?api-version=3.0";
|
||||||
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify([{ Text: text }]),
|
body: JSON.stringify([{ Text: text }]),
|
||||||
|
};
|
||||||
|
const res = await fetchData(input, init, {
|
||||||
useCache: true,
|
useCache: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (res[0].language) {
|
||||||
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return OPT_LANGS_MICROSOFT.get(res[0].language) ?? res[0].language;
|
return OPT_LANGS_MICROSOFT.get(res[0].language) ?? res[0].language;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,7 +105,8 @@ export const apiMicrosoftLangdetect = async (text) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const apiBaiduLangdetect = async (text) => {
|
export const apiBaiduLangdetect = async (text) => {
|
||||||
const res = await fetchData(URL_BAIDU_LANGDETECT, {
|
const input = "https://fanyi.baidu.com/langdetect";
|
||||||
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
},
|
},
|
||||||
@@ -129,10 +114,11 @@ export const apiBaiduLangdetect = async (text) => {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
query: text,
|
query: text,
|
||||||
}),
|
}),
|
||||||
useCache: true,
|
};
|
||||||
});
|
const res = await fetchData(input, init, { useCache: true });
|
||||||
|
|
||||||
if (res.error === 0) {
|
if (res.error === 0) {
|
||||||
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return OPT_LANGS_BAIDU.get(res.lan) ?? res.lan;
|
return OPT_LANGS_BAIDU.get(res.lan) ?? res.lan;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +131,8 @@ export const apiBaiduLangdetect = async (text) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const apiBaiduSuggest = async (text) => {
|
export const apiBaiduSuggest = async (text) => {
|
||||||
const res = await fetchData(URL_BAIDU_SUGGEST, {
|
const input = "https://fanyi.baidu.com/sug";
|
||||||
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
},
|
},
|
||||||
@@ -153,10 +140,11 @@ export const apiBaiduSuggest = async (text) => {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
kw: text,
|
kw: text,
|
||||||
}),
|
}),
|
||||||
useCache: true,
|
};
|
||||||
});
|
const res = await fetchData(input, init, { useCache: true });
|
||||||
|
|
||||||
if (res.errno === 0) {
|
if (res.errno === 0) {
|
||||||
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,10 +159,8 @@ export const apiBaiduSuggest = async (text) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const apiBaiduTTS = (text, lan = "uk", spd = 3) => {
|
export const apiBaiduTTS = (text, lan = "uk", spd = 3) => {
|
||||||
const url = `${URL_BAIDU_TTS}?${queryString.stringify({ lan, text, spd })}`;
|
const input = `https://fanyi.baidu.com/gettts?${queryString.stringify({ lan, text, spd })}`;
|
||||||
return fetchData(url, {
|
return fetchData(input);
|
||||||
useCache: false, // 为避免缓存过快增长,禁用缓存语音数据
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -183,23 +169,28 @@ export const apiBaiduTTS = (text, lan = "uk", spd = 3) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const apiTencentLangdetect = async (text) => {
|
export const apiTencentLangdetect = async (text) => {
|
||||||
|
const input = "https://transmart.qq.com/api/imt";
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
header: {
|
header: {
|
||||||
fn: "text_analysis",
|
fn: "text_analysis",
|
||||||
},
|
},
|
||||||
text,
|
text,
|
||||||
});
|
});
|
||||||
|
const init = {
|
||||||
const res = await fetchData(URL_TENCENT_TRANSMART, {
|
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body,
|
body,
|
||||||
useCache: true,
|
};
|
||||||
});
|
const res = await fetchData(input, init, { useCache: true });
|
||||||
|
|
||||||
|
if (res.language) {
|
||||||
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return OPT_LANGS_TENCENT.get(res.language) ?? res.language;
|
return OPT_LANGS_TENCENT.get(res.language) ?? res.language;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -216,11 +207,12 @@ export const apiTranslate = async ({
|
|||||||
useCache = true,
|
useCache = true,
|
||||||
usePool = true,
|
usePool = true,
|
||||||
}) => {
|
}) => {
|
||||||
let trText = "";
|
let cacheInput; // 缓存URL
|
||||||
let isSame = false;
|
let resCache; // 缓存对象
|
||||||
|
let res; // 翻译接口返回的JSON数据
|
||||||
|
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return [trText, true];
|
return ["", false];
|
||||||
}
|
}
|
||||||
|
|
||||||
const from =
|
const from =
|
||||||
@@ -229,139 +221,59 @@ export const apiTranslate = async ({
|
|||||||
const to = OPT_LANGS_SPECIAL[translator].get(toLang);
|
const to = OPT_LANGS_SPECIAL[translator].get(toLang);
|
||||||
if (!to) {
|
if (!to) {
|
||||||
kissLog(`target lang: ${toLang} not support`, "translate");
|
kissLog(`target lang: ${toLang} not support`, "translate");
|
||||||
return [trText, isSame];
|
return ["", false];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 版本号一/二位升级,旧缓存失效
|
// 查询缓存数据
|
||||||
|
// TODO: 优化缓存失效因素
|
||||||
|
if (useCache) {
|
||||||
const [v1, v2] = process.env.REACT_APP_VERSION.split(".");
|
const [v1, v2] = process.env.REACT_APP_VERSION.split(".");
|
||||||
const cacheOpts = {
|
const cacheOpts = {
|
||||||
translator,
|
translator,
|
||||||
text,
|
text,
|
||||||
fromLang,
|
fromLang,
|
||||||
toLang,
|
toLang,
|
||||||
|
userPrompt: apiSetting.userPrompt, // prompt改变,缓存失效
|
||||||
|
model: apiSetting.model, // model改变,缓存失效
|
||||||
version: [v1, v2].join("."),
|
version: [v1, v2].join("."),
|
||||||
};
|
};
|
||||||
|
cacheInput = `${URL_CACHE_TRAN}?${queryString.stringify(cacheOpts)}`;
|
||||||
|
resCache = await getHttpCachePolyfill(cacheInput);
|
||||||
|
}
|
||||||
|
|
||||||
const transOpts = {
|
// 请求接口数据
|
||||||
translator,
|
if (!resCache) {
|
||||||
|
const [input, init] = await genTransReq(translator, {
|
||||||
text,
|
text,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
};
|
...apiSetting,
|
||||||
|
});
|
||||||
const res = await fetchData(
|
res = await fetchData(input, init, {
|
||||||
`${URL_CACHE_TRAN}?${queryString.stringify(cacheOpts)}`,
|
useCache: false,
|
||||||
{
|
|
||||||
useCache,
|
|
||||||
usePool,
|
usePool,
|
||||||
transOpts,
|
fetchInterval: apiSetting.fetchInterval,
|
||||||
apiSetting,
|
fetchLimit: apiSetting.fetchLimit,
|
||||||
|
httpTimeout: apiSetting.httpTimeout,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res = resCache;
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
switch (translator) {
|
if (!res) {
|
||||||
case OPT_TRANS_GOOGLE:
|
return ["", false];
|
||||||
trText = res.sentences.map((item) => item.trans).join(" ");
|
|
||||||
isSame = to === res.src;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_GOOGLE_2:
|
|
||||||
trText = res?.[0]?.[0] || "";
|
|
||||||
isSame = to === res.src;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_MICROSOFT:
|
|
||||||
trText = res
|
|
||||||
.map((item) => item.translations.map((item) => item.text).join(" "))
|
|
||||||
.join(" ");
|
|
||||||
isSame = text === trText;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_DEEPL:
|
|
||||||
trText = res.translations.map((item) => item.text).join(" ");
|
|
||||||
isSame = to === res.translations[0].detected_source_language;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_DEEPLFREE:
|
|
||||||
trText = res.result?.texts.map((item) => item.text).join(" ");
|
|
||||||
isSame = to === res.result?.lang;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_DEEPLX:
|
|
||||||
trText = res.data;
|
|
||||||
isSame = to === res.source_lang;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_NIUTRANS:
|
|
||||||
const json = JSON.parse(res);
|
|
||||||
if (json.error_msg) {
|
|
||||||
throw new Error(json.error_msg);
|
|
||||||
}
|
}
|
||||||
trText = json.tgt_text;
|
|
||||||
isSame = to === json.from;
|
// 解析返回数据
|
||||||
break;
|
const [trText, isSame] = parseTransRes(translator, res, apiSetting, {
|
||||||
case OPT_TRANS_BAIDU:
|
text,
|
||||||
// trText = res.trans_result?.data.map((item) => item.dst).join(" ");
|
from,
|
||||||
// isSame = res.trans_result?.to === res.trans_result?.from;
|
to,
|
||||||
if (res.type === 1) {
|
});
|
||||||
trText = Object.keys(JSON.parse(res.result).content[0].mean[0].cont)[0];
|
|
||||||
isSame = to === res.from;
|
// 插入缓存
|
||||||
} else if (res.type === 2) {
|
if (useCache && !resCache && trText) {
|
||||||
trText = res.data.map((item) => item.dst).join(" ");
|
await putHttpCachePolyfill(cacheInput, null, res);
|
||||||
isSame = to === res.from;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_TENCENT:
|
|
||||||
trText = res?.auto_translation?.[0];
|
|
||||||
isSame = text === trText;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_VOLCENGINE:
|
|
||||||
trText = res?.translation || "";
|
|
||||||
isSame = to === res?.detected_language;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_OPENAI:
|
|
||||||
case OPT_TRANS_OPENAI_2:
|
|
||||||
case OPT_TRANS_OPENAI_3:
|
|
||||||
case OPT_TRANS_GEMINI_2:
|
|
||||||
case OPT_TRANS_OPENROUTER:
|
|
||||||
trText = res?.choices?.map((item) => item.message.content).join(" ");
|
|
||||||
isSame = text === trText;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_GEMINI:
|
|
||||||
trText = res?.candidates
|
|
||||||
?.map((item) => item.content?.parts.map((item) => item.text).join(" "))
|
|
||||||
.join(" ");
|
|
||||||
isSame = text === trText;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_CLAUDE:
|
|
||||||
trText = res?.content?.map((item) => item.text).join(" ");
|
|
||||||
isSame = text === trText;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_CLOUDFLAREAI:
|
|
||||||
trText = res?.result?.translated_text;
|
|
||||||
isSame = text === trText;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_OLLAMA:
|
|
||||||
case OPT_TRANS_OLLAMA_2:
|
|
||||||
case OPT_TRANS_OLLAMA_3:
|
|
||||||
const { thinkIgnore = "" } = apiSetting;
|
|
||||||
const deepModels = thinkIgnore.split(",").filter((model) => model.trim());
|
|
||||||
if (deepModels.some((model) => res?.model?.startsWith(model))) {
|
|
||||||
trText = res?.response.replace(/<think>[\s\S]*<\/think>/i, "");
|
|
||||||
} else {
|
|
||||||
trText = res?.response;
|
|
||||||
}
|
|
||||||
isSame = text === trText;
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_CUSTOMIZE:
|
|
||||||
case OPT_TRANS_CUSTOMIZE_2:
|
|
||||||
case OPT_TRANS_CUSTOMIZE_3:
|
|
||||||
case OPT_TRANS_CUSTOMIZE_4:
|
|
||||||
case OPT_TRANS_CUSTOMIZE_5:
|
|
||||||
const { resHook } = apiSetting;
|
|
||||||
if (resHook?.trim()) {
|
|
||||||
interpreter.run(`exports.resHook = ${resHook}`);
|
|
||||||
[trText, isSame] = interpreter.exports.resHook(res, text, from, to);
|
|
||||||
} else {
|
|
||||||
trText = res.text;
|
|
||||||
isSame = to === res.from;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [trText, isSame, res];
|
return [trText, isSame, res];
|
||||||
|
|||||||
@@ -629,9 +629,7 @@ const genCustom = ({ text, from, to, url, key, reqHook }) => {
|
|||||||
* @param {*}
|
* @param {*}
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
|
export const genTransReq = (translator, args) => {
|
||||||
const args = { text, from, to, ...apiSetting };
|
|
||||||
|
|
||||||
switch (translator) {
|
switch (translator) {
|
||||||
case OPT_TRANS_DEEPL:
|
case OPT_TRANS_DEEPL:
|
||||||
case OPT_TRANS_OPENAI:
|
case OPT_TRANS_OPENAI:
|
||||||
@@ -708,3 +706,128 @@ export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
|
|||||||
throw new Error(`[trans] translator: ${translator} not support`);
|
throw new Error(`[trans] translator: ${translator} not support`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析翻译接口返回数据
|
||||||
|
* @param {*} translator
|
||||||
|
* @param {*} res
|
||||||
|
* @param {*} apiSetting
|
||||||
|
* @param {*} param3
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const parseTransRes = (
|
||||||
|
translator,
|
||||||
|
res,
|
||||||
|
apiSetting,
|
||||||
|
{ text, from, to }
|
||||||
|
) => {
|
||||||
|
let trText = ""; // 返回的译文
|
||||||
|
let isSame = false; // 译文与原文语言是否相同
|
||||||
|
|
||||||
|
switch (translator) {
|
||||||
|
case OPT_TRANS_GOOGLE:
|
||||||
|
trText = res.sentences.map((item) => item.trans).join(" ");
|
||||||
|
isSame = to === res.src;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_GOOGLE_2:
|
||||||
|
trText = res?.[0]?.[0] || "";
|
||||||
|
isSame = to === res.src;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_MICROSOFT:
|
||||||
|
trText = res
|
||||||
|
.map((item) => item.translations.map((item) => item.text).join(" "))
|
||||||
|
.join(" ");
|
||||||
|
isSame = text === trText;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_DEEPL:
|
||||||
|
trText = res.translations.map((item) => item.text).join(" ");
|
||||||
|
isSame = to === res.translations[0].detected_source_language;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_DEEPLFREE:
|
||||||
|
trText = res.result?.texts.map((item) => item.text).join(" ");
|
||||||
|
isSame = to === res.result?.lang;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_DEEPLX:
|
||||||
|
trText = res.data;
|
||||||
|
isSame = to === res.source_lang;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_NIUTRANS:
|
||||||
|
const json = JSON.parse(res);
|
||||||
|
if (json.error_msg) {
|
||||||
|
throw new Error(json.error_msg);
|
||||||
|
}
|
||||||
|
trText = json.tgt_text;
|
||||||
|
isSame = to === json.from;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_BAIDU:
|
||||||
|
// trText = res.trans_result?.data.map((item) => item.dst).join(" ");
|
||||||
|
// isSame = res.trans_result?.to === res.trans_result?.from;
|
||||||
|
if (res.type === 1) {
|
||||||
|
trText = Object.keys(JSON.parse(res.result).content[0].mean[0].cont)[0];
|
||||||
|
isSame = to === res.from;
|
||||||
|
} else if (res.type === 2) {
|
||||||
|
trText = res.data.map((item) => item.dst).join(" ");
|
||||||
|
isSame = to === res.from;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_TENCENT:
|
||||||
|
trText = res?.auto_translation?.[0];
|
||||||
|
isSame = text === trText;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_VOLCENGINE:
|
||||||
|
trText = res?.translation || "";
|
||||||
|
isSame = to === res?.detected_language;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_OPENAI:
|
||||||
|
case OPT_TRANS_OPENAI_2:
|
||||||
|
case OPT_TRANS_OPENAI_3:
|
||||||
|
case OPT_TRANS_GEMINI_2:
|
||||||
|
case OPT_TRANS_OPENROUTER:
|
||||||
|
trText = res?.choices?.map((item) => item.message.content).join(" ");
|
||||||
|
isSame = text === trText;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_GEMINI:
|
||||||
|
trText = res?.candidates
|
||||||
|
?.map((item) => item.content?.parts.map((item) => item.text).join(" "))
|
||||||
|
.join(" ");
|
||||||
|
isSame = text === trText;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_CLAUDE:
|
||||||
|
trText = res?.content?.map((item) => item.text).join(" ");
|
||||||
|
isSame = text === trText;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_CLOUDFLAREAI:
|
||||||
|
trText = res?.result?.translated_text;
|
||||||
|
isSame = text === trText;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_OLLAMA:
|
||||||
|
case OPT_TRANS_OLLAMA_2:
|
||||||
|
case OPT_TRANS_OLLAMA_3:
|
||||||
|
const { thinkIgnore = "" } = apiSetting;
|
||||||
|
const deepModels = thinkIgnore.split(",").filter((model) => model.trim());
|
||||||
|
if (deepModels.some((model) => res?.model?.startsWith(model))) {
|
||||||
|
trText = res?.response.replace(/<think>[\s\S]*<\/think>/i, "");
|
||||||
|
} else {
|
||||||
|
trText = res?.response;
|
||||||
|
}
|
||||||
|
isSame = text === trText;
|
||||||
|
break;
|
||||||
|
case OPT_TRANS_CUSTOMIZE:
|
||||||
|
case OPT_TRANS_CUSTOMIZE_2:
|
||||||
|
case OPT_TRANS_CUSTOMIZE_3:
|
||||||
|
case OPT_TRANS_CUSTOMIZE_4:
|
||||||
|
case OPT_TRANS_CUSTOMIZE_5:
|
||||||
|
const { resHook } = apiSetting;
|
||||||
|
if (resHook?.trim()) {
|
||||||
|
interpreter.run(`exports.resHook = ${resHook}`);
|
||||||
|
[trText, isSame] = interpreter.exports.resHook(res, text, from, to);
|
||||||
|
} else {
|
||||||
|
trText = res.text;
|
||||||
|
isSame = to === res.from;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return [trText, isSame];
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import browser from "webextension-polyfill";
|
|||||||
import {
|
import {
|
||||||
MSG_FETCH,
|
MSG_FETCH,
|
||||||
MSG_GET_HTTPCACHE,
|
MSG_GET_HTTPCACHE,
|
||||||
|
MSG_PUT_HTTPCACHE,
|
||||||
MSG_TRANS_TOGGLE,
|
MSG_TRANS_TOGGLE,
|
||||||
MSG_OPEN_OPTIONS,
|
MSG_OPEN_OPTIONS,
|
||||||
MSG_SAVE_RULE,
|
MSG_SAVE_RULE,
|
||||||
@@ -21,7 +22,8 @@ import {
|
|||||||
} from "./config";
|
} from "./config";
|
||||||
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
|
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
|
||||||
import { trySyncSettingAndRules } from "./libs/sync";
|
import { trySyncSettingAndRules } from "./libs/sync";
|
||||||
import { fetchHandle, getHttpCache } from "./libs/fetch";
|
import { fetchHandle } from "./libs/fetch";
|
||||||
|
import { getHttpCache, putHttpCache } from "./libs/cache";
|
||||||
import { sendTabMsg } from "./libs/msg";
|
import { sendTabMsg } from "./libs/msg";
|
||||||
import { trySyncAllSubRules } from "./libs/subRules";
|
import { trySyncAllSubRules } from "./libs/subRules";
|
||||||
import { tryClearCaches } from "./libs";
|
import { tryClearCaches } from "./libs";
|
||||||
@@ -190,8 +192,9 @@ browser.runtime.onMessage.addListener(async ({ action, args }) => {
|
|||||||
case MSG_FETCH:
|
case MSG_FETCH:
|
||||||
return await fetchHandle(args);
|
return await fetchHandle(args);
|
||||||
case MSG_GET_HTTPCACHE:
|
case MSG_GET_HTTPCACHE:
|
||||||
const { input, init } = args;
|
return await getHttpCache(args.input, args.init);
|
||||||
return await getHttpCache(input, init);
|
case MSG_PUT_HTTPCACHE:
|
||||||
|
return await putHttpCache(args.input, args.init, args.data);
|
||||||
case MSG_OPEN_OPTIONS:
|
case MSG_OPEN_OPTIONS:
|
||||||
return await browser.runtime.openOptionsPage();
|
return await browser.runtime.openOptionsPage();
|
||||||
case MSG_SAVE_RULE:
|
case MSG_SAVE_RULE:
|
||||||
|
|||||||
@@ -703,9 +703,9 @@ export const I18N = {
|
|||||||
zh_TW: `OpenAI 提示詞`,
|
zh_TW: `OpenAI 提示詞`,
|
||||||
},
|
},
|
||||||
if_clear_cache: {
|
if_clear_cache: {
|
||||||
zh: `是否清除缓存`,
|
zh: `是否清除缓存(默认缓存7天)`,
|
||||||
en: `Whether clear cache`,
|
en: `Whether clear cache (Default cache is 7 days)`,
|
||||||
zh_TW: `是否清除快取`,
|
zh_TW: `是否清除快取(預設快取7天)`,
|
||||||
},
|
},
|
||||||
clear_cache_never: {
|
clear_cache_never: {
|
||||||
zh: `不清除缓存`,
|
zh: `不清除缓存`,
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export const CACHE_NAME = `${APP_NAME}_cache`;
|
|||||||
|
|
||||||
export const MSG_FETCH = "fetch";
|
export const MSG_FETCH = "fetch";
|
||||||
export const MSG_GET_HTTPCACHE = "get_httpcache";
|
export const MSG_GET_HTTPCACHE = "get_httpcache";
|
||||||
|
export const MSG_PUT_HTTPCACHE = "put_httpcache";
|
||||||
export const MSG_OPEN_OPTIONS = "open_options";
|
export const MSG_OPEN_OPTIONS = "open_options";
|
||||||
export const MSG_SAVE_RULE = "save_rule";
|
export const MSG_SAVE_RULE = "save_rule";
|
||||||
export const MSG_TRANS_TOGGLE = "trans_toggle";
|
export const MSG_TRANS_TOGGLE = "trans_toggle";
|
||||||
@@ -551,6 +552,7 @@ export const DEFAULT_SUBRULES_LIST = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const DEFAULT_HTTP_TIMEOUT = 5000; // 调用超时时间
|
export const DEFAULT_HTTP_TIMEOUT = 5000; // 调用超时时间
|
||||||
|
export const DEFAULT_CACHE_TIMEOUT = 3600 * 24 * 7; // 缓存超时时间(7天)
|
||||||
|
|
||||||
// 翻译接口
|
// 翻译接口
|
||||||
const defaultCustomApi = {
|
const defaultCustomApi = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { getMsauth, setMsauth } from "./storage";
|
import { getMsauth, setMsauth } from "./storage";
|
||||||
import { URL_MICROSOFT_AUTH } from "../config";
|
import { URL_MICROSOFT_AUTH } from "../config";
|
||||||
import { fetchHandle } from "./fetch";
|
import { fetchData } from "./fetch";
|
||||||
import { kissLog } from "./log";
|
import { kissLog } from "./log";
|
||||||
|
|
||||||
const parseMSToken = (token) => {
|
const parseMSToken = (token) => {
|
||||||
@@ -35,7 +35,7 @@ const _msAuth = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 缓存没有或失效,查询接口
|
// 缓存没有或失效,查询接口
|
||||||
token = await fetchHandle({ input: URL_MICROSOFT_AUTH });
|
token = await fetchData(URL_MICROSOFT_AUTH);
|
||||||
exp = parseMSToken(token);
|
exp = parseMSToken(token);
|
||||||
await setMsauth({ token, exp });
|
await setMsauth({ token, exp });
|
||||||
return [token, exp];
|
return [token, exp];
|
||||||
|
|||||||
137
src/libs/cache.js
Normal file
137
src/libs/cache.js
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
import {
|
||||||
|
CACHE_NAME,
|
||||||
|
DEFAULT_CACHE_TIMEOUT,
|
||||||
|
MSG_GET_HTTPCACHE,
|
||||||
|
MSG_PUT_HTTPCACHE,
|
||||||
|
} from "../config";
|
||||||
|
import { kissLog } from "./log";
|
||||||
|
import { isExt } from "./client";
|
||||||
|
import { isBg } from "./browser";
|
||||||
|
import { sendBgMsg } from "./msg";
|
||||||
|
import { blobToBase64 } from "./utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造缓存 request
|
||||||
|
* @param {*} input
|
||||||
|
* @param {*} init
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const newCacheReq = async (input, init) => {
|
||||||
|
let request = new Request(input, init);
|
||||||
|
if (request.method !== "GET") {
|
||||||
|
const body = await request.text();
|
||||||
|
const cacheUrl = new URL(request.url);
|
||||||
|
cacheUrl.pathname += body;
|
||||||
|
request = new Request(cacheUrl.toString(), { method: "GET" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询 caches
|
||||||
|
* @param {*} input
|
||||||
|
* @param {*} init
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getHttpCache = async (input, init) => {
|
||||||
|
try {
|
||||||
|
const req = await newCacheReq(input, init);
|
||||||
|
const cache = await caches.open(CACHE_NAME);
|
||||||
|
const res = await cache.match(req);
|
||||||
|
if (res) {
|
||||||
|
return await parseResponse(res);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
kissLog(err, "get cache");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入 caches
|
||||||
|
* @param {*} input
|
||||||
|
* @param {*} init
|
||||||
|
* @param {*} data
|
||||||
|
*/
|
||||||
|
export const putHttpCache = async (input, init, data) => {
|
||||||
|
try {
|
||||||
|
const req = await newCacheReq(input, init);
|
||||||
|
const cache = await caches.open(CACHE_NAME);
|
||||||
|
const res = new Response(JSON.stringify(data), {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Cache-Control": `max-age=${DEFAULT_CACHE_TIMEOUT}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// res.headers.set("Cache-Control", `max-age=${DEFAULT_CACHE_TIMEOUT}`);
|
||||||
|
await cache.put(req, res);
|
||||||
|
} catch (err) {
|
||||||
|
kissLog(err, "put cache");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 response
|
||||||
|
* @param {*} res
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const parseResponse = async (res) => {
|
||||||
|
if (!res) {
|
||||||
|
throw new Error("Response object does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const msg = {
|
||||||
|
url: res.url,
|
||||||
|
status: res.status,
|
||||||
|
};
|
||||||
|
if (res.headers.get("Content-Type")?.includes("json")) {
|
||||||
|
msg.response = await res.json();
|
||||||
|
}
|
||||||
|
throw new Error(JSON.stringify(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = res.headers.get("Content-Type");
|
||||||
|
if (contentType?.includes("json")) {
|
||||||
|
return res.json();
|
||||||
|
} else if (contentType?.includes("audio")) {
|
||||||
|
const blob = await res.blob();
|
||||||
|
return blobToBase64(blob);
|
||||||
|
}
|
||||||
|
return res.text();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getHttpCache 兼容性封装
|
||||||
|
* @param {*} input
|
||||||
|
* @param {*} init
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getHttpCachePolyfill = (input, init) => {
|
||||||
|
// 插件
|
||||||
|
if (isExt && !isBg()) {
|
||||||
|
return sendBgMsg(MSG_GET_HTTPCACHE, { input, init });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 油猴/网页/BackgroundPage
|
||||||
|
return getHttpCache(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* putHttpCache 兼容性封装
|
||||||
|
* @param {*} input
|
||||||
|
* @param {*} init
|
||||||
|
* @param {*} data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const putHttpCachePolyfill = (input, init, data) => {
|
||||||
|
// 插件
|
||||||
|
if (isExt && !isBg()) {
|
||||||
|
return sendBgMsg(MSG_PUT_HTTPCACHE, { input, init, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 油猴/网页/BackgroundPage
|
||||||
|
return putHttpCache(input, init, data);
|
||||||
|
};
|
||||||
@@ -1,38 +1,11 @@
|
|||||||
import { isExt, isGm } from "./client";
|
import { isExt, isGm } from "./client";
|
||||||
import { sendBgMsg } from "./msg";
|
import { sendBgMsg } from "./msg";
|
||||||
import { taskPool } from "./pool";
|
|
||||||
import { getSettingWithDefault } from "./storage";
|
import { getSettingWithDefault } from "./storage";
|
||||||
|
import { MSG_FETCH, DEFAULT_HTTP_TIMEOUT } from "../config";
|
||||||
import {
|
|
||||||
MSG_FETCH,
|
|
||||||
MSG_GET_HTTPCACHE,
|
|
||||||
CACHE_NAME,
|
|
||||||
DEFAULT_FETCH_INTERVAL,
|
|
||||||
DEFAULT_FETCH_LIMIT,
|
|
||||||
DEFAULT_HTTP_TIMEOUT,
|
|
||||||
} from "../config";
|
|
||||||
import { isBg } from "./browser";
|
import { isBg } from "./browser";
|
||||||
import { genTransReq } from "../apis/trans";
|
|
||||||
import { kissLog } from "./log";
|
import { kissLog } from "./log";
|
||||||
import { blobToBase64 } from "./utils";
|
import { getFetchPool } from "./pool";
|
||||||
|
import { getHttpCachePolyfill, parseResponse } from "./cache";
|
||||||
/**
|
|
||||||
* 构造缓存 request
|
|
||||||
* @param {*} input
|
|
||||||
* @param {*} init
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const newCacheReq = async (input, init) => {
|
|
||||||
let request = new Request(input, init);
|
|
||||||
if (request.method !== "GET") {
|
|
||||||
const body = await request.text();
|
|
||||||
const cacheUrl = new URL(request.url);
|
|
||||||
cacheUrl.pathname += body;
|
|
||||||
request = new Request(cacheUrl.toString(), { method: "GET" });
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 油猴脚本的请求封装
|
* 油猴脚本的请求封装
|
||||||
@@ -73,56 +46,25 @@ export const fetchGM = async (
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 发起请求
|
* 发起请求
|
||||||
* @param {*} param0
|
* @param {*} input
|
||||||
|
* @param {*} init
|
||||||
|
* @param {*} opts
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const fetchPatcher = async (input, init, transOpts, apiSetting) => {
|
export const fetchPatcher = async (input, init = {}, opts) => {
|
||||||
if (transOpts?.translator) {
|
let timeout = opts?.httpTimeout;
|
||||||
[input, init] = await genTransReq(transOpts, apiSetting);
|
if (!timeout) {
|
||||||
}
|
|
||||||
|
|
||||||
if (!input) {
|
|
||||||
throw new Error("url is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
let timeout = apiSetting?.httpTimeout || DEFAULT_HTTP_TIMEOUT;
|
|
||||||
if (!apiSetting) {
|
|
||||||
try {
|
try {
|
||||||
timeout = (await getSettingWithDefault()).httpTimeout;
|
timeout = (await getSettingWithDefault()).httpTimeout;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
//
|
kissLog(err, "getSettingWithDefault");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!timeout) {
|
||||||
|
timeout = DEFAULT_HTTP_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
if (isGm) {
|
if (isGm) {
|
||||||
// let info;
|
|
||||||
// if (window.KISS_GM) {
|
|
||||||
// info = await window.KISS_GM.getInfo();
|
|
||||||
// } else {
|
|
||||||
// info = GM.info;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Tampermonkey --> .connects
|
|
||||||
// Violentmonkey --> .connect
|
|
||||||
// const connects = info?.script?.connects || info?.script?.connect || [];
|
|
||||||
// const url = new URL(input);
|
|
||||||
// const isSafe = connects.find((item) => url.hostname.endsWith(item));
|
|
||||||
|
|
||||||
// if (isSafe) {
|
|
||||||
// // todo: 自定义接口 init 可能包含了 signal
|
|
||||||
// Object.assign(init, { timeout });
|
|
||||||
|
|
||||||
// const { body, headers, status, statusText } = window.KISS_GM
|
|
||||||
// ? await window.KISS_GM.fetch(input, init)
|
|
||||||
// : await fetchGM(input, init);
|
|
||||||
|
|
||||||
// return new Response(body, {
|
|
||||||
// headers: new Headers(headers),
|
|
||||||
// status,
|
|
||||||
// statusText,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// todo: 自定义接口 init 可能包含了 signal
|
// todo: 自定义接口 init 可能包含了 signal
|
||||||
Object.assign(init, { timeout });
|
Object.assign(init, { timeout });
|
||||||
|
|
||||||
@@ -144,92 +86,13 @@ export const fetchPatcher = async (input, init, transOpts, apiSetting) => {
|
|||||||
return fetch(input, init);
|
return fetch(input, init);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析 response
|
|
||||||
* @param {*} res
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const parseResponse = async (res) => {
|
|
||||||
if (!res) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const contentType = res.headers.get("Content-Type");
|
|
||||||
if (contentType?.includes("json")) {
|
|
||||||
return await res.json();
|
|
||||||
} else if (contentType?.includes("audio")) {
|
|
||||||
const blob = await res.blob();
|
|
||||||
return await blobToBase64(blob);
|
|
||||||
}
|
|
||||||
return await res.text();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询 caches
|
|
||||||
* @param {*} input
|
|
||||||
* @param {*} param1
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getHttpCache = async (input, { method, headers, body }) => {
|
|
||||||
try {
|
|
||||||
const req = await newCacheReq(input, { method, headers, body });
|
|
||||||
const cache = await caches.open(CACHE_NAME);
|
|
||||||
const res = await cache.match(req);
|
|
||||||
return parseResponse(res);
|
|
||||||
} catch (err) {
|
|
||||||
kissLog(err, "get cache");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插入 caches
|
|
||||||
* @param {*} input
|
|
||||||
* @param {*} param1
|
|
||||||
* @param {*} res
|
|
||||||
*/
|
|
||||||
export const putHttpCache = async (input, { method, headers, body }, res) => {
|
|
||||||
try {
|
|
||||||
const req = await newCacheReq(input, { method, headers, body });
|
|
||||||
const cache = await caches.open(CACHE_NAME);
|
|
||||||
await cache.put(req, res);
|
|
||||||
} catch (err) {
|
|
||||||
kissLog(err, "put cache");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理请求
|
* 处理请求
|
||||||
* @param {*} param0
|
* @param {*} param0
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const fetchHandle = async ({
|
export const fetchHandle = async ({ input, init, opts }) => {
|
||||||
input,
|
const res = await fetchPatcher(input, init, opts);
|
||||||
useCache,
|
|
||||||
transOpts,
|
|
||||||
apiSetting,
|
|
||||||
...init
|
|
||||||
}) => {
|
|
||||||
// 发送请求
|
|
||||||
const res = await fetchPatcher(input, init, transOpts, apiSetting);
|
|
||||||
if (!res) {
|
|
||||||
throw new Error("Unknow error");
|
|
||||||
} else if (!res.ok) {
|
|
||||||
const msg = {
|
|
||||||
url: res.url,
|
|
||||||
status: res.status,
|
|
||||||
};
|
|
||||||
if (res.headers.get("Content-Type")?.includes("json")) {
|
|
||||||
msg.response = await res.json();
|
|
||||||
}
|
|
||||||
throw new Error(JSON.stringify(msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插入缓存
|
|
||||||
if (useCache) {
|
|
||||||
await putHttpCache(input, init, res.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseResponse(res);
|
return parseResponse(res);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -238,7 +101,7 @@ export const fetchHandle = async ({
|
|||||||
* @param {*} args
|
* @param {*} args
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const fetchPolyfill = (args) => {
|
const fetchPolyfill = (args) => {
|
||||||
// 插件
|
// 插件
|
||||||
if (isExt && !isBg()) {
|
if (isExt && !isBg()) {
|
||||||
return sendBgMsg(MSG_FETCH, args);
|
return sendBgMsg(MSG_FETCH, args);
|
||||||
@@ -248,72 +111,36 @@ export const fetchPolyfill = (args) => {
|
|||||||
return fetchHandle(args);
|
return fetchHandle(args);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* getHttpCache 兼容性封装
|
|
||||||
* @param {*} input
|
|
||||||
* @param {*} init
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getHttpCachePolyfill = (input, init) => {
|
|
||||||
// 插件
|
|
||||||
if (isExt && !isBg()) {
|
|
||||||
return sendBgMsg(MSG_GET_HTTPCACHE, { input, init });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 油猴/网页/BackgroundPage
|
|
||||||
return getHttpCache(input, init);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求池实例
|
|
||||||
*/
|
|
||||||
export const fetchPool = taskPool(
|
|
||||||
fetchPolyfill,
|
|
||||||
null,
|
|
||||||
DEFAULT_FETCH_INTERVAL,
|
|
||||||
DEFAULT_FETCH_LIMIT
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据请求
|
* 数据请求
|
||||||
* @param {*} input
|
* @param {*} input
|
||||||
|
* @param {*} init
|
||||||
* @param {*} param1
|
* @param {*} param1
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const fetchData = async (input, { useCache, usePool, ...args } = {}) => {
|
export const fetchData = async (
|
||||||
|
input,
|
||||||
|
init,
|
||||||
|
{ useCache, usePool, fetchInterval, fetchLimit, ...opts } = {}
|
||||||
|
) => {
|
||||||
if (!input?.trim()) {
|
if (!input?.trim()) {
|
||||||
throw new Error("URL is empty");
|
throw new Error("URL is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询缓存
|
// 使用缓存数据
|
||||||
if (useCache) {
|
if (useCache) {
|
||||||
const cache = await getHttpCachePolyfill(input, args);
|
const resCache = await getHttpCachePolyfill(input, init);
|
||||||
if (cache) {
|
if (resCache) {
|
||||||
return cache;
|
return resCache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过任务池发送请求
|
// 通过任务池发送请求
|
||||||
if (usePool) {
|
if (usePool) {
|
||||||
return fetchPool.push({ input, useCache, ...args });
|
const fetchPool = getFetchPool(fetchInterval, fetchLimit);
|
||||||
|
return fetchPool.push(fetchPolyfill, { input, init, opts });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接请求
|
// 直接请求
|
||||||
return fetchPolyfill({ input, useCache, ...args });
|
return fetchPolyfill({ input, init, opts });
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新 fetch pool 参数
|
|
||||||
* @param {*} interval
|
|
||||||
* @param {*} limit
|
|
||||||
*/
|
|
||||||
export const updateFetchPool = (interval, limit) => {
|
|
||||||
fetchPool.update(interval, limit);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空任务池
|
|
||||||
*/
|
|
||||||
export const clearFetchPool = () => {
|
|
||||||
fetchPool.clear();
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { DEFAULT_FETCH_INTERVAL, DEFAULT_FETCH_LIMIT } from "../config";
|
||||||
import { kissLog } from "./log";
|
import { kissLog } from "./log";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -8,13 +9,7 @@ import { kissLog } from "./log";
|
|||||||
* @param {*} _limit
|
* @param {*} _limit
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const taskPool = (
|
const taskPool = (_interval = 100, _limit = 100, _retryInteral = 1000) => {
|
||||||
fn,
|
|
||||||
preFn,
|
|
||||||
_interval = 100,
|
|
||||||
_limit = 100,
|
|
||||||
_retryInteral = 1000
|
|
||||||
) => {
|
|
||||||
const pool = [];
|
const pool = [];
|
||||||
const maxRetry = 2; // 最大重试次数
|
const maxRetry = 2; // 最大重试次数
|
||||||
let maxCount = _limit; // 最大数量
|
let maxCount = _limit; // 最大数量
|
||||||
@@ -31,10 +26,9 @@ export const taskPool = (
|
|||||||
const item = pool.shift();
|
const item = pool.shift();
|
||||||
if (item) {
|
if (item) {
|
||||||
curCount++;
|
curCount++;
|
||||||
const { args, resolve, reject, retry } = item;
|
const { fn, args, resolve, reject, retry } = item;
|
||||||
try {
|
try {
|
||||||
const preArgs = preFn ? await preFn(item.args) : {};
|
const res = await fn(args);
|
||||||
const res = await fn({ ...args, ...preArgs });
|
|
||||||
resolve(res);
|
resolve(res);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
kissLog(err, "task");
|
kissLog(err, "task");
|
||||||
@@ -54,12 +48,12 @@ export const taskPool = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
push: async (args) => {
|
push: async (fn, args) => {
|
||||||
if (!timer) {
|
if (!timer) {
|
||||||
run();
|
run();
|
||||||
}
|
}
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
pool.push({ args, resolve, reject, retry: 0 });
|
pool.push({ fn, args, resolve, reject, retry: 0 });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
update: (_interval = 100, _limit = 100) => {
|
update: (_interval = 100, _limit = 100) => {
|
||||||
@@ -78,3 +72,40 @@ export const taskPool = (
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求池实例
|
||||||
|
*/
|
||||||
|
let fetchPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求池实例
|
||||||
|
*/
|
||||||
|
export const getFetchPool = (interval, limit) => {
|
||||||
|
if (!fetchPool) {
|
||||||
|
fetchPool = taskPool(
|
||||||
|
interval ?? DEFAULT_FETCH_INTERVAL,
|
||||||
|
limit ?? DEFAULT_FETCH_LIMIT
|
||||||
|
);
|
||||||
|
} else if (interval && limit) {
|
||||||
|
updateFetchPool(interval, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetchPool;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新请求池参数
|
||||||
|
* @param {*} interval
|
||||||
|
* @param {*} limit
|
||||||
|
*/
|
||||||
|
export const updateFetchPool = (interval, limit) => {
|
||||||
|
fetchPool && fetchPool.update(interval, limit);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空请求池
|
||||||
|
*/
|
||||||
|
export const clearFetchPool = () => {
|
||||||
|
fetchPool && fetchPool.clear();
|
||||||
|
};
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ import {
|
|||||||
OPT_TIMING_PAGEOPEN,
|
OPT_TIMING_PAGEOPEN,
|
||||||
OPT_TIMING_MOUSEOVER,
|
OPT_TIMING_MOUSEOVER,
|
||||||
DEFAULT_TRANS_APIS,
|
DEFAULT_TRANS_APIS,
|
||||||
DEFAULT_FETCH_LIMIT,
|
|
||||||
DEFAULT_FETCH_INTERVAL,
|
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import Content from "../views/Content";
|
import Content from "../views/Content";
|
||||||
import { updateFetchPool, clearFetchPool } from "./fetch";
|
import { clearFetchPool } from "./pool";
|
||||||
import { debounce, genEventName, getHtmlText } from "./utils";
|
import { debounce, genEventName, getHtmlText } from "./utils";
|
||||||
import { runFixer } from "./webfix";
|
import { runFixer } from "./webfix";
|
||||||
import { apiTranslate } from "../apis";
|
import { apiTranslate } from "../apis";
|
||||||
@@ -107,18 +105,6 @@ export class Translator {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
_updatePool(translator) {
|
|
||||||
if (!translator) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
fetchInterval = DEFAULT_FETCH_INTERVAL,
|
|
||||||
fetchLimit = DEFAULT_FETCH_LIMIT,
|
|
||||||
} = this._setting.transApis[translator] || {};
|
|
||||||
updateFetchPool(fetchInterval, fetchLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(rule, setting) {
|
constructor(rule, setting) {
|
||||||
this._overrideAttachShadow();
|
this._overrideAttachShadow();
|
||||||
|
|
||||||
@@ -131,8 +117,6 @@ export class Translator {
|
|||||||
.map((item) => item.split(",").map((item) => item.trim()))
|
.map((item) => item.split(",").map((item) => item.trim()))
|
||||||
.filter(([term]) => Boolean(term));
|
.filter(([term]) => Boolean(term));
|
||||||
|
|
||||||
this._updatePool(rule.translator);
|
|
||||||
|
|
||||||
if (rule.transOpen === "true") {
|
if (rule.transOpen === "true") {
|
||||||
this._register();
|
this._register();
|
||||||
}
|
}
|
||||||
@@ -169,7 +153,6 @@ export class Translator {
|
|||||||
|
|
||||||
updateRule = (obj) => {
|
updateRule = (obj) => {
|
||||||
this.rule = { ...this.rule, ...obj };
|
this.rule = { ...this.rule, ...obj };
|
||||||
this._updatePool(obj.translator);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
toggle = () => {
|
toggle = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user