From 6daf8e3bb42ec4f5c3ce62c627c9ed28c964e945 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Sun, 14 Jan 2024 23:29:29 +0800 Subject: [PATCH] Perf: optimize sort domains & preload promise --- Build/build-speedtest-domainset.ts | 30 +++++++++++++++++++++++------- Build/build-stream-service.ts | 23 +++++++++++------------ Build/lib/cached-tld-parse.ts | 5 +++-- Build/lib/memo-promise.ts | 9 +++++++-- Build/lib/stable-sort-domain.ts | 12 ++++-------- 5 files changed, 48 insertions(+), 31 deletions(-) diff --git a/Build/build-speedtest-domainset.ts b/Build/build-speedtest-domainset.ts index 69d8ae8d..f715c048 100644 --- a/Build/build-speedtest-domainset.ts +++ b/Build/build-speedtest-domainset.ts @@ -13,6 +13,9 @@ import picocolors from 'picocolors'; import { fetchRemoteTextByLine } from './lib/fetch-text-by-line'; import { processLine } from './lib/process-line'; import { TTL, deserializeArray, fsCache, serializeArray } from './lib/cache-filesystem'; +import { createMemoizedPromise } from './lib/memo-promise'; + +import * as SetHelpers from 'mnemonist/set'; const s = new Sema(2); @@ -80,15 +83,26 @@ const querySpeedtestApi = async (keyword: string): Promise> } }; +const getPreviousSpeedtestDomainsPromise = createMemoizedPromise(async () => { + const domains = new Set(); + for await (const l of await fetchRemoteTextByLine('https://ruleset.skk.moe/List/domainset/speedtest.conf')) { + const line = processLine(l); + if (line) { + domains.add(line); + } + } + return domains; +}); + export const buildSpeedtestDomainSet = task(import.meta.path, async (span) => { // Predefined domainset /** @type {Set} */ const domains = new Set([ + // speedtest.net '.speedtest.net', '.speedtestcustom.com', '.ooklaserver.net', '.speed.misaka.one', - '.speed.cloudflare.com', '.speedtest.rt.ru', '.speedtest.aptg.com.tw', '.speedtest.gslnetworks.com', @@ -133,6 +147,13 @@ export const buildSpeedtestDomainSet = task(import.meta.path, async (span) => { '.speedtest.optitel.com.au', '.speednet.net.tr', '.speedtest.angolacables.co.ao', + '.ookla-speedtest.fsr.com', + '.speedtest.comnet.com.tr', + '.speedtest.gslnetworks.com.au', + '.speedtest.gslnetworks.com', + '.speedtestunonet.com.br', + // Cloudflare + '.speed.cloudflare.com', // Wi-Fi Man '.wifiman.com', '.wifiman.me', @@ -152,12 +173,7 @@ export const buildSpeedtestDomainSet = task(import.meta.path, async (span) => { ]); await span.traceChild('fetch previous speedtest domainset').traceAsyncFn(async () => { - for await (const l of await fetchRemoteTextByLine('https://ruleset.skk.moe/List/domainset/speedtest.conf')) { - const line = processLine(l); - if (line) { - domains.add(line); - } - } + SetHelpers.add(domains, await getPreviousSpeedtestDomainsPromise()); }); await new Promise((resolve) => { diff --git a/Build/build-stream-service.ts b/Build/build-stream-service.ts index d321073d..e1b0cc78 100644 --- a/Build/build-stream-service.ts +++ b/Build/build-stream-service.ts @@ -9,8 +9,7 @@ import { ALL, NORTH_AMERICA, EU, HK, TW, JP, KR } from '../Source/stream'; import { SHARED_DESCRIPTION } from './lib/constants'; export const createRulesetForStreamService = (span: Span, fileId: string, title: string, streamServices: Array) => { - const childSpan = span.traceChild(fileId); - return [ + return span.traceChild(fileId).traceAsyncFn(async (childSpan) => Promise.all([ // Domains createRuleset( childSpan, @@ -48,20 +47,20 @@ export const createRulesetForStreamService = (span: Span, fileId: string, title: path.resolve(import.meta.dir, `../List/ip/${fileId}.conf`), path.resolve(import.meta.dir, `../Clash/ip/${fileId}.txt`) ) - ]; + ])); }; export const buildStreamService = task(import.meta.path, async (span) => { return Promise.all([ - ...createRulesetForStreamService(span, 'stream', 'All', ALL), - ...createRulesetForStreamService(span, 'stream_us', 'North America', NORTH_AMERICA), - ...createRulesetForStreamService(span, 'stream_eu', 'Europe', EU), - ...createRulesetForStreamService(span, 'stream_hk', 'Hong Kong', HK), - ...createRulesetForStreamService(span, 'stream_tw', 'Taiwan', TW), - ...createRulesetForStreamService(span, 'stream_jp', 'Japan', JP), - // ...createRulesetForStreamService('stream_au', 'Oceania', AU), - ...createRulesetForStreamService(span, 'stream_kr', 'Korean', KR) - // ...createRulesetForStreamService('stream_south_east_asia', 'South East Asia', SOUTH_EAST_ASIA) + createRulesetForStreamService(span, 'stream', 'All', ALL), + createRulesetForStreamService(span, 'stream_us', 'North America', NORTH_AMERICA), + createRulesetForStreamService(span, 'stream_eu', 'Europe', EU), + createRulesetForStreamService(span, 'stream_hk', 'Hong Kong', HK), + createRulesetForStreamService(span, 'stream_tw', 'Taiwan', TW), + createRulesetForStreamService(span, 'stream_jp', 'Japan', JP), + // createRulesetForStreamService('stream_au', 'Oceania', AU), + createRulesetForStreamService(span, 'stream_kr', 'Korean', KR) + // createRulesetForStreamService('stream_south_east_asia', 'South East Asia', SOUTH_EAST_ASIA) ]); }); diff --git a/Build/lib/cached-tld-parse.ts b/Build/lib/cached-tld-parse.ts index ef3ac47a..8c1de5a8 100644 --- a/Build/lib/cached-tld-parse.ts +++ b/Build/lib/cached-tld-parse.ts @@ -16,8 +16,9 @@ export const parseWithoutDetectIp = parse2; let gothillGetDomainCache: ReturnType | null = null; export const createCachedGorhillGetDomain = (gorhill: PublicSuffixList) => { + gothillGetDomainCache ??= createCache('cached-gorhill-get-domain', true); return (domain: string) => { - gothillGetDomainCache ??= createCache('cached-gorhill-get-domain', true); - return gothillGetDomainCache.sync(domain, () => gorhill.getDomain(domain[0] === '.' ? domain.slice(1) : domain)); + // we do know gothillGetDomainCache exists here + return gothillGetDomainCache!.sync(domain, () => gorhill.getDomain(domain[0] === '.' ? domain.slice(1) : domain)); }; }; diff --git a/Build/lib/memo-promise.ts b/Build/lib/memo-promise.ts index ff26f4c8..0c701113 100644 --- a/Build/lib/memo-promise.ts +++ b/Build/lib/memo-promise.ts @@ -1,7 +1,12 @@ -export const createMemoizedPromise = (fn: () => Promise): () => Promise => { +export const createMemoizedPromise = (fn: () => Promise, preload = true): () => Promise => { let promise: Promise | null = null; + + if (preload) { + promise = fn(); + } + return () => { - promise ||= fn(); + promise ??= fn(); return promise; }; }; diff --git a/Build/lib/stable-sort-domain.ts b/Build/lib/stable-sort-domain.ts index 8b6da71b..42a9ce9a 100644 --- a/Build/lib/stable-sort-domain.ts +++ b/Build/lib/stable-sort-domain.ts @@ -35,18 +35,14 @@ const compare = (a: string | null, b: string | null) => { export const sortDomains = (inputs: string[], gorhill: PublicSuffixList) => { const getDomain = createCachedGorhillGetDomain(gorhill); - const domains = inputs.reduce>((acc, cur) => { - acc[cur] ||= getDomain(cur); + const domains = inputs.reduce>((acc, cur) => { + if (!acc.has(cur)) acc.set(cur, getDomain(cur)); return acc; - }, {}); + }, new Map()); const sorter = (a: string, b: string) => { if (a === b) return 0; - - const aDomain = domains[a]; - const bDomain = domains[b]; - - return compare(aDomain, bDomain) || compare(a, b); + return compare(domains.get(a)!, domains.get(b)!) || compare(a, b); }; return inputs.sort(sorter);