@lancewu602/mihomo-dash 0.0.0-stage → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +99 -2
- package/bin/mihomo-dash.js +4 -0
- package/package.json +63 -4
- package/server/CHANGELOG.md +51 -0
- package/server/package.json +13 -0
- package/server/src/cli/index.js +75 -0
- package/server/src/cli/service.js +167 -0
- package/server/src/cli/status.js +245 -0
- package/server/src/http/config-files.js +148 -0
- package/server/src/http/config-order.js +186 -0
- package/server/src/http/config-sections.js +278 -0
- package/server/src/http/default-config.js +69 -0
- package/server/src/http/groups.js +386 -0
- package/server/src/http/index.js +260 -0
- package/server/src/http/kernel-admin.js +522 -0
- package/server/src/http/kernel-proxy.js +43 -0
- package/server/src/http/providers.js +251 -0
- package/server/src/http/rules.js +509 -0
- package/server/src/http/settings.js +409 -0
- package/server/src/http/system-proxy.js +86 -0
- package/server/src/index.js +26 -0
- package/server/src/kernel/archive.js +181 -0
- package/server/src/kernel/binary.js +33 -0
- package/server/src/kernel/client.js +138 -0
- package/server/src/kernel/install.js +150 -0
- package/server/src/kernel/lifecycle.js +339 -0
- package/server/src/kernel/run.js +11 -0
- package/server/src/shared/args.js +57 -0
- package/server/src/shared/atomic-file.js +41 -0
- package/server/src/shared/exec.js +44 -0
- package/server/src/shared/kernel-config.js +27 -0
- package/server/src/shared/log-file.js +92 -0
- package/server/src/shared/panel.js +58 -0
- package/server/src/shared/paths.js +72 -0
- package/server/src/shared/service.js +552 -0
- package/server/src/shared/system-proxy.js +375 -0
- package/server/src/shared/text.js +11 -0
- package/server/tests/cli-service.test.js +153 -0
- package/server/tests/config-dir.test.js +133 -0
- package/server/tests/config-order.test.js +148 -0
- package/server/tests/groups.test.js +558 -0
- package/server/tests/kernel-admin.test.js +647 -0
- package/server/tests/kernel.test.js +250 -0
- package/server/tests/log-file.test.js +110 -0
- package/server/tests/providers.test.js +259 -0
- package/server/tests/rules.test.js +463 -0
- package/server/tests/service.test.js +470 -0
- package/server/tests/settings.test.js +456 -0
- package/server/tests/status.test.js +269 -0
- package/server/tests/system-proxy.test.js +497 -0
- package/server/tsconfig.json +17 -0
- package/web/dist/assets/index-BpDzYhuI.css +1 -0
- package/web/dist/assets/index-WmujD2EM.js +515 -0
- package/web/dist/favicon.svg +5 -0
- package/web/dist/index.html +14 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config.yaml 顶层键排序(server/src/http/config-order.js + config-files.js 的写入路径)测试。
|
|
3
|
+
*
|
|
4
|
+
* 断言的是「只搬位置、不改内容」:键下面的内容、行尾注释、键上方紧贴的说明、文件头注释都得保住,
|
|
5
|
+
* 块与块之间不留空行;排序结果必须幂等、解析出来跟原文一模一样。
|
|
6
|
+
* 运行:npm test
|
|
7
|
+
*/
|
|
8
|
+
import assert from 'node:assert/strict';
|
|
9
|
+
import { after, before, test } from 'node:test';
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import http from 'node:http';
|
|
12
|
+
import os from 'node:os';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import yaml from 'js-yaml';
|
|
15
|
+
|
|
16
|
+
/** @type {Record<string, any>} */ let mods = {};
|
|
17
|
+
/** @type {string} */ let tmpDir;
|
|
18
|
+
/** @type {string} */ let cfgDir;
|
|
19
|
+
/** @type {import('node:http').Server} */ let kernel;
|
|
20
|
+
/** @type {number} */ let stubPort = 0;
|
|
21
|
+
|
|
22
|
+
const configPath = () => path.join(cfgDir, 'config.yaml');
|
|
23
|
+
const readConfig = () => fs.readFileSync(configPath(), 'utf8');
|
|
24
|
+
const writeConfig = (text) => fs.writeFileSync(configPath(), text);
|
|
25
|
+
/** 桩内核的地址也得写进配置(代码只认 config.yaml 的 external-controller) */
|
|
26
|
+
|
|
27
|
+
before(async () => {
|
|
28
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mihomo-dash-order-'));
|
|
29
|
+
cfgDir = path.join(tmpDir, 'mihomo');
|
|
30
|
+
fs.mkdirSync(cfgDir, { recursive: true });
|
|
31
|
+
|
|
32
|
+
kernel = http.createServer((_req, res) => {
|
|
33
|
+
res.writeHead(200, { 'content-type': 'application/json' });
|
|
34
|
+
res.end('{}');
|
|
35
|
+
});
|
|
36
|
+
await new Promise((resolve) => kernel.listen(0, '127.0.0.1', resolve));
|
|
37
|
+
stubPort = kernel.address().port;
|
|
38
|
+
|
|
39
|
+
process.env.MIHOMO_DIR = cfgDir;
|
|
40
|
+
process.env.MIHOMO_DASH_DIR = path.join(tmpDir, 'cli');
|
|
41
|
+
mods = { order: await import('../src/http/config-order.js') };
|
|
42
|
+
mods.files = await import('../src/http/config-files.js');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
after(async () => {
|
|
46
|
+
await new Promise((resolve) => kernel.close(resolve));
|
|
47
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('乱序的顶层键排成固定顺序;内容、注释、缩进一字不改,块之间不留空行', () => {
|
|
51
|
+
const src = `unified-delay: false
|
|
52
|
+
geox-url:
|
|
53
|
+
geosite: "https://x/geosite.dat"
|
|
54
|
+
geoip: "https://x/geoip.dat"
|
|
55
|
+
geo-update-interval: 12
|
|
56
|
+
geodata-mode: true
|
|
57
|
+
mixed-port: 7890
|
|
58
|
+
# 运行模式
|
|
59
|
+
mode: rule
|
|
60
|
+
log-level: warning # 行尾注释也要留着
|
|
61
|
+
external-controller: 127.0.0.1:8190
|
|
62
|
+
ipv6: true
|
|
63
|
+
|
|
64
|
+
# ===== 规则 =====
|
|
65
|
+
rules:
|
|
66
|
+
- MATCH,DIRECT
|
|
67
|
+
`;
|
|
68
|
+
assert.equal(
|
|
69
|
+
mods.order.orderTopLevel(src),
|
|
70
|
+
`mixed-port: 7890
|
|
71
|
+
ipv6: true
|
|
72
|
+
# 运行模式
|
|
73
|
+
mode: rule
|
|
74
|
+
log-level: warning # 行尾注释也要留着
|
|
75
|
+
unified-delay: false
|
|
76
|
+
external-controller: 127.0.0.1:8190
|
|
77
|
+
geodata-mode: true
|
|
78
|
+
geo-update-interval: 12
|
|
79
|
+
geox-url:
|
|
80
|
+
geosite: "https://x/geosite.dat"
|
|
81
|
+
geoip: "https://x/geoip.dat"
|
|
82
|
+
# ===== 规则 =====
|
|
83
|
+
rules:
|
|
84
|
+
- MATCH,DIRECT
|
|
85
|
+
`,
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('幂等,且解析结果与原文完全一致(排序只是排版)', () => {
|
|
90
|
+
const src = `rules:\n - MATCH,DIRECT\nmixed-port: 7890\nunified-delay: true\ndns:\n enable: true\n`;
|
|
91
|
+
const once = mods.order.orderTopLevel(src);
|
|
92
|
+
assert.equal(mods.order.orderTopLevel(once), once);
|
|
93
|
+
assert.deepEqual(yaml.load(once), yaml.load(src));
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('文件头注释留在最上面;面板不认识的键排在 rules 前面,保持相对顺序', () => {
|
|
97
|
+
const src = `# 我的配置\n# 第二行\n\naaa-unknown: 1\nproxy-providers:\n p:\n url: x\nbbb-unknown: 2\nrules:\n - MATCH,DIRECT\n`;
|
|
98
|
+
assert.equal(
|
|
99
|
+
mods.order.orderTopLevel(src),
|
|
100
|
+
`# 我的配置\n# 第二行\nproxy-providers:\n p:\n url: x\naaa-unknown: 1\nbbb-unknown: 2\nrules:\n - MATCH,DIRECT\n`,
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('块之间不留空行:原文分了块的也压成紧凑写法,块内部空行不动', () => {
|
|
105
|
+
assert.equal(
|
|
106
|
+
mods.order.orderTopLevel('rules:\n - MATCH,DIRECT\n\nmixed-port: 7890\n\nmode: rule\n'),
|
|
107
|
+
'mixed-port: 7890\nmode: rule\nrules:\n - MATCH,DIRECT\n',
|
|
108
|
+
);
|
|
109
|
+
// 段落里面自己留的空行(这里 dns 内部)不算块间分隔,原样保留
|
|
110
|
+
assert.equal(
|
|
111
|
+
mods.order.orderTopLevel('# 头\n\ndns:\n enable: true\n\n ipv6: false\nmixed-port: 7890\n'),
|
|
112
|
+
'# 头\nmixed-port: 7890\ndns:\n enable: true\n\n ipv6: false\n',
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('没有顶层键 / 空文件:原样返回,不抛错', () => {
|
|
117
|
+
assert.equal(mods.order.orderTopLevel(''), '');
|
|
118
|
+
assert.equal(mods.order.orderTopLevel('# 只有注释\n'), '# 只有注释\n');
|
|
119
|
+
assert.equal(mods.order.orderTopLevel('proxies:\n'), 'proxies:\n');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('安全网:解析结果对不上时放弃排序,绝不拿用户文件冒险', () => {
|
|
123
|
+
// 同名顶层键在 YAML 里是错的(js-yaml 直接报错):排序应当被跳过,文件原样写回去
|
|
124
|
+
const dup = 'mixed-port: 7890\nrules:\n - MATCH,DIRECT\nmixed-port: 1\n';
|
|
125
|
+
assert.equal(mods.files.orderedConfigText(dup), dup);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('写盘路径:saveFile(配置文件页)排 config.yaml,不排 providers/*.yaml', () => {
|
|
129
|
+
writeConfig('rules:\n - MATCH,DIRECT\nmixed-port: 7890\n');
|
|
130
|
+
mods.files.saveFile('config.yaml', readConfig());
|
|
131
|
+
assert.equal(readConfig(), 'mixed-port: 7890\nrules:\n - MATCH,DIRECT\n');
|
|
132
|
+
|
|
133
|
+
const prov = path.join(cfgDir, 'providers');
|
|
134
|
+
fs.mkdirSync(prov, { recursive: true });
|
|
135
|
+
fs.writeFileSync(path.join(prov, 'p.yaml'), 'proxies: []\n');
|
|
136
|
+
mods.files.saveFile('providers/p.yaml', 'proxies: []\n');
|
|
137
|
+
assert.equal(fs.readFileSync(path.join(prov, 'p.yaml'), 'utf8'), 'proxies: []\n');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test('写盘路径:saveConfigWithReload(GEO 键走的那条)也会排序 + 发重载请求', async () => {
|
|
141
|
+
await mods.files.saveConfigWithReload(
|
|
142
|
+
`rules:\n - MATCH,DIRECT\nexternal-controller: 127.0.0.1:${stubPort}\n`,
|
|
143
|
+
);
|
|
144
|
+
assert.equal(
|
|
145
|
+
readConfig(),
|
|
146
|
+
`external-controller: 127.0.0.1:${stubPort}\nrules:\n - MATCH,DIRECT\n`,
|
|
147
|
+
);
|
|
148
|
+
});
|