mirror of
https://github.com/SukkaW/Surge.git
synced 2026-03-15 07:26:42 +08:00
Experimental: LAN Cache Support (WIP)
Some checks failed
Build / Build (push) Has been cancelled
Build / Diff output (push) Has been cancelled
Build / Deploy to Cloudflare Pages (3.114.12) (push) Has been cancelled
Build / Deploy to GitHub and GitLab (push) Has been cancelled
Build / Remove Artifacts after Deployment (push) Has been cancelled
Some checks failed
Build / Build (push) Has been cancelled
Build / Diff output (push) Has been cancelled
Build / Deploy to Cloudflare Pages (3.114.12) (push) Has been cancelled
Build / Deploy to GitHub and GitLab (push) Has been cancelled
Build / Remove Artifacts after Deployment (push) Has been cancelled
This commit is contained in:
@@ -3,9 +3,10 @@ import path from 'node:path';
|
|||||||
import { DOMESTICS, DOH_BOOTSTRAP, AdGuardHomeDNSMapping } from '../Source/non_ip/domestic';
|
import { DOMESTICS, DOH_BOOTSTRAP, AdGuardHomeDNSMapping } from '../Source/non_ip/domestic';
|
||||||
import { DIRECTS, HOSTS, LAN } from '../Source/non_ip/direct';
|
import { DIRECTS, HOSTS, LAN } from '../Source/non_ip/direct';
|
||||||
import type { DNSMapping } from '../Source/non_ip/direct';
|
import type { DNSMapping } from '../Source/non_ip/direct';
|
||||||
import { readFileIntoProcessedArray } from './lib/fetch-text-by-line';
|
import { fetchRemoteTextByLine, readFileIntoProcessedArray } from './lib/fetch-text-by-line';
|
||||||
import { compareAndWriteFile } from './lib/create-file';
|
import { compareAndWriteFile } from './lib/create-file';
|
||||||
import { task } from './trace';
|
import { task } from './trace';
|
||||||
|
import type { Span } from './trace';
|
||||||
import { SHARED_DESCRIPTION } from './constants/description';
|
import { SHARED_DESCRIPTION } from './constants/description';
|
||||||
import { once } from 'foxts/once';
|
import { once } from 'foxts/once';
|
||||||
import * as yaml from 'yaml';
|
import * as yaml from 'yaml';
|
||||||
@@ -13,6 +14,7 @@ import { appendArrayInPlace } from 'foxts/append-array-in-place';
|
|||||||
import { OUTPUT_INTERNAL_DIR, OUTPUT_MODULES_DIR, OUTPUT_MODULES_RULES_DIR, SOURCE_DIR } from './constants/dir';
|
import { OUTPUT_INTERNAL_DIR, OUTPUT_MODULES_DIR, OUTPUT_MODULES_RULES_DIR, SOURCE_DIR } from './constants/dir';
|
||||||
import { MihomoNameserverPolicyOutput, RulesetOutput } from './lib/rules/ruleset';
|
import { MihomoNameserverPolicyOutput, RulesetOutput } from './lib/rules/ruleset';
|
||||||
import { SurgeOnlyRulesetOutput } from './lib/rules/ruleset';
|
import { SurgeOnlyRulesetOutput } from './lib/rules/ruleset';
|
||||||
|
import { $$fetch } from './lib/fetch-retry';
|
||||||
|
|
||||||
export function createGetDnsMappingRule(allowWildcard: boolean) {
|
export function createGetDnsMappingRule(allowWildcard: boolean) {
|
||||||
const hasWildcard = (domain: string) => {
|
const hasWildcard = (domain: string) => {
|
||||||
@@ -112,6 +114,7 @@ export const buildDomesticRuleset = task(require.main === module, __filename)(as
|
|||||||
.addFromRuleset(lans)
|
.addFromRuleset(lans)
|
||||||
.write(),
|
.write(),
|
||||||
|
|
||||||
|
buildLANCacheRuleset(span),
|
||||||
...dataset.map(([name, { ruleset, domains }]) => {
|
...dataset.map(([name, { ruleset, domains }]) => {
|
||||||
if (!ruleset) {
|
if (!ruleset) {
|
||||||
return;
|
return;
|
||||||
@@ -340,3 +343,84 @@ export const buildDomesticRuleset = task(require.main === module, __filename)(as
|
|||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function buildLANCacheRuleset(span: Span) {
|
||||||
|
const childSpan = span.traceChild('build LAN cache ruleset');
|
||||||
|
|
||||||
|
const cacheDomainsData = await childSpan.traceChildAsync('fetch cache_domains.json', async () => (await $$fetch('https://cdn.jsdelivr.net/gh/uklans/cache-domains@master/cache_domains.json')).json());
|
||||||
|
if (!cacheDomainsData || typeof cacheDomainsData !== 'object' || !('cache_domains' in cacheDomainsData) || !Array.isArray(cacheDomainsData.cache_domains)) {
|
||||||
|
throw new TypeError('Invalid cache domains data');
|
||||||
|
}
|
||||||
|
const allDomainFiles = cacheDomainsData.cache_domains.reduce<string[]>((acc, { domain_files }) => {
|
||||||
|
if (Array.isArray(domain_files)) {
|
||||||
|
appendArrayInPlace(acc, domain_files);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const allDomains = (
|
||||||
|
await Promise.all(
|
||||||
|
allDomainFiles.map(
|
||||||
|
async (file) => childSpan.traceChildAsync(
|
||||||
|
'download ' + file,
|
||||||
|
async () => Array.fromAsync(await fetchRemoteTextByLine('https://cdn.jsdelivr.net/gh/uklans/cache-domains@master/' + file, true))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).flat();
|
||||||
|
|
||||||
|
const surgeOutput = new SurgeOnlyRulesetOutput(
|
||||||
|
span,
|
||||||
|
'lancache',
|
||||||
|
'sukka_local_dns_mapping',
|
||||||
|
OUTPUT_MODULES_RULES_DIR
|
||||||
|
)
|
||||||
|
.withTitle('Sukka\'s Ruleset - Local DNS Mapping (lancache)')
|
||||||
|
.appendDescription(
|
||||||
|
SHARED_DESCRIPTION,
|
||||||
|
'',
|
||||||
|
'This is an internal rule that is only referenced by sukka_local_dns_mapping.sgmodule',
|
||||||
|
'Do not use this file in your Rule section.'
|
||||||
|
);
|
||||||
|
|
||||||
|
const mihomoOutput = new MihomoNameserverPolicyOutput(
|
||||||
|
span,
|
||||||
|
'lancache',
|
||||||
|
'mihomo_nameserver_policy',
|
||||||
|
OUTPUT_INTERNAL_DIR
|
||||||
|
)
|
||||||
|
.withTitle('Sukka\'s Ruleset - Local DNS Mapping for Mihomo NameServer Policy (lancache)')
|
||||||
|
.appendDescription(
|
||||||
|
SHARED_DESCRIPTION,
|
||||||
|
'',
|
||||||
|
'This ruleset is only used for mihomo\'s nameserver-policy feature, which',
|
||||||
|
'is similar to the RULE-SET referenced by sukka_local_dns_mapping.sgmodule.',
|
||||||
|
'Do not use this file in your Rule section.'
|
||||||
|
);
|
||||||
|
|
||||||
|
for (let i = 0, len = allDomains.length; i < len; i++) {
|
||||||
|
const domain = allDomains[i];
|
||||||
|
|
||||||
|
if (domain.includes('*')) {
|
||||||
|
// If only *. prefix is used, we can convert it to DOMAIN-SUFFIX
|
||||||
|
if (domain.startsWith('*.') && !domain.slice(2).includes('*')) {
|
||||||
|
const domainSuffix = domain.slice(2);
|
||||||
|
surgeOutput.addDomainSuffix(domainSuffix);
|
||||||
|
mihomoOutput.addDomainSuffix(domainSuffix);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
surgeOutput.addDomainWildcard(domain);
|
||||||
|
mihomoOutput.addDomainWildcard(domain);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
surgeOutput.addDomain(domain);
|
||||||
|
mihomoOutput.addDomain(domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
surgeOutput.write(),
|
||||||
|
mihomoOutput.write()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|||||||
@@ -147,9 +147,14 @@ export class FileOutput {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bulkAddDomainWildcard(domains: string[]) {
|
addDomainWildcard(wildcard: string) {
|
||||||
for (let i = 0, len = domains.length; i < len; i++) {
|
this.wildcardSet.add(wildcard);
|
||||||
this.wildcardSet.add(domains[i]);
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bulkAddDomainWildcard(wildcards: string[]) {
|
||||||
|
for (let i = 0, len = wildcards.length; i < len; i++) {
|
||||||
|
this.wildcardSet.add(wildcards[i]);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user