From a91f9780427adcadfe6da16ffac782a3c353d995 Mon Sep 17 00:00:00 2001 From: xream Date: Tue, 30 Jan 2024 14:14:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BF=9C=E7=A8=8B=E8=AE=A2=E9=98=85=20?= =?UTF-8?q?URL=20=E6=96=B0=E5=A2=9E=E5=8F=82=E6=95=B0=20validCheck=20?= =?UTF-8?q?=E5=B0=86=E6=A3=80=E6=9F=A5=E8=AE=A2=E9=98=85=E6=9C=89=E6=95=88?= =?UTF-8?q?=E6=9C=9F=E5=92=8C=E5=89=A9=E4=BD=99=E6=B5=81=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/package.json | 2 +- .../src/core/proxy-utils/processors/index.js | 2 + backend/src/utils/download.js | 69 +++++++++++-------- backend/src/utils/flow.js | 23 +++++++ 4 files changed, 65 insertions(+), 31 deletions(-) diff --git a/backend/package.json b/backend/package.json index 7749351..45c5615 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "sub-store", - "version": "2.14.194", + "version": "2.14.195", "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.", "main": "src/main.js", "scripts": { diff --git a/backend/src/core/proxy-utils/processors/index.js b/backend/src/core/proxy-utils/processors/index.js index 449b101..ed115b7 100644 --- a/backend/src/core/proxy-utils/processors/index.js +++ b/backend/src/core/proxy-utils/processors/index.js @@ -14,6 +14,7 @@ import { getFlowField, getFlowHeaders, parseFlowHeaders, + validCheck, flowTransfer, } from '@/utils/flow'; @@ -806,6 +807,7 @@ function createDynamicFunction(name, script, $arguments) { getFlowHeaders, parseFlowHeaders, flowTransfer, + validCheck, }; if ($.env.isLoon) { return new Function( diff --git a/backend/src/utils/download.js b/backend/src/utils/download.js index 9b59459..f1f7c80 100644 --- a/backend/src/utils/download.js +++ b/backend/src/utils/download.js @@ -4,7 +4,12 @@ import { HTTP, ENV } from '@/vendor/open-api'; import { hex_md5 } from '@/vendor/md5'; import resourceCache from '@/utils/resource-cache'; import headersResourceCache from '@/utils/headers-resource-cache'; -import { getFlowField } from '@/utils/flow'; +import { + getFlowField, + getFlowHeaders, + parseFlowHeaders, + validCheck, +} from '@/utils/flow'; import $ from '@/core/app'; const tasks = new Map(); @@ -64,36 +69,40 @@ export default async function download(rawUrl, ua, timeout) { timeout: requestTimeout, }); - const result = new Promise((resolve, reject) => { - // try to find in app cache - const cached = resourceCache.get(id); - if (!$arguments?.noCache && cached) { - resolve(cached); - } else { - $.info( - `Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nURL: ${url}`, - ); - http.get(url) - .then((resp) => { - const { body, headers } = resp; - if (headers) { - const flowInfo = getFlowField(headers); - if (flowInfo) { - headersResourceCache.set(url, flowInfo); - } - } - if (body.replace(/\s/g, '').length === 0) - reject(new Error('远程资源内容为空!')); - else { - resourceCache.set(id, body); - resolve(body); - } - }) - .catch(() => { - reject(new Error(`无法下载 URL:${url}`)); - }); + let result; + + // try to find in app cache + const cached = resourceCache.get(id); + if (!$arguments?.noCache && cached) { + result = cached; + } else { + $.info( + `Downloading...\nUser-Agent: ${userAgent}\nTimeout: ${requestTimeout}\nURL: ${url}`, + ); + try { + const { body, headers } = await http.get(url); + + if (headers) { + const flowInfo = getFlowField(headers); + if (flowInfo) { + headersResourceCache.set(url, flowInfo); + } + } + if (body.replace(/\s/g, '').length === 0) + throw new Error(new Error('远程资源内容为空')); + + resourceCache.set(id, body); + result = body; + } catch (e) { + throw new Error(`无法下载 URL ${url}: ${e.message ?? e}`); } - }); + } + + // 检查订阅有效性 + + if ($arguments?.validCheck) { + await validCheck(parseFlowHeaders(await getFlowHeaders(url))); + } if (!isNode) { tasks.set(id, result); diff --git a/backend/src/utils/flow.js b/backend/src/utils/flow.js index 6414a38..8c8116a 100644 --- a/backend/src/utils/flow.js +++ b/backend/src/utils/flow.js @@ -120,3 +120,26 @@ export function flowTransfer(flow, unit = 'B') { ? { value: flow.toFixed(1), unit: unit } : flowTransfer(flow / 1024, unitList[++unitIndex]); } + +export function validCheck(flow) { + if (!flow) { + throw new Error('没有流量信息'); + } + if (flow?.expires && flow.expires * 1000 < Date.now()) { + const date = new Date(flow.expires * 1000).toLocaleDateString(); + throw new Error(`订阅已过期: ${date}`); + } + if (flow?.total) { + const upload = flow.usage?.upload || 0; + const download = flow.usage?.download || 0; + if (flow.total - upload - download < 0) { + const current = upload + download; + const currT = flowTransfer(Math.abs(current)); + currT.value = current < 0 ? '-' + currT.value : currT.value; + const totalT = flowTransfer(flow.total); + throw new Error( + `流量已用完: ${currT.value} ${currT.unit} / ${totalT.value} ${totalT.unit}`, + ); + } + } +}