@swimmingliu/autovpn 1.6.2 → 1.6.4
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/dist/artifacts/list.js
CHANGED
|
@@ -8,6 +8,41 @@ function loadJson(filePath) {
|
|
|
8
8
|
}
|
|
9
9
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
10
10
|
}
|
|
11
|
+
function countNonEmptyLines(filePath) {
|
|
12
|
+
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return fs.readFileSync(filePath, 'utf8')
|
|
16
|
+
.split(/\r?\n/)
|
|
17
|
+
.map((line) => line.trim())
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.length;
|
|
20
|
+
}
|
|
21
|
+
function positiveNumber(value) {
|
|
22
|
+
const numeric = Number(value);
|
|
23
|
+
return Number.isFinite(numeric) && numeric > 0 ? numeric : 0;
|
|
24
|
+
}
|
|
25
|
+
function restoreArtifactCounts(artifactDir, counts = {}) {
|
|
26
|
+
const restored = { ...counts };
|
|
27
|
+
const fileCounts = [
|
|
28
|
+
['raw_links', 'vpn_node_raw.txt'],
|
|
29
|
+
['deduped_links', 'vpn_node_deduped.txt'],
|
|
30
|
+
['speedtest_links', 'vpn_node_speedtest.txt'],
|
|
31
|
+
['availability_links', 'vpn_node_availability.txt'],
|
|
32
|
+
['final_links', 'vpn_node_emoji.txt'],
|
|
33
|
+
['postprocess_links', 'vpn_node_emoji.txt']
|
|
34
|
+
];
|
|
35
|
+
for (const [countKey, fileName] of fileCounts) {
|
|
36
|
+
if (positiveNumber(restored[countKey]) > 0) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const fileCount = countNonEmptyLines(path.join(artifactDir, fileName));
|
|
40
|
+
if (fileCount && fileCount > 0) {
|
|
41
|
+
restored[countKey] = fileCount;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return restored;
|
|
45
|
+
}
|
|
11
46
|
function latestArtifactDir(artifactsRoot) {
|
|
12
47
|
if (!fs.existsSync(artifactsRoot)) {
|
|
13
48
|
return '';
|
|
@@ -37,7 +72,7 @@ export function artifactLatest(projectRoot, env = process.env) {
|
|
|
37
72
|
...payload,
|
|
38
73
|
run_status: report.run_status ?? '',
|
|
39
74
|
stage_status: report.stage_status ?? {},
|
|
40
|
-
counts: report.counts ?? {},
|
|
75
|
+
counts: restoreArtifactCounts(latest, (report.counts ?? {})),
|
|
41
76
|
source_counts: report.source_counts ?? {},
|
|
42
77
|
deployment: safeDeployment((report.deployment ?? {})),
|
|
43
78
|
error: redactText(String(report.error ?? ''))
|
|
@@ -88,7 +123,7 @@ export function artifactList(projectRoot, env = process.env) {
|
|
|
88
123
|
artifact_name: path.basename(artifactDir),
|
|
89
124
|
run_status: report.run_status ?? '',
|
|
90
125
|
stage_status: stageStatus,
|
|
91
|
-
counts: report.counts ?? {},
|
|
126
|
+
counts: restoreArtifactCounts(artifactDir, (report.counts ?? {})),
|
|
92
127
|
source_counts: report.source_counts ?? {},
|
|
93
128
|
retry_context: report.retry_context ?? {},
|
|
94
129
|
retryable_stages: retryableStages(artifactDir, stageStatus),
|
package/dist/doctor/checks.js
CHANGED
|
@@ -41,6 +41,21 @@ function commandPath(name, env, platform = process.platform) {
|
|
|
41
41
|
}
|
|
42
42
|
return '';
|
|
43
43
|
}
|
|
44
|
+
function firstExistingPath(candidates) {
|
|
45
|
+
return candidates.find((candidate) => candidate && fs.existsSync(candidate)) ?? '';
|
|
46
|
+
}
|
|
47
|
+
function mihomoInstallCandidates(env) {
|
|
48
|
+
const homeDir = String(env.HOME ?? env.USERPROFILE ?? '').trim();
|
|
49
|
+
return [
|
|
50
|
+
homeDir ? path.join(homeDir, 'clashctl', 'bin', 'mihomo') : '',
|
|
51
|
+
'/opt/homebrew/bin/mihomo',
|
|
52
|
+
'/usr/local/bin/mihomo',
|
|
53
|
+
'/usr/bin/mihomo'
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
function mihomoPath(env) {
|
|
57
|
+
return commandPath('mihomo', env) || firstExistingPath(mihomoInstallCandidates(env));
|
|
58
|
+
}
|
|
44
59
|
function safeRun(command, env) {
|
|
45
60
|
try {
|
|
46
61
|
const { executable, args } = normalizeManagedToolCommandForSpawn(command);
|
|
@@ -98,7 +113,7 @@ function loadProfile(profilePath) {
|
|
|
98
113
|
}
|
|
99
114
|
function checkProxyRuntime(env) {
|
|
100
115
|
const checks = [];
|
|
101
|
-
const mihomo =
|
|
116
|
+
const mihomo = mihomoPath(env);
|
|
102
117
|
if (!mihomo) {
|
|
103
118
|
checks.push(check('mihomo', 'fail', 'mihomo binary is missing'));
|
|
104
119
|
}
|
|
@@ -423,6 +423,30 @@ export async function runNodePipeline(options, context = {}) {
|
|
|
423
423
|
const limitAvailability = createLimiter(Number(speedConfig.concurrency ?? 1));
|
|
424
424
|
let speedCompleted = 0;
|
|
425
425
|
let availabilityCompleted = 0;
|
|
426
|
+
let speedArtifactFlush = Promise.resolve();
|
|
427
|
+
let availabilityArtifactFlush = Promise.resolve();
|
|
428
|
+
const flushStreamingSpeedArtifacts = async () => {
|
|
429
|
+
const resultSnapshot = [...speedResults];
|
|
430
|
+
const linkSnapshot = [...passedSpeedLinks];
|
|
431
|
+
speedArtifactFlush = speedArtifactFlush.catch(() => undefined).then(async () => {
|
|
432
|
+
summary.counts.speedtest_links = linkSnapshot.length;
|
|
433
|
+
await writeLines(artifactDir, 'vpn_node_speedtest.txt', linkSnapshot);
|
|
434
|
+
await writeJson(artifactDir, 'vpn_node_speedtest_report.json', resultSnapshot);
|
|
435
|
+
await writeReport();
|
|
436
|
+
});
|
|
437
|
+
await speedArtifactFlush;
|
|
438
|
+
};
|
|
439
|
+
const flushStreamingAvailabilityArtifacts = async () => {
|
|
440
|
+
const resultSnapshot = [...availabilityResults];
|
|
441
|
+
const linkSnapshot = resultSnapshot.filter((result) => result.all_passed).map((result) => result.link);
|
|
442
|
+
availabilityArtifactFlush = availabilityArtifactFlush.catch(() => undefined).then(async () => {
|
|
443
|
+
summary.counts.availability_links = linkSnapshot.length;
|
|
444
|
+
await writeLines(artifactDir, 'vpn_node_availability.txt', linkSnapshot);
|
|
445
|
+
await writeJson(artifactDir, 'vpn_node_availability_report.json', resultSnapshot);
|
|
446
|
+
await writeReport();
|
|
447
|
+
});
|
|
448
|
+
await availabilityArtifactFlush;
|
|
449
|
+
};
|
|
426
450
|
const runStreamingAvailability = (speedResult) => {
|
|
427
451
|
const task = limitAvailability(async () => {
|
|
428
452
|
const results = context.stages?.availability
|
|
@@ -436,15 +460,14 @@ export async function runNodePipeline(options, context = {}) {
|
|
|
436
460
|
for (const result of results) {
|
|
437
461
|
availabilityResults.push(result);
|
|
438
462
|
availabilityCompleted += 1;
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
}
|
|
463
|
+
await flushStreamingAvailabilityArtifacts();
|
|
464
|
+
emit('availability_link_result', {
|
|
465
|
+
completed: availabilityCompleted,
|
|
466
|
+
total: passedSpeedLinks.length,
|
|
467
|
+
link: result.link,
|
|
468
|
+
all_passed: result.all_passed,
|
|
469
|
+
provider_results: result.provider_results
|
|
470
|
+
});
|
|
448
471
|
}
|
|
449
472
|
});
|
|
450
473
|
availabilityTasks.push(task);
|
|
@@ -476,8 +499,12 @@ export async function runNodePipeline(options, context = {}) {
|
|
|
476
499
|
});
|
|
477
500
|
if (passed) {
|
|
478
501
|
passedSpeedLinks.push(result.link);
|
|
502
|
+
await flushStreamingSpeedArtifacts();
|
|
479
503
|
runStreamingAvailability(result);
|
|
480
504
|
}
|
|
505
|
+
else if (useStreamingStages) {
|
|
506
|
+
await flushStreamingSpeedArtifacts();
|
|
507
|
+
}
|
|
481
508
|
});
|
|
482
509
|
speedTasks.push(task);
|
|
483
510
|
task.catch(() => undefined);
|
|
@@ -178,10 +178,36 @@ async function closeChildProcess(process) {
|
|
|
178
178
|
process.kill('SIGTERM');
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
|
-
async function
|
|
181
|
+
async function fileExists(candidate) {
|
|
182
|
+
try {
|
|
183
|
+
const info = await stat(candidate);
|
|
184
|
+
return info.isFile();
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function firstExistingFile(candidates) {
|
|
191
|
+
for (const candidate of candidates) {
|
|
192
|
+
if (candidate && await fileExists(candidate)) {
|
|
193
|
+
return candidate;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return '';
|
|
197
|
+
}
|
|
198
|
+
function mihomoInstallCandidates(env = process.env) {
|
|
199
|
+
const homeDir = String(env.HOME ?? env.USERPROFILE ?? '').trim();
|
|
200
|
+
return [
|
|
201
|
+
homeDir ? path.join(homeDir, 'clashctl', 'bin', 'mihomo') : '',
|
|
202
|
+
'/opt/homebrew/bin/mihomo',
|
|
203
|
+
'/usr/local/bin/mihomo',
|
|
204
|
+
'/usr/bin/mihomo'
|
|
205
|
+
];
|
|
206
|
+
}
|
|
207
|
+
async function resolveMihomoCommand(runtimePath, env = process.env) {
|
|
182
208
|
const candidate = String(runtimePath ?? '').trim();
|
|
183
209
|
if (!candidate) {
|
|
184
|
-
return 'mihomo';
|
|
210
|
+
return await firstExistingFile(mihomoInstallCandidates(env)) || 'mihomo';
|
|
185
211
|
}
|
|
186
212
|
try {
|
|
187
213
|
const info = await stat(candidate);
|
|
@@ -189,12 +215,12 @@ async function resolveMihomoCommand(runtimePath) {
|
|
|
189
215
|
return candidate;
|
|
190
216
|
}
|
|
191
217
|
if (info.isDirectory() && path.basename(candidate) === 'runtime') {
|
|
192
|
-
return 'mihomo';
|
|
218
|
+
return await firstExistingFile(mihomoInstallCandidates(env)) || 'mihomo';
|
|
193
219
|
}
|
|
194
220
|
}
|
|
195
221
|
catch {
|
|
196
222
|
if (path.basename(candidate) === 'runtime') {
|
|
197
|
-
return 'mihomo';
|
|
223
|
+
return await firstExistingFile(mihomoInstallCandidates(env)) || 'mihomo';
|
|
198
224
|
}
|
|
199
225
|
}
|
|
200
226
|
return candidate;
|
|
@@ -214,7 +240,7 @@ export async function openMihomoRuntime(link, options = {}) {
|
|
|
214
240
|
const tempDir = await mkdtemp(path.join(os.tmpdir(), 'autovpn-mihomo-'));
|
|
215
241
|
const configPath = path.join(tempDir, 'config.json');
|
|
216
242
|
await writeFile(configPath, JSON.stringify(config), 'utf8');
|
|
217
|
-
const command = await resolveMihomoCommand(options.runtimePath);
|
|
243
|
+
const command = await resolveMihomoCommand(options.runtimePath, options.env ?? process.env);
|
|
218
244
|
const child = (options.spawn ?? defaultSpawn)(command, ['-f', configPath], {
|
|
219
245
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
220
246
|
env: stripProxyEnv(options.env ?? process.env)
|