mirror of
https://github.com/SukkaW/Surge.git
synced 2026-01-29 01:51:52 +08:00
Perf: minor improvements here and there
This commit is contained in:
@@ -23,7 +23,7 @@ if (!fs.existsSync(CACHE_DIR)) {
|
|||||||
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const agent = new Agent({ allowH2: true });
|
const agent = new Agent({ allowH2: false });
|
||||||
|
|
||||||
setGlobalDispatcher(agent.compose(
|
setGlobalDispatcher(agent.compose(
|
||||||
interceptors.retry({
|
interceptors.retry({
|
||||||
|
|||||||
@@ -111,10 +111,8 @@ export function processFilterRulesWithPreload(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// const R_KNOWN_NOT_NETWORK_FILTER_PATTERN_2 = /(\$popup|\$removeparam|\$popunder|\$cname)/;
|
// many filter that has modifiers can not work on Surge/Clash because browser context is required
|
||||||
// cname exceptional filter can not be parsed by NetworkFilter
|
// we can early bail out those rules
|
||||||
// Surge / Clash can't handle CNAME either, so we just ignore them
|
|
||||||
|
|
||||||
const kwfilter = createKeywordFilter([
|
const kwfilter = createKeywordFilter([
|
||||||
'!',
|
'!',
|
||||||
'?',
|
'?',
|
||||||
@@ -132,10 +130,16 @@ const kwfilter = createKeywordFilter([
|
|||||||
// special modifier
|
// special modifier
|
||||||
'$popup',
|
'$popup',
|
||||||
'$removeparam',
|
'$removeparam',
|
||||||
|
'$redirect',
|
||||||
'$popunder',
|
'$popunder',
|
||||||
'$cname',
|
'$cname',
|
||||||
'$frame',
|
'$frame',
|
||||||
'$domain',
|
'$domain',
|
||||||
|
'$from',
|
||||||
|
'$to',
|
||||||
|
'$csp',
|
||||||
|
'$replace',
|
||||||
|
'$urlskip',
|
||||||
// some bad syntax
|
// some bad syntax
|
||||||
'^popup'
|
'^popup'
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -91,8 +91,7 @@ describe('Trie', () => {
|
|||||||
trie.add('example.com');
|
trie.add('example.com');
|
||||||
trie.add('moe.sb');
|
trie.add('moe.sb');
|
||||||
|
|
||||||
expect(trie.delete('')).toBe(false);
|
expect(trie.delete('no-match.com')).toBe(false);
|
||||||
expect(trie.delete('')).toBe(false);
|
|
||||||
expect(trie.delete('example.org')).toBe(false);
|
expect(trie.delete('example.org')).toBe(false);
|
||||||
|
|
||||||
expect(trie.delete('skk.moe')).toBe(true);
|
expect(trie.delete('skk.moe')).toBe(true);
|
||||||
@@ -131,7 +130,7 @@ describe('Trie', () => {
|
|||||||
expect(trie.find('.example.com')).toStrictEqual(['blog.example.com', 'cdn.example.com']);
|
expect(trie.find('.example.com')).toStrictEqual(['blog.example.com', 'cdn.example.com']);
|
||||||
expect(trie.find('org')).toStrictEqual(['example.org']);
|
expect(trie.find('org')).toStrictEqual(['example.org']);
|
||||||
expect(trie.find('example.net')).toStrictEqual([]);
|
expect(trie.find('example.net')).toStrictEqual([]);
|
||||||
expect(trie.find('')).toStrictEqual(['example.com', 'example.org', 'blog.example.com', 'cdn.example.com']);
|
expect(trie.dump()).toStrictEqual(['example.com', 'example.org', 'blog.example.com', 'cdn.example.com']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be possible to retrieve items matching the given prefix even with a smol trie', () => {
|
it('should be possible to retrieve items matching the given prefix even with a smol trie', () => {
|
||||||
@@ -148,7 +147,7 @@ describe('Trie', () => {
|
|||||||
expect(trie.find('.example.com')).toStrictEqual(['.example.com']);
|
expect(trie.find('.example.com')).toStrictEqual(['.example.com']);
|
||||||
expect(trie.find('org')).toStrictEqual(['example.org']);
|
expect(trie.find('org')).toStrictEqual(['example.org']);
|
||||||
expect(trie.find('example.net')).toStrictEqual([]);
|
expect(trie.find('example.net')).toStrictEqual([]);
|
||||||
expect(trie.find('')).toStrictEqual(['.example.com', 'example.org']);
|
expect(trie.dump()).toStrictEqual(['.example.com', 'example.org']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be possible to create a trie from an arbitrary iterable.', () => {
|
it('should be possible to create a trie from an arbitrary iterable.', () => {
|
||||||
@@ -192,6 +191,28 @@ describe('surge domainset dedupe', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('smol tree', () => {
|
describe('smol tree', () => {
|
||||||
|
it('should init tree', () => {
|
||||||
|
const trie = createTrie([
|
||||||
|
'skk.moe',
|
||||||
|
'anotherskk.moe',
|
||||||
|
'blog.anotherskk.moe',
|
||||||
|
'blog.skk.moe',
|
||||||
|
'.cdn.local',
|
||||||
|
'blog.img.skk.local',
|
||||||
|
'img.skk.local'
|
||||||
|
], true);
|
||||||
|
|
||||||
|
expect(trie.dump()).toStrictEqual([
|
||||||
|
'skk.moe',
|
||||||
|
'anotherskk.moe',
|
||||||
|
'.cdn.local',
|
||||||
|
'blog.skk.moe',
|
||||||
|
'blog.anotherskk.moe',
|
||||||
|
'img.skk.local',
|
||||||
|
'blog.img.skk.local'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('should create simple tree - 1', () => {
|
it('should create simple tree - 1', () => {
|
||||||
const trie = createTrie([
|
const trie = createTrie([
|
||||||
'.skk.moe', 'blog.skk.moe', '.cdn.skk.moe', 'skk.moe',
|
'.skk.moe', 'blog.skk.moe', '.cdn.skk.moe', 'skk.moe',
|
||||||
@@ -264,7 +285,7 @@ describe('smol tree', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should efficiently whitelist domains', () => {
|
it('should effctly whitelist domains', () => {
|
||||||
const trie = createTrie([
|
const trie = createTrie([
|
||||||
'skk.moe',
|
'skk.moe',
|
||||||
'anotherskk.moe',
|
'anotherskk.moe',
|
||||||
@@ -275,16 +296,6 @@ describe('smol tree', () => {
|
|||||||
'img.skk.local'
|
'img.skk.local'
|
||||||
], true);
|
], true);
|
||||||
|
|
||||||
expect(trie.dump()).toStrictEqual([
|
|
||||||
'skk.moe',
|
|
||||||
'anotherskk.moe',
|
|
||||||
'.cdn.local',
|
|
||||||
'blog.skk.moe',
|
|
||||||
'blog.anotherskk.moe',
|
|
||||||
'img.skk.local',
|
|
||||||
'blog.img.skk.local'
|
|
||||||
]);
|
|
||||||
|
|
||||||
trie.whitelist('.skk.moe');
|
trie.whitelist('.skk.moe');
|
||||||
|
|
||||||
expect(trie.dump()).toStrictEqual([
|
expect(trie.dump()).toStrictEqual([
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ function deepTrieNodeToJSON(node: TrieNode,
|
|||||||
|
|
||||||
const createNode = <Meta = any>(parent: TrieNode | null = null): TrieNode => [1, parent, new Map<string, TrieNode>(), null] as TrieNode<Meta>;
|
const createNode = <Meta = any>(parent: TrieNode | null = null): TrieNode => [1, parent, new Map<string, TrieNode>(), null] as TrieNode<Meta>;
|
||||||
|
|
||||||
export function hostnameToTokens(hostname: string, hostnameFromIndex: number): string[] {
|
function hostnameToTokens(hostname: string, hostnameFromIndex: number): string[] {
|
||||||
const tokens = hostname.split('.');
|
const tokens = hostname.split('.');
|
||||||
const results: string[] = [];
|
const results: string[] = [];
|
||||||
let token = '';
|
let token = '';
|
||||||
@@ -50,6 +50,8 @@ export function hostnameToTokens(hostname: string, hostnameFromIndex: number): s
|
|||||||
token = tokens[i];
|
token = tokens[i];
|
||||||
if (token.length > 0) {
|
if (token.length > 0) {
|
||||||
results.push(token);
|
results.push(token);
|
||||||
|
} else {
|
||||||
|
throw new TypeError(JSON.stringify({ hostname, hostnameFromIndex }, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +119,9 @@ abstract class Triebase<Meta = any> {
|
|||||||
let parent: TrieNode = node;
|
let parent: TrieNode = node;
|
||||||
|
|
||||||
let token: string;
|
let token: string;
|
||||||
|
let child: Map<string, TrieNode<Meta>> = node[2];
|
||||||
|
|
||||||
|
// reverse lookup from end to start
|
||||||
for (let i = tokens.length - 1; i >= 0; i--) {
|
for (let i = tokens.length - 1; i >= 0; i--) {
|
||||||
token = tokens[i];
|
token = tokens[i];
|
||||||
|
|
||||||
@@ -127,8 +131,10 @@ abstract class Triebase<Meta = any> {
|
|||||||
|
|
||||||
parent = node;
|
parent = node;
|
||||||
|
|
||||||
if (node[2].has(token)) {
|
child = node[2];
|
||||||
node = node[2].get(token)!;
|
// cache node index access is 20% faster than direct access when doing twice
|
||||||
|
if (child.has(token)) {
|
||||||
|
node = child.get(token)!;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -147,6 +153,8 @@ abstract class Triebase<Meta = any> {
|
|||||||
let node: TrieNode = this.$root;
|
let node: TrieNode = this.$root;
|
||||||
let parent: TrieNode = node;
|
let parent: TrieNode = node;
|
||||||
|
|
||||||
|
let child: Map<string, TrieNode<Meta>> = node[2];
|
||||||
|
|
||||||
const onToken = (token: string) => {
|
const onToken = (token: string) => {
|
||||||
// if (token === '') {
|
// if (token === '') {
|
||||||
// return true;
|
// return true;
|
||||||
@@ -154,8 +162,10 @@ abstract class Triebase<Meta = any> {
|
|||||||
|
|
||||||
parent = node;
|
parent = node;
|
||||||
|
|
||||||
if (node[2].has(token)) {
|
child = node[2];
|
||||||
node = node[2].get(token)!;
|
|
||||||
|
if (child.has(token)) {
|
||||||
|
node = child.get(token)!;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -204,12 +214,14 @@ abstract class Triebase<Meta = any> {
|
|||||||
const node = nodeStack.shift()!;
|
const node = nodeStack.shift()!;
|
||||||
const suffix = suffixStack.shift()!;
|
const suffix = suffixStack.shift()!;
|
||||||
|
|
||||||
if (node[2].size) {
|
const child = node[2];
|
||||||
const keys = Array.from(node[2].keys()).sort(Triebase.compare);
|
|
||||||
|
if (child.size) {
|
||||||
|
const keys = Array.from(child.keys()).sort(Triebase.compare);
|
||||||
|
|
||||||
for (let i = 0, l = keys.length; i < l; i++) {
|
for (let i = 0, l = keys.length; i < l; i++) {
|
||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
const childNode = node[2].get(key)!;
|
const childNode = child.get(key)!;
|
||||||
|
|
||||||
// Pushing the child node to the stack for next iteration of DFS
|
// Pushing the child node to the stack for next iteration of DFS
|
||||||
nodeStack.push(childNode);
|
nodeStack.push(childNode);
|
||||||
@@ -271,17 +283,18 @@ abstract class Triebase<Meta = any> {
|
|||||||
suffixStack.push(initialSuffix);
|
suffixStack.push(initialSuffix);
|
||||||
|
|
||||||
let node: TrieNode<Meta> = initialNode;
|
let node: TrieNode<Meta> = initialNode;
|
||||||
|
let child: Map<string, TrieNode<Meta>> = node[2];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
node = nodeStack.shift()!;
|
node = nodeStack.shift()!;
|
||||||
const suffix = suffixStack.shift()!;
|
const suffix = suffixStack.shift()!;
|
||||||
|
child = node[2];
|
||||||
if (node[2].size) {
|
if (child.size) {
|
||||||
const keys = Array.from(node[2].keys()).sort(Triebase.compare);
|
const keys = Array.from(child.keys()).sort(Triebase.compare);
|
||||||
|
|
||||||
for (let i = 0, l = keys.length; i < l; i++) {
|
for (let i = 0, l = keys.length; i < l; i++) {
|
||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
const childNode = node[2].get(key)!;
|
const childNode = child.get(key)!;
|
||||||
|
|
||||||
// Pushing the child node to the stack for next iteration of DFS
|
// Pushing the child node to the stack for next iteration of DFS
|
||||||
nodeStack.push(childNode);
|
nodeStack.push(childNode);
|
||||||
@@ -303,18 +316,21 @@ abstract class Triebase<Meta = any> {
|
|||||||
const onLoop = (node: TrieNode, parent: TrieNode, token: string) => {
|
const onLoop = (node: TrieNode, parent: TrieNode, token: string) => {
|
||||||
// Keeping track of a potential branch to prune
|
// Keeping track of a potential branch to prune
|
||||||
|
|
||||||
// Even if the node size is 1, but the single child is ".", we should retain the branch
|
const child = node[2];
|
||||||
// Since the "." could be special if it is the leaf-est node
|
|
||||||
const onlyChild = node[2].size === 0 && !node[1];
|
|
||||||
|
|
||||||
if (toPrune != null) { // the top-est branch that could potentially being pruned
|
// console.log({
|
||||||
if (!onlyChild) {
|
// child, parent, token
|
||||||
// The branch has moew than single child, retain the branch.
|
// });
|
||||||
// And we need to abort prune the parent, so we set it to null
|
// console.log(this.inspect(0));
|
||||||
|
|
||||||
|
if (toPrune !== null) { // the most near branch that could potentially being pruned
|
||||||
|
if (child.size > 1) {
|
||||||
|
// The branch has some children, the branch need retain.
|
||||||
|
// And we need to abort prune that parent branch, so we set it to null
|
||||||
toPrune = null;
|
toPrune = null;
|
||||||
tokenToPrune = null;
|
tokenToPrune = null;
|
||||||
}
|
}
|
||||||
} else if (onlyChild) {
|
} else if (child.size < 1) {
|
||||||
// There is only one token child, or no child at all, we can prune it safely
|
// There is only one token child, or no child at all, we can prune it safely
|
||||||
// It is now the top-est branch that could potentially being pruned
|
// It is now the top-est branch that could potentially being pruned
|
||||||
toPrune = parent;
|
toPrune = parent;
|
||||||
@@ -552,7 +568,6 @@ export class HostnameSmolTrie<Meta = any> extends Triebase<Meta> {
|
|||||||
public whitelist(suffix: string, includeAllSubdomain = suffix[0] === '.', hostnameFromIndex = suffix[0] === '.' ? 1 : 0) {
|
public whitelist(suffix: string, includeAllSubdomain = suffix[0] === '.', hostnameFromIndex = suffix[0] === '.' ? 1 : 0) {
|
||||||
const tokens = hostnameToTokens(suffix, hostnameFromIndex);
|
const tokens = hostnameToTokens(suffix, hostnameFromIndex);
|
||||||
const res = this.getSingleChildLeaf(tokens);
|
const res = this.getSingleChildLeaf(tokens);
|
||||||
|
|
||||||
if (res === null) return;
|
if (res === null) return;
|
||||||
|
|
||||||
const { node, toPrune, tokenToPrune } = res;
|
const { node, toPrune, tokenToPrune } = res;
|
||||||
@@ -572,7 +587,7 @@ export class HostnameSmolTrie<Meta = any> extends Triebase<Meta> {
|
|||||||
// return early if not found
|
// return early if not found
|
||||||
if (missingBit(node[0], START)) return;
|
if (missingBit(node[0], START)) return;
|
||||||
|
|
||||||
if (tokenToPrune && toPrune) {
|
if (toPrune && tokenToPrune) {
|
||||||
toPrune[2].delete(tokenToPrune);
|
toPrune[2].delete(tokenToPrune);
|
||||||
} else {
|
} else {
|
||||||
node[0] = deleteBit(node[0], START);
|
node[0] = deleteBit(node[0], START);
|
||||||
@@ -587,13 +602,15 @@ export class HostnameTrie<Meta = any> extends Triebase<Meta> {
|
|||||||
|
|
||||||
add(suffix: string, includeAllSubdomain = suffix[0] === '.', meta?: Meta, hostnameFromIndex = suffix[0] === '.' ? 1 : 0): void {
|
add(suffix: string, includeAllSubdomain = suffix[0] === '.', meta?: Meta, hostnameFromIndex = suffix[0] === '.' ? 1 : 0): void {
|
||||||
let node: TrieNode<Meta> = this.$root;
|
let node: TrieNode<Meta> = this.$root;
|
||||||
|
let child: Map<string, TrieNode<Meta>> = node[2];
|
||||||
|
|
||||||
const onToken = (token: string) => {
|
const onToken = (token: string) => {
|
||||||
if (node[2].has(token)) {
|
child = node[2];
|
||||||
node = node[2].get(token)!;
|
if (child.has(token)) {
|
||||||
|
node = child.get(token)!;
|
||||||
} else {
|
} else {
|
||||||
const newNode = createNode(node);
|
const newNode = createNode(node);
|
||||||
node[2].set(token, newNode);
|
child.set(token, newNode);
|
||||||
node = newNode;
|
node = newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ export function task(importMetaMain: boolean, importMetaPath: string) {
|
|||||||
dummySpan.traceChildAsync('dummy', (childSpan) => fn(childSpan, onCleanup)).finally(() => {
|
dummySpan.traceChildAsync('dummy', (childSpan) => fn(childSpan, onCleanup)).finally(() => {
|
||||||
dummySpan.stop();
|
dummySpan.stop();
|
||||||
printTraceResult(dummySpan.traceResult);
|
printTraceResult(dummySpan.traceResult);
|
||||||
whyIsNodeRunning();
|
process.nextTick(whyIsNodeRunning);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user