Skip to content

Commit 511d14e

Browse files
committed
Experimental: LAN Cache Support
1 parent 8dda300 commit 511d14e

2 files changed

Lines changed: 93 additions & 4 deletions

File tree

Build/build-domestic-direct-lan-ruleset-dns-mapping-module.ts

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@ import path from 'node:path';
33
import { DOMESTICS, DOH_BOOTSTRAP, AdGuardHomeDNSMapping } from '../Source/non_ip/domestic';
44
import { DIRECTS, HOSTS, LAN } from '../Source/non_ip/direct';
55
import type { DNSMapping } from '../Source/non_ip/direct';
6-
import { readFileIntoProcessedArray } from './lib/fetch-text-by-line';
6+
import { fetchRemoteTextByLine, readFileIntoProcessedArray } from './lib/fetch-text-by-line';
77
import { compareAndWriteFile } from './lib/create-file';
88
import { task } from './trace';
9+
import type { Span } from './trace';
910
import { SHARED_DESCRIPTION } from './constants/description';
1011
import { once } from 'foxts/once';
1112
import * as yaml from 'yaml';
1213
import { appendArrayInPlace } from 'foxts/append-array-in-place';
1314
import { OUTPUT_INTERNAL_DIR, OUTPUT_MODULES_DIR, OUTPUT_MODULES_RULES_DIR, SOURCE_DIR } from './constants/dir';
1415
import { MihomoNameserverPolicyOutput, RulesetOutput } from './lib/rules/ruleset';
1516
import { SurgeOnlyRulesetOutput } from './lib/rules/ruleset';
17+
import { $$fetch } from './lib/fetch-retry';
1618

1719
export function createGetDnsMappingRule(allowWildcard: boolean) {
1820
const hasWildcard = (domain: string) => {
@@ -112,6 +114,7 @@ export const buildDomesticRuleset = task(require.main === module, __filename)(as
112114
.addFromRuleset(lans)
113115
.write(),
114116

117+
buildLANCacheRuleset(span),
115118
...dataset.map(([name, { ruleset, domains }]) => {
116119
if (!ruleset) {
117120
return;
@@ -340,3 +343,84 @@ export const buildDomesticRuleset = task(require.main === module, __filename)(as
340343
)
341344
]);
342345
});
346+
347+
async function buildLANCacheRuleset(span: Span) {
348+
const childSpan = span.traceChild('build LAN cache ruleset');
349+
350+
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());
351+
if (!cacheDomainsData || typeof cacheDomainsData !== 'object' || !('cache_domains' in cacheDomainsData) || !Array.isArray(cacheDomainsData.cache_domains)) {
352+
throw new TypeError('Invalid cache domains data');
353+
}
354+
const allDomainFiles = cacheDomainsData.cache_domains.reduce<string[]>((acc, { domain_files }) => {
355+
if (Array.isArray(domain_files)) {
356+
appendArrayInPlace(acc, domain_files);
357+
}
358+
return acc;
359+
}, []);
360+
361+
const allDomains = (
362+
await Promise.all(
363+
allDomainFiles.map(
364+
async (file) => childSpan.traceChildAsync(
365+
'download ' + file,
366+
async () => Array.fromAsync(await fetchRemoteTextByLine('https://cdn.jsdelivr.net/gh/uklans/cache-domains@master/' + file, true))
367+
)
368+
)
369+
)
370+
).flat();
371+
372+
const surgeOutput = new SurgeOnlyRulesetOutput(
373+
span,
374+
'lancache',
375+
'sukka_local_dns_mapping',
376+
OUTPUT_MODULES_RULES_DIR
377+
)
378+
.withTitle('Sukka\'s Ruleset - Local DNS Mapping (lancache)')
379+
.appendDescription(
380+
SHARED_DESCRIPTION,
381+
'',
382+
'This is an internal rule that is only referenced by sukka_local_dns_mapping.sgmodule',
383+
'Do not use this file in your Rule section.'
384+
);
385+
386+
const mihomoOutput = new MihomoNameserverPolicyOutput(
387+
span,
388+
'lancache',
389+
'mihomo_nameserver_policy',
390+
OUTPUT_INTERNAL_DIR
391+
)
392+
.withTitle('Sukka\'s Ruleset - Local DNS Mapping for Mihomo NameServer Policy (lancache)')
393+
.appendDescription(
394+
SHARED_DESCRIPTION,
395+
'',
396+
'This ruleset is only used for mihomo\'s nameserver-policy feature, which',
397+
'is similar to the RULE-SET referenced by sukka_local_dns_mapping.sgmodule.',
398+
'Do not use this file in your Rule section.'
399+
);
400+
401+
for (let i = 0, len = allDomains.length; i < len; i++) {
402+
const domain = allDomains[i];
403+
404+
if (domain.includes('*')) {
405+
// If only *. prefix is used, we can convert it to DOMAIN-SUFFIX
406+
if (domain.startsWith('*.') && !domain.slice(2).includes('*')) {
407+
const domainSuffix = domain.slice(2);
408+
surgeOutput.addDomainSuffix(domainSuffix);
409+
mihomoOutput.addDomainSuffix(domainSuffix);
410+
continue;
411+
}
412+
413+
surgeOutput.addDomainWildcard(domain);
414+
mihomoOutput.addDomainWildcard(domain);
415+
continue;
416+
}
417+
418+
surgeOutput.addDomain(domain);
419+
mihomoOutput.addDomain(domain);
420+
}
421+
422+
return Promise.all([
423+
surgeOutput.write(),
424+
mihomoOutput.write()
425+
]);
426+
}

Build/lib/rules/base.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,14 @@ export class FileOutput {
147147
return this;
148148
}
149149

150-
bulkAddDomainWildcard(domains: string[]) {
151-
for (let i = 0, len = domains.length; i < len; i++) {
152-
this.wildcardSet.add(domains[i]);
150+
addDomainWildcard(wildcard: string) {
151+
this.wildcardSet.add(wildcard);
152+
return this;
153+
}
154+
155+
bulkAddDomainWildcard(wildcards: string[]) {
156+
for (let i = 0, len = wildcards.length; i < len; i++) {
157+
this.wildcardSet.add(wildcards[i]);
153158
}
154159
return this;
155160
}

0 commit comments

Comments
 (0)