Skip to content

Commit

Permalink
feat: remote rule set
Browse files Browse the repository at this point in the history
See #5
  • Loading branch information
geekdada committed Aug 25, 2019
1 parent ab8f695 commit a820cdb
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 6 deletions.
18 changes: 14 additions & 4 deletions lib/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ora from 'ora';
import path from 'path';
import _rimraf from 'rimraf';
import util from 'util';
import _ from 'lodash';

import {
ArtifactConfig,
Expand All @@ -19,7 +20,7 @@ import {
SimpleNodeConfig,
SupportProviderEnum,
NodeFilterType,
CommandConfig,
CommandConfig, RemoteSnippet,
} from './types';
import {
getBlackSSLConfig,
Expand All @@ -39,7 +40,7 @@ import {
toUrlSafeBase64,
usFilter,
youtubePremiumFilter as defaultYoutubePremiumFilter,
normalizeClashProxyGroupConfig,
normalizeClashProxyGroupConfig, loadRemoteSnippetList,
} from './utils';
import getEngine from './template';

Expand All @@ -49,22 +50,28 @@ const spinner = ora();
async function run(config: CommandConfig): Promise<void> {
const artifactList: ReadonlyArray<ArtifactConfig> = config.artifacts;
const distPath = resolveRoot(config.output);
const remoteSnippetsConfig = config.remoteSnippets || [];
const remoteSnippetList = await loadRemoteSnippetList(remoteSnippetsConfig);

await rimraf(distPath);
await fs.mkdir(distPath);

for (const artifact of artifactList) {
spinner.start(`Generating ${artifact.name}`);

const result = await generate(config, artifact);
const result = await generate(config, artifact, remoteSnippetList);
const destFilePath = resolveRoot(config.output, artifact.name);

await fs.writeFile(destFilePath, result);
spinner.succeed();
}
}

export async function generate(config: CommandConfig, artifact: ArtifactConfig): Promise<string> {
export async function generate(
config: CommandConfig,
artifact: ArtifactConfig,
remoteSnippetList: ReadonlyArray<RemoteSnippet>
): Promise<string> {
const templateEngine = getEngine(config.templateDir);
const {
name: artifactName,
Expand Down Expand Up @@ -146,6 +153,9 @@ export async function generate(config: CommandConfig, artifact: ArtifactConfig):
downloadUrl: getDownloadUrl(config.urlBase, artifactName),
nodes: nodeList,
names: nodeNameList,
remoteSnippets: _.keyBy(remoteSnippetList, item => {
return item.name;
}),
nodeList,
provider,
artifactName,
Expand Down
10 changes: 10 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export enum SupportProviderEnum {
export interface CommandConfig {
readonly output: string;
readonly artifacts: ReadonlyArray<ArtifactConfig>;
readonly remoteSnippets?: ReadonlyArray<RemoteSnippetConfig>;
readonly urlBase: string;
readonly providerDir: string;
readonly templateDir: string;
Expand All @@ -26,6 +27,15 @@ export interface CommandConfig {
};
}

export interface RemoteSnippetConfig {
readonly url: string;
readonly name: string;
}

export interface RemoteSnippet extends RemoteSnippetConfig {
readonly main: (rule: string) => string;
}

export interface ArtifactConfig {
readonly name: string;
readonly template: string;
Expand Down
44 changes: 44 additions & 0 deletions lib/utils/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,47 @@ test('getShadowsocksJSONConfig', async t => {
'obfs-host': 'www.bing.com',
});
});

test('loadRemoteSnippetList', async t => {
const remoteSnippetList = await utils.loadRemoteSnippetList([
{
url: 'https://github.com/Blankwonder/surge-list/raw/master/telegram.list',
name: 'telegram',
},
{
url: 'https://github.com/Blankwonder/surge-list/raw/master/netflix.list',
name: 'netflix',
},
{
url: 'https://gist.githubusercontent.com/geekdada/77995d58363c0a271ab56bbcc2dc9054/raw/d1ba422e96a29d8a846303454aeba8fa0ee72e1c/test-ruleset.list',
name: 'test',
}
]);
const result1 = 'IP-CIDR,91.108.56.0/22,Proxy,no-resolve\n' +
'IP-CIDR,91.108.4.0/22,Proxy,no-resolve\n' +
'IP-CIDR,91.108.8.0/22,Proxy,no-resolve\n' +
'IP-CIDR,109.239.140.0/24,Proxy,no-resolve\n' +
'IP-CIDR,149.154.160.0/20,Proxy,no-resolve\n' +
'IP-CIDR,149.154.164.0/22,Proxy,no-resolve\n' +
'IP-CIDR,149.154.172.0/22,Proxy,no-resolve\n' +
'IP-CIDR,91.108.12.0/22,Proxy,no-resolve';
const result2 = '# Netflix\n' +
'USER-AGENT,Argo*,Proxy\n' +
'DOMAIN-SUFFIX,fast.com,Proxy\n' +
'DOMAIN-SUFFIX,netflix.com,Proxy\n' +
'DOMAIN-SUFFIX,netflix.net,Proxy\n' +
'DOMAIN-SUFFIX,nflxext.com,Proxy\n' +
'DOMAIN-SUFFIX,nflximg.com,Proxy\n' +
'DOMAIN-SUFFIX,nflximg.net,Proxy\n' +
'DOMAIN-SUFFIX,nflxso.net,Proxy\n' +
'DOMAIN-SUFFIX,nflxvideo.net,Proxy';
const result3 = '# China Apps\n' +
'USER-AGENT,MicroMessenger Client,Proxy\n' +
'USER-AGENT,WeChat*,Proxy\n' +
'USER-AGENT,MApi*,Proxy // Dianping\n' +
'IP-CIDR,149.154.164.0/22,Proxy,no-resolve // Telegram';

t.is(remoteSnippetList[0].main('Proxy'), result1);
t.is(remoteSnippetList[1].main('Proxy'), result2);
t.is(remoteSnippetList[2].main('Proxy'), result3);
});
61 changes: 59 additions & 2 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@ import {
HttpsNodeConfig,
NodeFilterType,
NodeNameFilterType,
NodeTypeEnum, PossibleNodeConfigType,
NodeTypeEnum,
PossibleNodeConfigType,
ShadowsocksNodeConfig,
ShadowsocksrNodeConfig,
SimpleNodeConfig,
SnellNodeConfig,
CommandConfig, ProxyGroupModifier, PlainObjectOf,
CommandConfig,
ProxyGroupModifier,
PlainObjectOf,
RemoteSnippetConfig,
RemoteSnippet,
} from '../types';

const ConfigCache = new LRU<string, any>({
Expand Down Expand Up @@ -491,3 +496,55 @@ export const normalizeClashProxyGroupConfig = (
}
});
};

export const addProxyToSurgeRuleSet = (str: string, rule: string): string => {
const result: string[] = [];

str
.split('\n')
.filter(item => item && item.trim() !== '')
.forEach(item => {
if (!item.startsWith('#') && !item.startsWith('//')) {
const comment = item.split('//');
const line = comment[0].trim().split(',');

if (line.length === 2) {
line.push(rule);
} else {
line.splice(2, 0, rule);
}

result.push(line.join(',') + (comment[1] ? ` //${comment[1]}` : ''));
} else {
result.push(item);
}
});

return result.join('\n');
};

export const loadRemoteSnippetList = (remoteSnippetList: ReadonlyArray<RemoteSnippetConfig>): Promise<ReadonlyArray<RemoteSnippet>> => {
function load(url: string): Promise<string> {
console.log(`下载远程片段:${url}`);

return axios.get<string>(url, {
timeout: 20000,
proxy: false,
responseType: 'text',
})
.then(data => data.data)
.catch(err => {
console.error(`远程片段 ${url} 下载失败。`);
throw err;
});
}

return Promise.all(remoteSnippetList.map<Promise<RemoteSnippet>>(item => {
return load(item.url)
.then(res => ({
main: (rule: string) => addProxyToSurgeRuleSet(res, rule),
name: item.name,
url: item.url,
}));
}));
};

0 comments on commit a820cdb

Please sign in to comment.