2023-08-30 18:05:37 +08:00
|
|
|
import { isExt, isGm } from "./client";
|
2023-08-31 13:38:06 +08:00
|
|
|
import { sendBgMsg } from "./msg";
|
2023-08-10 11:55:40 +08:00
|
|
|
import { taskPool } from "./pool";
|
2023-07-20 13:45:41 +08:00
|
|
|
import {
|
|
|
|
|
MSG_FETCH,
|
2023-08-10 11:55:40 +08:00
|
|
|
MSG_FETCH_LIMIT,
|
2023-08-11 16:48:09 +08:00
|
|
|
MSG_FETCH_CLEAR,
|
2023-07-20 13:45:41 +08:00
|
|
|
CACHE_NAME,
|
2023-08-10 11:55:40 +08:00
|
|
|
DEFAULT_FETCH_INTERVAL,
|
|
|
|
|
DEFAULT_FETCH_LIMIT,
|
2023-07-20 13:45:41 +08:00
|
|
|
} from "../config";
|
2023-09-20 17:47:23 +08:00
|
|
|
import { isBg } from "./browser";
|
2023-10-21 11:54:04 +08:00
|
|
|
import { newCacheReq, newTransReq } from "./req";
|
2023-07-20 13:45:41 +08:00
|
|
|
|
2024-03-19 14:25:37 +08:00
|
|
|
const TIMEOUT = 8000;
|
|
|
|
|
|
2023-07-20 13:45:41 +08:00
|
|
|
/**
|
2023-08-05 18:15:01 +08:00
|
|
|
* 油猴脚本的请求封装
|
|
|
|
|
* @param {*} input
|
|
|
|
|
* @param {*} init
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2023-08-29 00:06:50 +08:00
|
|
|
export const fetchGM = async (input, { method = "GET", headers, body } = {}) =>
|
2023-08-05 18:15:01 +08:00
|
|
|
new Promise((resolve, reject) => {
|
2023-08-16 11:38:53 +08:00
|
|
|
GM.xmlHttpRequest({
|
|
|
|
|
method,
|
|
|
|
|
url: input,
|
|
|
|
|
headers,
|
|
|
|
|
data: body,
|
2023-10-21 11:54:04 +08:00
|
|
|
// withCredentials: true,
|
2024-03-19 14:25:37 +08:00
|
|
|
timeout: TIMEOUT,
|
2023-10-21 11:54:04 +08:00
|
|
|
onload: ({ response, responseHeaders, status, statusText, ...opts }) => {
|
|
|
|
|
const headers = {};
|
2023-09-28 16:18:28 +08:00
|
|
|
responseHeaders.split("\n").forEach((line) => {
|
|
|
|
|
const [name, value] = line.split(":").map((item) => item.trim());
|
|
|
|
|
if (name && value) {
|
2023-10-21 11:54:04 +08:00
|
|
|
headers[name] = value;
|
2023-09-28 16:18:28 +08:00
|
|
|
}
|
|
|
|
|
});
|
2023-10-21 11:54:04 +08:00
|
|
|
resolve({
|
|
|
|
|
body: response,
|
|
|
|
|
headers,
|
|
|
|
|
status,
|
|
|
|
|
statusText,
|
|
|
|
|
});
|
2023-08-16 11:38:53 +08:00
|
|
|
},
|
|
|
|
|
onerror: reject,
|
|
|
|
|
});
|
2023-08-05 18:15:01 +08:00
|
|
|
});
|
|
|
|
|
|
2023-08-04 17:56:47 +08:00
|
|
|
/**
|
2023-08-10 11:55:40 +08:00
|
|
|
* 发起请求
|
|
|
|
|
* @param {*} param0
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2023-10-21 11:54:04 +08:00
|
|
|
export const fetchApi = async ({ input, init, transOpts, apiSetting }) => {
|
2023-10-20 17:44:48 +08:00
|
|
|
if (transOpts?.translator) {
|
2023-10-21 11:54:04 +08:00
|
|
|
[input, init] = await newTransReq(transOpts, apiSetting);
|
2023-08-10 11:55:40 +08:00
|
|
|
}
|
|
|
|
|
|
2023-11-06 15:42:21 +08:00
|
|
|
if (!input) {
|
|
|
|
|
throw new Error("url is empty");
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-21 23:46:42 +08:00
|
|
|
if (isGm) {
|
2023-08-29 00:06:50 +08:00
|
|
|
let info;
|
|
|
|
|
if (window.KISS_GM) {
|
|
|
|
|
info = await window.KISS_GM.getInfo();
|
|
|
|
|
} else {
|
|
|
|
|
info = GM.info;
|
|
|
|
|
}
|
2023-10-21 11:54:04 +08:00
|
|
|
|
2023-09-03 21:45:06 +08:00
|
|
|
// Tampermonkey --> .connects
|
|
|
|
|
// Violentmonkey --> .connect
|
|
|
|
|
const connects = info?.script?.connects || info?.script?.connect || [];
|
2023-08-21 23:46:42 +08:00
|
|
|
const url = new URL(input);
|
|
|
|
|
const isSafe = connects.find((item) => url.hostname.endsWith(item));
|
2023-10-21 11:54:04 +08:00
|
|
|
|
2023-08-21 23:46:42 +08:00
|
|
|
if (isSafe) {
|
2023-10-21 11:54:04 +08:00
|
|
|
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,
|
|
|
|
|
});
|
2023-08-21 23:46:42 +08:00
|
|
|
}
|
2023-08-10 11:55:40 +08:00
|
|
|
}
|
2023-10-21 11:54:04 +08:00
|
|
|
|
2024-03-19 14:25:37 +08:00
|
|
|
if (AbortSignal?.timeout) {
|
|
|
|
|
Object.assign(init, { signal: AbortSignal.timeout(TIMEOUT) });
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-10 11:55:40 +08:00
|
|
|
return fetch(input, init);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 请求池实例
|
|
|
|
|
*/
|
|
|
|
|
export const fetchPool = taskPool(
|
|
|
|
|
fetchApi,
|
2023-10-21 11:54:04 +08:00
|
|
|
null,
|
2023-08-10 11:55:40 +08:00
|
|
|
DEFAULT_FETCH_INTERVAL,
|
|
|
|
|
DEFAULT_FETCH_LIMIT
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 请求数据统一接口
|
2023-08-04 17:56:47 +08:00
|
|
|
* @param {*} input
|
|
|
|
|
* @param {*} opts
|
2023-07-20 13:45:41 +08:00
|
|
|
* @returns
|
|
|
|
|
*/
|
2023-08-09 10:33:00 +08:00
|
|
|
export const fetchData = async (
|
|
|
|
|
input,
|
2023-10-20 17:44:48 +08:00
|
|
|
{ useCache, usePool, transOpts, apiSetting, ...init } = {}
|
2023-08-09 10:33:00 +08:00
|
|
|
) => {
|
2023-10-20 17:44:48 +08:00
|
|
|
const cacheReq = await newCacheReq(input, init);
|
2023-07-20 13:45:41 +08:00
|
|
|
let res;
|
|
|
|
|
|
|
|
|
|
// 查询缓存
|
|
|
|
|
if (useCache) {
|
|
|
|
|
try {
|
2023-08-29 21:24:25 +08:00
|
|
|
const cache = await caches.open(CACHE_NAME);
|
2023-07-20 13:45:41 +08:00
|
|
|
res = await cache.match(cacheReq);
|
|
|
|
|
} catch (err) {
|
2023-08-29 21:33:27 +08:00
|
|
|
console.log("[cache match]", err.message);
|
2023-07-20 13:45:41 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!res) {
|
2023-08-10 11:55:40 +08:00
|
|
|
// 发送请求
|
|
|
|
|
if (usePool) {
|
2023-10-20 17:44:48 +08:00
|
|
|
res = await fetchPool.push({ input, init, transOpts, apiSetting });
|
2023-08-05 18:15:01 +08:00
|
|
|
} else {
|
2023-10-20 17:44:48 +08:00
|
|
|
res = await fetchApi({ input, init, transOpts, apiSetting });
|
2023-08-05 18:15:01 +08:00
|
|
|
}
|
2023-07-20 13:45:41 +08:00
|
|
|
|
2023-08-10 11:55:40 +08:00
|
|
|
if (!res?.ok) {
|
2023-11-02 23:35:36 +08:00
|
|
|
const cause = {
|
|
|
|
|
status: res.status,
|
|
|
|
|
};
|
|
|
|
|
if (res.headers.get("Content-Type")?.includes("json")) {
|
|
|
|
|
cause.body = await res.json();
|
|
|
|
|
}
|
|
|
|
|
throw new Error(`response: [${res.status}] ${res.statusText}`, { cause });
|
2023-08-10 11:55:40 +08:00
|
|
|
}
|
2023-07-20 13:45:41 +08:00
|
|
|
|
2023-08-10 11:55:40 +08:00
|
|
|
// 插入缓存
|
|
|
|
|
if (useCache) {
|
|
|
|
|
try {
|
2023-08-29 21:24:25 +08:00
|
|
|
const cache = await caches.open(CACHE_NAME);
|
2023-08-10 11:55:40 +08:00
|
|
|
await cache.put(cacheReq, res.clone());
|
|
|
|
|
} catch (err) {
|
2023-08-29 21:33:27 +08:00
|
|
|
console.log("[cache put]", err.message);
|
2023-08-10 11:55:40 +08:00
|
|
|
}
|
2023-07-20 13:45:41 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const contentType = res.headers.get("Content-Type");
|
|
|
|
|
if (contentType?.includes("json")) {
|
|
|
|
|
return await res.json();
|
|
|
|
|
}
|
|
|
|
|
return await res.text();
|
|
|
|
|
};
|
2023-08-05 18:15:01 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* fetch 兼容性封装
|
|
|
|
|
* @param {*} input
|
|
|
|
|
* @param {*} opts
|
|
|
|
|
* @returns
|
|
|
|
|
*/
|
2023-09-20 17:47:23 +08:00
|
|
|
export const fetchPolyfill = async (input, opts) => {
|
2023-10-20 17:44:48 +08:00
|
|
|
if (!input?.trim()) {
|
2023-09-06 14:57:02 +08:00
|
|
|
throw new Error("URL is empty");
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-05 18:15:01 +08:00
|
|
|
// 插件
|
2023-09-20 17:47:23 +08:00
|
|
|
if (isExt && !isBg()) {
|
2023-08-31 13:38:06 +08:00
|
|
|
const res = await sendBgMsg(MSG_FETCH, { input, opts });
|
2023-08-05 18:15:01 +08:00
|
|
|
if (res.error) {
|
2023-11-02 23:35:36 +08:00
|
|
|
throw new Error(res.error, { cause: res.cause });
|
2023-08-05 18:15:01 +08:00
|
|
|
}
|
|
|
|
|
return res.data;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-22 16:27:09 +08:00
|
|
|
// 油猴/网页/BackgroundPage
|
|
|
|
|
return await fetchData(input, opts);
|
2023-08-05 18:15:01 +08:00
|
|
|
};
|
2023-08-10 11:55:40 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 更新 fetch pool 参数
|
|
|
|
|
* @param {*} interval
|
|
|
|
|
* @param {*} limit
|
|
|
|
|
*/
|
2023-08-31 13:38:06 +08:00
|
|
|
export const updateFetchPool = async (interval, limit) => {
|
2023-08-10 11:55:40 +08:00
|
|
|
if (isExt) {
|
2023-08-31 13:38:06 +08:00
|
|
|
const res = await sendBgMsg(MSG_FETCH_LIMIT, { interval, limit });
|
2023-08-10 11:55:40 +08:00
|
|
|
if (res.error) {
|
|
|
|
|
throw new Error(res.error);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
fetchPool.update(interval, limit);
|
|
|
|
|
}
|
|
|
|
|
};
|
2023-08-11 16:48:09 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 清空任务池
|
|
|
|
|
*/
|
2023-08-31 13:38:06 +08:00
|
|
|
export const clearFetchPool = async () => {
|
2023-08-11 16:48:09 +08:00
|
|
|
if (isExt) {
|
2023-08-31 13:38:06 +08:00
|
|
|
const res = await sendBgMsg(MSG_FETCH_CLEAR);
|
2023-08-11 16:48:09 +08:00
|
|
|
if (res.error) {
|
|
|
|
|
throw new Error(res.error);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
fetchPool.clear();
|
|
|
|
|
}
|
|
|
|
|
};
|