Skip to content

Commit 2700c8c

Browse files
committed
feat: 支持单条订阅和组合订阅配置 "不查询订阅流量信息"; 支持订阅链接参数传入 noFlow 强制指定 "不查询订阅流量信息"
1 parent 47ce75a commit 2700c8c

10 files changed

Lines changed: 529 additions & 39 deletions

File tree

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sub-store",
3-
"version": "2.36.27",
3+
"version": "2.36.28",
44
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
55
"main": "src/main.js",
66
"packageManager": "pnpm@11.0.9",

backend/src/core/proxy-utils/index.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ async function processFn(
141141
source,
142142
$options,
143143
raw,
144+
executionContext = {},
144145
) {
145146
let context = {};
146147
if (raw !== undefined) {
@@ -182,7 +183,10 @@ async function processFn(
182183
let script;
183184
let $arguments = {};
184185
if (item.type.indexOf('Script') !== -1) {
185-
({ script, $arguments } = await loadScriptItem(item));
186+
({ script, $arguments } = await loadScriptItem(
187+
item,
188+
executionContext,
189+
));
186190
}
187191

188192
if (!PROXY_PROCESSORS[item.type]) {
@@ -206,7 +210,10 @@ async function processFn(
206210
context,
207211
);
208212
} else {
209-
processor = PROXY_PROCESSORS[item.type](item.args || {});
213+
processor = PROXY_PROCESSORS[item.type](
214+
item.args || {},
215+
executionContext,
216+
);
210217
}
211218
proxies = await ApplyProcessor(processor, proxies);
212219
}
@@ -219,6 +226,7 @@ async function processResponseFn(
219226
targetPlatform,
220227
source,
221228
$options,
229+
executionContext = {},
222230
) {
223231
let context = {};
224232
let output = normalizeResponse(response);
@@ -243,7 +251,10 @@ async function processResponseFn(
243251
continue;
244252
}
245253

246-
const { script, $arguments } = await loadScriptItem(item);
254+
const { script, $arguments } = await loadScriptItem(
255+
item,
256+
executionContext,
257+
);
247258
$.log(
248259
`Applying "${item.type}" with arguments:\n >>> ${
249260
JSON.stringify(item.args, null, 2) || 'None'
@@ -264,7 +275,7 @@ async function processResponseFn(
264275
return output;
265276
}
266277

267-
async function loadScriptItem(item) {
278+
async function loadScriptItem(item, executionContext = {}) {
268279
let script;
269280
let $arguments = {};
270281
const { mode, content } = item.args || {};
@@ -319,6 +330,7 @@ async function loadScriptItem(item) {
319330
script = await produceArtifact({
320331
type: 'file',
321332
name,
333+
noFlow: executionContext.noFlow,
322334
});
323335
}
324336
} catch (err) {
@@ -341,7 +353,17 @@ async function loadScriptItem(item) {
341353
} else {
342354
// if this is a remote script, download it
343355
try {
344-
script = await download(url);
356+
script = await download(
357+
url,
358+
undefined,
359+
undefined,
360+
undefined,
361+
undefined,
362+
undefined,
363+
undefined,
364+
undefined,
365+
{ noFlow: executionContext.noFlow },
366+
);
345367
// $.info(`Script loaded: >>>\n ${script}`);
346368
} catch (err) {
347369
$.error(

backend/src/core/proxy-utils/processors/index.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,15 @@ function getMihomoProfileProxies(config) {
527527
return Array.isArray(config?.proxies) ? config.proxies : [];
528528
}
529529

530-
function AddProxiesFromSubscriptionOperator({
531-
sourceType = 'subscription',
532-
sourceName,
533-
includeUnsupportedProxy,
534-
position = 'replace',
535-
} = {}) {
530+
function AddProxiesFromSubscriptionOperator(
531+
{
532+
sourceType = 'subscription',
533+
sourceName,
534+
includeUnsupportedProxy,
535+
position = 'replace',
536+
} = {},
537+
executionContext = {},
538+
) {
536539
const apply = async (input) => {
537540
if (!isMihomoConfigFile(input?.$file)) return input;
538541

@@ -547,6 +550,7 @@ function AddProxiesFromSubscriptionOperator({
547550
'delete-underscore-fields': true,
548551
'include-unsupported-proxy': includeUnsupportedProxy,
549552
},
553+
noFlow: executionContext.noFlow,
550554
});
551555

552556
switch (position) {

backend/src/restful/download.js

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,9 @@ async function downloadSubscription(req, res) {
291291
if (noCache) {
292292
$.info(`指定不使用缓存: ${noCache}`);
293293
}
294+
if (req.query.noFlow) {
295+
$.info(`指定不查询订阅流量信息: ${req.query.noFlow}`);
296+
}
294297

295298
const allSubs = $.read(SUBS_KEY);
296299
const fakeSub = _fakeNode ? {
@@ -306,6 +309,7 @@ async function downloadSubscription(req, res) {
306309
const sub = (_fakeNode || _fakeSub) ? fakeSub : findByName(allSubs, name);
307310
if (sub) {
308311
try {
312+
const noFlow = req.query.noFlow || sub.noFlow;
309313
const passThroughUA = sub.passThroughUA;
310314
if (passThroughUA) {
311315
$.info(
@@ -335,6 +339,7 @@ async function downloadSubscription(req, res) {
335339
$options,
336340
proxy,
337341
noCache,
342+
noFlow,
338343
};
339344
if (_fakeNode || _fakeSub) {
340345
if(_fakeNode) {
@@ -377,7 +382,11 @@ async function downloadSubscription(req, res) {
377382
}
378383
}
379384
}
380-
if (!$arguments.noFlow && /^https?/.test(url)) {
385+
if (
386+
!noFlow &&
387+
!$arguments.noFlow &&
388+
/^https?/.test(url)
389+
) {
381390
// forward flow headers
382391
flowInfo = await getFlowHeaders(
383392
$arguments?.insecure ? `${url}#insecure` : url,
@@ -414,7 +423,7 @@ async function downloadSubscription(req, res) {
414423
);
415424
}
416425
}
417-
if (sub.subUserinfo) {
426+
if (!noFlow && sub.subUserinfo) {
418427
let subUserInfo;
419428
if (/^https?:\/\//.test(sub.subUserinfo)) {
420429
try {
@@ -499,6 +508,7 @@ async function downloadSubscription(req, res) {
499508
targetPlatform: platform,
500509
source: { [sub.name]: sub },
501510
$options,
511+
executionContext: { noFlow },
502512
});
503513
res.send(
504514
await applyAgeOutputEncryption({
@@ -644,9 +654,13 @@ async function downloadCollection(req, res) {
644654
if (noCache) {
645655
$.info(`指定不使用缓存: ${noCache}`);
646656
}
657+
if (req.query.noFlow) {
658+
$.info(`指定不查询订阅流量信息: ${req.query.noFlow}`);
659+
}
647660

648661
if (collection) {
649662
try {
663+
const noFlow = req.query.noFlow || collection.noFlow;
650664
let output = await produceArtifact({
651665
type: 'collection',
652666
name,
@@ -665,11 +679,12 @@ async function downloadCollection(req, res) {
665679
$options,
666680
proxy,
667681
noCache,
682+
noFlow,
668683
ua: reqUA,
669684
});
670685
let subUserInfoOfSub;
671686
// 默认透传第一个子订阅的流量信息,除非 firstSubFlow 显式设置为 false
672-
if (collection.firstSubFlow !== false) {
687+
if (!noFlow && collection.firstSubFlow !== false) {
673688
// forward flow header from the first subscription in this collection
674689
const allSubs = $.read(SUBS_KEY);
675690
const subnames = collection.subscriptions;
@@ -707,7 +722,11 @@ async function downloadCollection(req, res) {
707722
}
708723
}
709724
}
710-
if (!$arguments.noFlow && /^https?:/.test(url)) {
725+
if (
726+
!sub.noFlow &&
727+
!$arguments.noFlow &&
728+
/^https?:/.test(url)
729+
) {
711730
subUserInfoOfSub = await getFlowHeaders(
712731
$arguments?.insecure
713732
? `${url}#insecure`
@@ -729,7 +748,7 @@ async function downloadCollection(req, res) {
729748
);
730749
}
731750
}
732-
if (sub.subUserinfo) {
751+
if (!sub.noFlow && sub.subUserinfo) {
733752
let subUserInfo;
734753
if (/^https?:\/\//.test(sub.subUserinfo)) {
735754
try {
@@ -764,24 +783,26 @@ async function downloadCollection(req, res) {
764783
}
765784

766785
let subUserInfoOfCol;
767-
if (/^https?:\/\//.test(collection.subUserinfo)) {
768-
try {
769-
subUserInfoOfCol = await getFlowHeaders(
770-
undefined,
771-
undefined,
772-
undefined,
773-
proxy || collection.proxy,
774-
collection.subUserinfo,
775-
);
776-
} catch (e) {
777-
$.error(
778-
`组合订阅 ${name} 使用自定义流量链接 ${
779-
collection.subUserinfo
780-
} 获取流量信息时发生错误: ${JSON.stringify(e)}`,
781-
);
786+
if (!noFlow) {
787+
if (/^https?:\/\//.test(collection.subUserinfo)) {
788+
try {
789+
subUserInfoOfCol = await getFlowHeaders(
790+
undefined,
791+
undefined,
792+
undefined,
793+
proxy || collection.proxy,
794+
collection.subUserinfo,
795+
);
796+
} catch (e) {
797+
$.error(
798+
`组合订阅 ${name} 使用自定义流量链接 ${
799+
collection.subUserinfo
800+
} 获取流量信息时发生错误: ${JSON.stringify(e)}`,
801+
);
802+
}
803+
} else {
804+
subUserInfoOfCol = collection.subUserinfo;
782805
}
783-
} else {
784-
subUserInfoOfCol = collection.subUserinfo;
785806
}
786807
const subUserInfo = [subUserInfoOfCol, subUserInfoOfSub]
787808
.filter((i) => i)
@@ -846,6 +867,7 @@ async function downloadCollection(req, res) {
846867
targetPlatform: platform,
847868
source: { _collection: collection },
848869
$options,
870+
executionContext: { noFlow },
849871
});
850872
res.send(
851873
await applyAgeOutputEncryption({

backend/src/restful/response-transformer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export async function applyResponseTransformers({
3737
targetPlatform,
3838
source,
3939
$options,
40+
executionContext,
4041
}) {
4142
const currentHeaders = getCurrentHeaders(res);
4243
const transformed = await ProxyUtils.processResponse(
@@ -49,6 +50,7 @@ export async function applyResponseTransformers({
4950
targetPlatform,
5051
source,
5152
$options,
53+
executionContext,
5254
);
5355
setHeaders(res, currentHeaders, transformed.header || transformed.headers);
5456
setStatus(res, transformed.status || transformed.statusCode);

backend/src/restful/subscriptions.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ async function getFlowInfo(req, res) {
6565
);
6666
return;
6767
}
68+
if (req.query.noFlow || sub.noFlow) {
69+
failed(
70+
res,
71+
new RequestInvalidError(
72+
'NO_FLOW_INFO',
73+
'N/A',
74+
`Subscription ${name}: noFlow`,
75+
),
76+
400,
77+
);
78+
return;
79+
}
6880
if (
6981
sub.source === 'local' &&
7082
!['localFirst', 'remoteFirst'].includes(sub.mergeSources)

0 commit comments

Comments
 (0)