Skip to content

Commit 4d88419

Browse files
committed
feat: Add BaseConfigBuilder class for building configuration
1 parent f2b31bc commit 4d88419

5 files changed

+376
-354
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"wrangler": "^3.60.3"
1515
},
1616
"dependencies": {
17-
"js-yaml": "^4.1.0"
17+
"js-yaml": "^4.1.0",
18+
"sublink-plus": "file:"
1819
}
1920
}

src/BaseConfigBuilder.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { ProxyParser } from './ProxyParsers.js';
2+
import { DeepCopy } from './utils.js';
3+
4+
export class BaseConfigBuilder {
5+
constructor(inputString, baseConfig) {
6+
this.inputString = inputString;
7+
this.config = DeepCopy(baseConfig);
8+
}
9+
10+
async build() {
11+
const customItems = await this.parseCustomItems();
12+
this.addCustomItems(customItems);
13+
this.addSelectors();
14+
return this.formatConfig();
15+
}
16+
17+
async parseCustomItems() {
18+
const urls = this.inputString.split('\n').filter(url => url.trim() !== '');
19+
const parsedItems = [];
20+
21+
for (const url of urls) {
22+
const result = await ProxyParser.parse(url);
23+
if (Array.isArray(result)) {
24+
for (const subUrl of result) {
25+
const subResult = await ProxyParser.parse(subUrl);
26+
if (subResult) {
27+
parsedItems.push(subResult);
28+
}
29+
}
30+
} else if (result) {
31+
parsedItems.push(result);
32+
}
33+
}
34+
35+
return parsedItems;
36+
}
37+
38+
addCustomItems(customItems) {
39+
// This method should be implemented in child classes
40+
throw new Error('addCustomItems must be implemented in child class');
41+
}
42+
43+
addSelectors() {
44+
// This method should be implemented in child classes
45+
throw new Error('addSelectors must be implemented in child class');
46+
}
47+
48+
formatConfig() {
49+
// This method should be implemented in child classes
50+
throw new Error('formatConfig must be implemented in child class');
51+
}
52+
}

src/ClashConfigBuilder.js

+23-46
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,23 @@
11
import yaml from 'js-yaml';
2-
import { ProxyParser } from './ProxyParsers.js';
32
import { CLASH_CONFIG, SELECTORS_LIST } from './config.js';
3+
import { BaseConfigBuilder } from './BaseConfigBuilder.js';
44
import { DeepCopy } from './utils.js';
55

6-
export class ClashConfigBuilder {
6+
export class ClashConfigBuilder extends BaseConfigBuilder {
77
constructor(inputString) {
8-
this.inputString = inputString;
9-
this.config = DeepCopy(CLASH_CONFIG);
8+
super(inputString, CLASH_CONFIG);
109
}
1110

12-
async build() {
13-
const customProxies = await this.parseCustomProxies();
14-
this.addCustomProxies(customProxies);
15-
return yaml.dump(this.config);
16-
}
17-
18-
async parseCustomProxies() {
19-
const urls = this.inputString.split('\n').filter(url => url.trim() !== '');
20-
const parsedProxies = [];
21-
22-
for (const url of urls) {
23-
const result = await ProxyParser.parse(url);
24-
if (Array.isArray(result)) {
25-
// If the result is an array, it's from an HTTP(S) source
26-
for (const subUrl of result) {
27-
const subResult = await ProxyParser.parse(subUrl);
28-
if (subResult) {
29-
parsedProxies.push(subResult);
30-
}
31-
}
32-
} else if (result) {
33-
parsedProxies.push(result);
11+
addCustomItems(customItems) {
12+
customItems.forEach(item => {
13+
if (item?.tag && !this.config.proxies.some(p => p.name === item.tag)) {
14+
this.config.proxies.push(this.convertToClashProxy(item));
3415
}
35-
}
36-
37-
return parsedProxies;
16+
});
3817
}
3918

40-
addCustomProxies(customProxies) {
41-
customProxies.forEach(proxy => {
42-
if (proxy?.tag && !this.config.proxies.some(p => p.name === proxy.tag)) {
43-
this.config.proxies.push(this.convertToClashProxy(proxy));
44-
}
45-
});
46-
const proxyList = customProxies.filter(proxy => proxy?.tag !== undefined).map(proxy => proxy?.tag);
19+
addSelectors() {
20+
const proxyList = this.config.proxies.map(proxy => proxy.name);
4721
this.config['proxy-groups'].push({
4822
name: '⚡ 自动选择',
4923
type: 'url-test',
@@ -53,17 +27,20 @@ export class ClashConfigBuilder {
5327
lazy: false
5428
});
5529
proxyList.unshift('DIRECT', 'REJECT', '⚡ 自动选择');
56-
SELECTORS_LIST.forEach(selector => {
57-
if (!this.config['proxy-groups'].some(g => g.name === selector)) {
58-
this.config['proxy-groups'].push({
59-
type: "select",
60-
name: selector,
61-
proxies: selector !== '🚀 节点选择' ? ['🚀 节点选择', ...proxyList] : proxyList
62-
});
63-
}
64-
});
65-
}
30+
SELECTORS_LIST.forEach(selector => {
31+
if (!this.config['proxy-groups'].some(g => g.name === selector)) {
32+
this.config['proxy-groups'].push({
33+
type: "select",
34+
name: selector,
35+
proxies: selector !== '🚀 节点选择' ? ['🚀 节点选择', ...proxyList] : proxyList
36+
});
37+
}
38+
});
39+
}
6640

41+
formatConfig() {
42+
return yaml.dump(this.config);
43+
}
6744
convertToClashProxy(proxy) {
6845
switch(proxy.type) {
6946
case 'shadowsocks':

src/SingboxConfigBuilder.js

+20-47
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,35 @@
11
import { SING_BOX_CONFIG, SELECTORS_LIST } from './config.js';
2-
import { ProxyParser } from './ProxyParsers.js';
2+
import { BaseConfigBuilder } from './BaseConfigBuilder.js';
33
import { DeepCopy } from './utils.js';
44

5-
export class ConfigBuilder {
5+
export class ConfigBuilder extends BaseConfigBuilder {
66
constructor(inputString) {
7-
this.inputString = inputString;
8-
this.config = DeepCopy(SING_BOX_CONFIG);
7+
super(inputString, SING_BOX_CONFIG);
98
}
109

11-
async build() {
12-
const customOutbounds = await this.parseCustomOutbounds();
13-
this.addCustomOutbounds(customOutbounds);
14-
this.addSelectors();
15-
return this.config;
16-
}
17-
18-
async parseCustomOutbounds() {
19-
const urls = this.inputString.split('\n').filter(url => url.trim() !== '');
20-
const parsedOutbounds = [];
21-
22-
for (const url of urls) {
23-
const result = await ProxyParser.parse(url);
24-
if (Array.isArray(result)) {
25-
// If the result is an array, it's from an HTTP(S) source
26-
for (const subUrl of result) {
27-
const subResult = await ProxyParser.parse(subUrl);
28-
if (subResult) {
29-
parsedOutbounds.push(subResult);
30-
}
31-
}
32-
} else if (result) {
33-
parsedOutbounds.push(result);
34-
}
35-
}
36-
37-
return parsedOutbounds;
38-
}
39-
40-
addCustomOutbounds(customOutbounds) {
41-
// Filter out null values before adding to config.outbounds
42-
const validOutbounds = customOutbounds.filter(outbound => outbound != null);
43-
this.config.outbounds.push(...validOutbounds);
10+
addCustomItems(customItems) {
11+
const validItems = customItems.filter(item => item != null);
12+
this.config.outbounds.push(...validItems);
4413
}
4514

46-
addSelectors() {
47-
const tagList = this.config.outbounds.filter(outbound => outbound?.server != undefined).map(outbound => outbound.tag);
15+
addSelectors() {
16+
const tagList = this.config.outbounds.filter(outbound => outbound?.server != undefined).map(outbound => outbound.tag);
4817
this.config.outbounds.push({
4918
type: "urltest",
5019
tag: "⚡ 自动选择",
5120
outbounds: DeepCopy(tagList),
5221
});
5322
tagList.unshift('DIRECT', 'REJECT', '⚡ 自动选择');
54-
SELECTORS_LIST.forEach(selector => {
55-
this.config.outbounds.push({
56-
type: "selector",
57-
tag: selector,
58-
outbounds: selector !== '🚀 节点选择' ? ['🚀 节点选择', ...tagList] : tagList
59-
});
60-
});
61-
}
23+
SELECTORS_LIST.forEach(selector => {
24+
this.config.outbounds.push({
25+
type: "selector",
26+
tag: selector,
27+
outbounds: selector !== '🚀 节点选择' ? ['🚀 节点选择', ...tagList] : tagList
28+
});
29+
});
30+
}
31+
32+
formatConfig() {
33+
return this.config;
34+
}
6235
}

0 commit comments

Comments
 (0)