From a5e36a1cd8a2f5dd8074eafb5201d96e4a659dd9 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Fri, 17 Nov 2023 21:36:09 +0800 Subject: [PATCH] Chore: minor changes --- Build/build-chn-cidr.ts | 4 +- Build/build-speedtest-domainset.ts | 23 +++++++-- Build/download-previous-build.ts | 2 - Build/index.ts | 46 +++++------------- Build/lib/fetch-remote-text-by-line.ts | 5 +- Build/lib/parse-filter.ts | 2 +- Build/lib/trace-runner.ts | 8 ++- .../build-internal-reverse-chn-cidr-worker.ts | 8 +++ bun.lockb | Bin 113034 -> 108306 bytes package.json | 3 +- 10 files changed, 51 insertions(+), 50 deletions(-) create mode 100644 Build/workers/build-internal-reverse-chn-cidr-worker.ts diff --git a/Build/build-chn-cidr.ts b/Build/build-chn-cidr.ts index 0ada565e..6295f995 100644 --- a/Build/build-chn-cidr.ts +++ b/Build/build-chn-cidr.ts @@ -11,12 +11,12 @@ const EXCLUDE_CIDRS = [ ]; export const buildChnCidr = task(__filename, async () => { - const [{ exclude: excludeCidrs }, cidr] = await Promise.all([ + const [{ exclude }, cidr] = await Promise.all([ import('cidr-tools-wasm'), processLineFromReadline(await fetchRemoteTextAndCreateReadlineInterface('https://raw.githubusercontent.com/misakaio/chnroutes2/master/chnroutes.txt')) ]); - const filteredCidr = excludeCidrs(cidr, EXCLUDE_CIDRS, true); + const filteredCidr = exclude(cidr, EXCLUDE_CIDRS, true); const description = [ 'License: CC BY-SA 2.0', diff --git a/Build/build-speedtest-domainset.ts b/Build/build-speedtest-domainset.ts index 9298f99d..f0d45e62 100644 --- a/Build/build-speedtest-domainset.ts +++ b/Build/build-speedtest-domainset.ts @@ -6,18 +6,29 @@ import domainSorter from './lib/stable-sort-domain'; import { Sema } from 'async-sema'; import * as tldts from 'tldts'; import { task } from './lib/trace-runner'; -const s = new Sema(2); +const s = new Sema(3); + +const latestTopUserAgentsPromise = fetch('https://unpkg.com/top-user-agents@latest/index.json') + .then(res => res.json() as Promise); const querySpeedtestApi = async (keyword: string): Promise<(string | null)[]> => { - await s.acquire(); + const [topUserAgents] = await Promise.all([ + latestTopUserAgentsPromise, + s.acquire() + ]); + + const randomUserAgent = topUserAgents[Math.floor(Math.random() * topUserAgents.length)]; try { + const key = `fetch speedtest endpoints: ${keyword}`; + console.time(key); + const res = await fetch(`https://www.speedtest.net/api/js/servers?engine=js&search=${keyword}&limit=100`, { headers: { dnt: '1', Referer: 'https://www.speedtest.net/', accept: 'application/json, text/plain, */*', - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36', + 'User-Agent': randomUserAgent, 'Accept-Language': 'en-US,en;q=0.9', 'Sec-Ch-Ua': '"Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"', 'Sec-Ch-Ua-Mobile': '?0', @@ -28,12 +39,14 @@ const querySpeedtestApi = async (keyword: string): Promise<(string | null)[]> => } }); if (!res.ok) { - const text = await res.text(); - throw new Error(text); + throw new Error(res.statusText + '\n' + await res.text()); } const json = await res.json() as { url: string; }[]; s.release(); + + console.timeEnd(key); + return json.map(({ url }) => tldts.getHostname(url, { detectIp: false })); } catch (e) { s.release(); diff --git a/Build/download-previous-build.ts b/Build/download-previous-build.ts index 65da50cb..7369d057 100644 --- a/Build/download-previous-build.ts +++ b/Build/download-previous-build.ts @@ -75,8 +75,6 @@ export const downloadPreviousBuild = task(__filename, async () => { ); } })); - - // return fsp.unlink(extractedPath).catch(() => { }); }); export const downloadPublicSuffixList = task(__filename, async () => { diff --git a/Build/index.ts b/Build/index.ts index ac15fbc0..1f05ab20 100644 --- a/Build/index.ts +++ b/Build/index.ts @@ -16,39 +16,11 @@ import { buildRedirectModule } from './build-redirect-module'; import { validate } from './validate-domainset'; import { buildPublicHtml } from './build-public'; - -import { Worker } from 'jest-worker'; - -type WithWorker = import('jest-worker').Worker & { __sukka_worker_name: string } & T - -const requireWorker = (path: string, exposedMethods?: (keyof T & string)[]): WithWorker => { - const _worker = new Worker( - import.meta.require.resolve(path), - { - numWorkers: 1, - maxRetries: 0, - enableWorkerThreads: true, - exposedMethods - } - ) as WithWorker; - _worker.getStderr().pipe(process.stderr); - _worker.getStdout().pipe(process.stdout); - _worker.__sukka_worker_name = path; - return _worker; -}; - -const endWorker = async (worker: WithWorker) => { - const { forceExited } = await worker.end(); - if (forceExited && worker.__sukka_worker_name) { - console.log(worker.__sukka_worker_name, 'forceExited'); - } -}; +import { TaskResult } from './lib/trace-runner'; (async () => { - const buildInternalReverseChnCIDRWorker: WithWorker = requireWorker('./build-internal-reverse-chn-cidr', ['buildInternalReverseChnCIDR']); + const buildInternalReverseChnCIDRWorker = new Worker(new URL('./workers/build-internal-reverse-chn-cidr-worker.ts', import.meta.url)); try { - const { buildInternalReverseChnCIDR } = buildInternalReverseChnCIDRWorker; - const downloadPreviousBuildPromise = downloadPreviousBuild(); const downloadPublicSuffixListPromise = downloadPublicSuffixList(); const buildCommonPromise = downloadPreviousBuildPromise.then(() => buildCommon()); @@ -75,7 +47,15 @@ const endWorker = async (worker: WithWorker) => { buildCommonPromise, buildCdnConfPromise ]).then(() => buildInternalCDNDomains()); - const buildInternalReverseChnCIDRPromise = buildInternalReverseChnCIDR(); + + const buildInternalReverseChnCIDRPromise = new Promise(resolve => { + buildInternalReverseChnCIDRWorker.postMessage(null); + buildInternalReverseChnCIDRWorker.onmessage = (e: MessageEvent) => { + buildInternalReverseChnCIDRWorker.terminate(); + resolve(e.data); + }; + }); + const buildInternalChnDomainsPromise = buildInternalChnDomains(); const buildDomesticRulesetPromise = downloadPreviousBuildPromise.then(() => buildDomesticRuleset()); @@ -109,9 +89,7 @@ const endWorker = async (worker: WithWorker) => { printStats(stats); } catch (e) { - console.error(e) - } finally { - await endWorker(buildInternalReverseChnCIDRWorker) + console.error(e); } })(); diff --git a/Build/lib/fetch-remote-text-by-line.ts b/Build/lib/fetch-remote-text-by-line.ts index 3e93dd16..2c5225ee 100644 --- a/Build/lib/fetch-remote-text-by-line.ts +++ b/Build/lib/fetch-remote-text-by-line.ts @@ -56,7 +56,6 @@ export async function* createReadlineInterfaceFromResponse(resp: Response): Asyn } } -export async function fetchRemoteTextAndCreateReadlineInterface(url: string | URL, opt?: RequestInit): Promise> { - const resp = await fetchWithRetry(url, opt); - return createReadlineInterfaceFromResponse(resp); +export function fetchRemoteTextAndCreateReadlineInterface(url: string | URL, opt?: RequestInit): Promise> { + return fetchWithRetry(url, opt).then(res => createReadlineInterfaceFromResponse(res)); } diff --git a/Build/lib/parse-filter.ts b/Build/lib/parse-filter.ts index 89550c73..98df18d0 100644 --- a/Build/lib/parse-filter.ts +++ b/Build/lib/parse-filter.ts @@ -68,7 +68,7 @@ export async function processDomainLists(domainListsUrl: string | URL) { } export async function processHosts(hostsUrl: string | URL, includeAllSubDomain = false) { - console.time(` - processHosts: ${hostsUrl}`); + console.time(`- processHosts: ${hostsUrl}`); if (typeof hostsUrl === 'string') { hostsUrl = new URL(hostsUrl); diff --git a/Build/lib/trace-runner.ts b/Build/lib/trace-runner.ts index 3a0920a5..886ac177 100644 --- a/Build/lib/trace-runner.ts +++ b/Build/lib/trace-runner.ts @@ -18,6 +18,12 @@ const traceAsync = async (prefix: string, fn: () => Promise): Promise = }; export { traceAsync }; +export interface TaskResult { + readonly start: number; + readonly end: number; + readonly taskName: string; +} + const task = (__filename: string, fn: () => Promise, customname: string | null = null) => { const taskName = customname ?? path.basename(__filename, path.extname(__filename)); return async () => { @@ -27,7 +33,7 @@ const task = (__filename: string, fn: () => Promise, customname: string | const end = performance.now(); console.log(`✅ [${taskName}] Executed successfully: ${(end - start).toFixed(3)}ms`); - return { start, end, taskName } as const; + return { start, end, taskName } as TaskResult; }; }; export { task }; diff --git a/Build/workers/build-internal-reverse-chn-cidr-worker.ts b/Build/workers/build-internal-reverse-chn-cidr-worker.ts new file mode 100644 index 00000000..d2f6ca43 --- /dev/null +++ b/Build/workers/build-internal-reverse-chn-cidr-worker.ts @@ -0,0 +1,8 @@ +declare const self: Worker; + +import { buildInternalReverseChnCIDR } from '../build-internal-reverse-chn-cidr'; + +self.onmessage = async () => { + const stat = await buildInternalReverseChnCIDR(); + postMessage(stat); +}; diff --git a/bun.lockb b/bun.lockb index c38d15c9eb6b40e9ccdc45dd6b31e641f76c3300..d69e15cd117dc4200b7fc671ec63a922b9e76972 100755 GIT binary patch delta 19107 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 delta 21957 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