Skip to content

Commit

Permalink
feat: useProviders, discardProviders
Browse files Browse the repository at this point in the history
  • Loading branch information
geekdada committed Jan 2, 2020
1 parent b4db6ad commit e11cb75
Show file tree
Hide file tree
Showing 20 changed files with 133 additions and 27 deletions.
40 changes: 40 additions & 0 deletions docs/guide/advance/custom-filter.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ sidebarDepth: 2

# 自定义过滤器

[[toc]]

在之前的版本里,我们允许用户使用内置的几个过滤器进行节点过滤。现在 Surgio 已经支持在 Provider 和 Surgio 配置中自定义 Filter。需要提醒一下大家,原来内置的国别过滤器已经拓展了不少,可以在 [这里](/guide/custom-template.md#过滤器) 查看。

## 如何自定义
Expand Down Expand Up @@ -159,3 +161,41 @@ module.exports = {
2. 若某个节点同时匹配多个规则,只会出现在第一次匹配的位置。
3. Provider 的配置项 `nodeFilter` 也支持排序类型的过滤器,但我们并不建议您这么用,因为 Provider 的 `nodeFilter` 配置项仅针对当前 Provider 而非合并进来的所有的节点,再者如果你同时在 `nodeFilter``getNodeNames`(包括但不限于)中使用排序过滤器,会进行多次排序,很难避免不出错。所以请尽可能在 `nodeFilter` 中使用普通的过滤器。
:::

### useProviders <Badge text="v1.11.0" vertical="middle" />

合并 Provider 之后若是想快速地过滤出某几个 Provider 中的节点作为一个策略组,可以使用该过滤器。

```js
// surgio.conf.js
const { utils } = require('surgio');

module.exports = {
customFilters: {
providerFilter: utils.useProviders(['dlercloud', 'maying']),
},
};
```

:::warning 注意
该过滤器不保证顺序。
:::

### discardProviders <Badge text="v1.11.0" vertical="middle" />

合并 Provider 之后若是想快速地舍弃某几个 Provider 中的节点作为一个策略组,可以使用该过滤器。

```js
// surgio.conf.js
const { utils } = require('surgio');

module.exports = {
customFilters: {
providerFilter: utils.discardProviders(['dlercloud', 'maying']),
},
};
```

:::warning 注意
该过滤器不保证顺序。
:::
2 changes: 2 additions & 0 deletions docs/guide/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ sidebarDepth: 2

# 托管 API 功能

[[toc]]

:::tip 提示
1. 请先参考 [文档](/guide/advance/api-gateway.md) 搭建托管 API
2. 该文档仅针对 now.sh 类型的部署
Expand Down
2 changes: 1 addition & 1 deletion lib/command/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class CheckCommand extends Command {
throw file;
}

const provider = getProvider(file);
const provider = getProvider(providerName, file);
const nodeList = await provider.getNodeList();

console.log(JSON.stringify(nodeList, null ,2));
Expand Down
4 changes: 3 additions & 1 deletion lib/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export async function generate(
let nodeConfigList: ReadonlyArray<PossibleNodeConfigType>;

try {
provider = getProvider(require(filePath));
provider = getProvider(providerName, require(filePath));
} catch (err) {
err.message = `处理 ${chalk.cyan(providerName)} 时出现错误,相关文件 ${filePath} ,错误原因: ${err.message}`;
throw err;
Expand Down Expand Up @@ -191,6 +191,7 @@ export async function generate(
nodeConfig.localPort = provider.nextPort;
}

nodeConfig.provider = provider;
nodeConfig.surgeConfig = config.surgeConfig;

if (provider.renameNode) {
Expand Down Expand Up @@ -253,6 +254,7 @@ export async function generate(
type: nodeConfig.type,
enable: nodeConfig.enable,
nodeName: nodeConfig.nodeName,
provider: nodeConfig.provider,
});
nodeList.push(nodeConfig);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/provider/BlackSSLProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export default class BlackSSLProvider extends Provider {
public readonly username: string;
public readonly password: string;

constructor(config: BlackSSLProviderConfig) {
super(config);
constructor(name: string, config: BlackSSLProviderConfig) {
super(name, config);

const schema = Joi.object({
username: Joi
Expand Down
4 changes: 2 additions & 2 deletions lib/provider/ClashProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ export default class ClashProvider extends Provider {
public readonly url: string;
public readonly udpRelay?: boolean;

constructor(config: ClashProviderConfig) {
super(config);
constructor(name: string, config: ClashProviderConfig) {
super(name, config);

const schema = Joi.object({
url: Joi
Expand Down
4 changes: 2 additions & 2 deletions lib/provider/CustomProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import Provider from './Provider';
export default class CustomProvider extends Provider {
public readonly nodeList: ReadonlyArray<any>;

constructor(config: CustomProviderConfig) {
super(config);
constructor(name: string, config: CustomProviderConfig) {
super(name, config);

const nodeSchema = Joi.object({
type: Joi.string()
Expand Down
2 changes: 1 addition & 1 deletion lib/provider/Provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default class Provider {
public readonly renameNode?: ProviderConfig['renameNode'];
private startPort?: number;

constructor(config: ProviderConfig) {
constructor(public name: string, config: ProviderConfig) {
const schema = Joi.object({
type: Joi.string()
.valid(...Object.values<string>(SupportProviderEnum))
Expand Down
4 changes: 2 additions & 2 deletions lib/provider/ShadowsocksJsonSubscribeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default class ShadowsocksJsonSubscribeProvider extends Provider {
public readonly url: string;
public readonly udpRelay?: boolean;

constructor(config: ShadowsocksJsonSubscribeProviderConfig) {
super(config);
constructor(name: string, config: ShadowsocksJsonSubscribeProviderConfig) {
super(name, config);

const schema = Joi.object({
url: Joi
Expand Down
4 changes: 2 additions & 2 deletions lib/provider/ShadowsocksSubscribeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default class ShadowsocksSubscribeProvider extends Provider {
public readonly url: string;
public readonly udpRelay?: boolean;

constructor(config: ShadowsocksSubscribeProviderConfig) {
super(config);
constructor(name: string, config: ShadowsocksSubscribeProviderConfig) {
super(name, config);

const schema = Joi.object({
url: Joi
Expand Down
4 changes: 2 additions & 2 deletions lib/provider/ShadowsocksrSubscribeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default class ShadowsocksrSubscribeProvider extends Provider {
public readonly url: string;
public readonly udpRelay?: boolean;

constructor(config: ShadowsocksrSubscribeProviderConfig) {
super(config);
constructor(name: string, config: ShadowsocksrSubscribeProviderConfig) {
super(name, config);

const schema = Joi.object({
url: Joi
Expand Down
4 changes: 2 additions & 2 deletions lib/provider/V2rayNSubscribeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import Provider from './Provider';
export default class V2rayNSubscribeProvider extends Provider {
public readonly url: string;

constructor(config: V2rayNSubscribeProviderConfig) {
super(config);
constructor(name: string, config: V2rayNSubscribeProviderConfig) {
super(name, config);

const schema = Joi.object({
url: Joi
Expand Down
3 changes: 2 additions & 1 deletion lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,16 +189,17 @@ export interface VmessNodeConfig extends SimpleNodeConfig {

export interface SimpleNodeConfig {
readonly type: NodeTypeEnum;
nodeName: string; // tslint:disable-line
readonly enable?: boolean;
// tslint:disable-next-line
tfo?: boolean; // TCP Fast Open
// tslint:disable-next-line
mptcp?: boolean; // Multi-Path TCP
nodeName: string; // tslint:disable-line
binPath?: string; // tslint:disable-line
localPort?: number; // tslint:disable-line
surgeConfig?: CommandConfig['surgeConfig']; // tslint:disable-line
hostnameIp?: ReadonlyArray<string>; // tslint:disable-line
provider?: Provider; // tslint:disable-line
}

export interface PlainObject { readonly [name: string]: any }
Expand Down
18 changes: 18 additions & 0 deletions lib/utils/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,24 @@ export const useRegexp = (regexp: RegExp): NodeNameFilterType => {
return item => regexp.test(item.nodeName);
};

export const useProviders = (keywords: ReadonlyArray<string>): NodeNameFilterType => {
// istanbul ignore next
if (!Array.isArray(keywords)) {
throw new Error('keywords 请使用数组');
}

return item => keywords.some(keyword => item?.provider?.name.includes(keyword));
};

export const discardProviders = (keywords: ReadonlyArray<string>): NodeNameFilterType => {
// istanbul ignore next
if (!Array.isArray(keywords)) {
throw new Error('keywords 请使用数组');
}

return item => !keywords.some(keyword => item?.provider?.name.includes(keyword));
};

export const useSortedKeywords = (keywords: ReadonlyArray<string>): SortedNodeNameFilterType => {
// istanbul ignore next
if (!Array.isArray(keywords)) {
Expand Down
16 changes: 8 additions & 8 deletions lib/utils/get-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,29 @@ import ShadowsocksSubscribeProvider from '../provider/ShadowsocksSubscribeProvid
import V2rayNSubscribeProvider from '../provider/V2rayNSubscribeProvider';
import { SupportProviderEnum } from '../types';

export default function(config: any): BlackSSLProvider|ShadowsocksJsonSubscribeProvider|ShadowsocksSubscribeProvider|CustomProvider|V2rayNSubscribeProvider|ShadowsocksrSubscribeProvider|ClashProvider {
export default function(name: string, config: any): BlackSSLProvider|ShadowsocksJsonSubscribeProvider|ShadowsocksSubscribeProvider|CustomProvider|V2rayNSubscribeProvider|ShadowsocksrSubscribeProvider|ClashProvider {
switch (config.type) {
case SupportProviderEnum.BlackSSL:
return new BlackSSLProvider(config);
return new BlackSSLProvider(name, config);

case SupportProviderEnum.ShadowsocksJsonSubscribe:
return new ShadowsocksJsonSubscribeProvider(config);
return new ShadowsocksJsonSubscribeProvider(name, config);

case SupportProviderEnum.ShadowsocksSubscribe:
return new ShadowsocksSubscribeProvider(config);
return new ShadowsocksSubscribeProvider(name, config);

case SupportProviderEnum.ShadowsocksrSubscribe:
return new ShadowsocksrSubscribeProvider(config);
return new ShadowsocksrSubscribeProvider(name, config);

case SupportProviderEnum.Custom: {
return new CustomProvider(config);
return new CustomProvider(name, config);
}

case SupportProviderEnum.V2rayNSubscribe:
return new V2rayNSubscribeProvider(config);
return new V2rayNSubscribeProvider(name, config);

case SupportProviderEnum.Clash:
return new ClashProvider(config);
return new ClashProvider(name, config);

default:
throw new Error(`Unsupported provider type: ${config.type}`);
Expand Down
1 change: 1 addition & 0 deletions test/fixture/custom-filter/surgio.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ module.exports = {
globalKeywordFilter: utils.useKeywords(['US 1']),
sortFilter: utils.useSortedKeywords(['🇺🇸US 2', '🇺🇸US 1']),
hkFirstUsSecondFilter: utils.mergeSortedFilters([utils.hkFilter, utils.usFilter]),
providerFilter: utils.useProviders(['custom']),
},
};
4 changes: 4 additions & 0 deletions test/fixture/custom-filter/template/test2.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@
{{ getNodeNames(nodeList, customFilters.hkFirstUsSecondFilter) }}
----
{{ getQuantumultXNodes(nodeList, customFilters.hkFirstUsSecondFilter) }}
----
{{ getNodeNames(nodeList, customFilters.providerFilter) }}
----
{{ getClashNodeNames(nodeList, customFilters.providerFilter) | json }}
6 changes: 5 additions & 1 deletion test/snapshots/cli.test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ Generated by [AVA](https://ava.li).
----␊
http://www.google.com/generate_204␊
----␊
http://example.com/template-functions.conf?access_token=abcd␊
https://example.com/template-functions.conf?access_token=abcd␊
`

## custom filter
Expand Down Expand Up @@ -436,4 +436,8 @@ Generated by [AVA](https://ava.li).
shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, tag=🇺🇸US 2␊
shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, tag=🇺🇸US 1␊
shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, udp-relay=true, fast-open=true, tag=🇺🇲 V03 US␊
----␊
🇭🇰 V01 HK 1, 🇭🇰 V01 HK 2, 🇺🇲 V03 US␊
----␊
["🇭🇰 V01 HK 1","🇭🇰 V01 HK 2","🇺🇲 V03 US"]␊
`
Binary file modified test/snapshots/cli.test.ts.snap
Binary file not shown.
34 changes: 34 additions & 0 deletions test/utils/filter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,40 @@ test('mergeFilters', t => {
});
});

test('useProviders', t => {
const fn = filter.useProviders(['测试', 'test']);

t.is(fn({
...generateVmessNode('test'),
provider: { name: '测试' }
} as any), true);
t.is(fn({
...generateVmessNode('test'),
provider: { name: 'test' }
} as any), true);
t.is(fn({
...generateVmessNode('test'),
provider: { name: 'other' }
} as any), false);
});

test('discardProviders', t => {
const fn = filter.discardProviders(['测试', 'test']);

t.is(fn({
...generateVmessNode('test'),
provider: { name: '测试' }
} as any), false);
t.is(fn({
...generateVmessNode('test'),
provider: { name: 'test' }
} as any), false);
t.is(fn({
...generateVmessNode('test'),
provider: { name: 'other' }
} as any), true);
});

function generateVmessNode(nodeName: string): VmessNodeConfig {
return {
type: NodeTypeEnum.Vmess,
Expand Down

0 comments on commit e11cb75

Please sign in to comment.