panrouter 5.4.0 → 5.4.2
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/package.json +1 -1
- package/pool-worker.mjs +81 -14
package/package.json
CHANGED
package/pool-worker.mjs
CHANGED
|
@@ -74,6 +74,7 @@ const FINGERPRINT = getFingerprint();
|
|
|
74
74
|
const DEVICE_TYPE = detectDeviceType();
|
|
75
75
|
const SERVER_PORT = 50816;
|
|
76
76
|
const PID_FILE = path.join(os.tmpdir(), "panrouter-pool-worker.pid");
|
|
77
|
+
const RUNTIME_DIR = path.join(HOME_DIR, ".panrouter-runtime");
|
|
77
78
|
|
|
78
79
|
// ─── 重连参数 ────────────────────────────────────────────────────────────────
|
|
79
80
|
const WS_RECONNECT_BASE = 1000;
|
|
@@ -177,7 +178,7 @@ function scheduleReconnect() {
|
|
|
177
178
|
|
|
178
179
|
function handleUpgrade() {
|
|
179
180
|
log("收到主控升级指令,开始升级...", "WARN");
|
|
180
|
-
//
|
|
181
|
+
// 断开连接
|
|
181
182
|
if (ws) {
|
|
182
183
|
try { ws.close(1000, "Upgrading"); } catch {}
|
|
183
184
|
ws = null;
|
|
@@ -192,17 +193,23 @@ function handleUpgrade() {
|
|
|
192
193
|
log(`升级失败: ${e.message},仍尝试重启`, "ERR");
|
|
193
194
|
}
|
|
194
195
|
|
|
195
|
-
//
|
|
196
|
-
|
|
196
|
+
// 写 PID 文件让新进程可追踪(旧 PID 文件被 cleanupStaleSelf 覆盖)
|
|
197
|
+
try {
|
|
198
|
+
if (!fs.existsSync(RUNTIME_DIR)) fs.mkdirSync(RUNTIME_DIR, { recursive: true });
|
|
199
|
+
fs.writeFileSync(PID_FILE, String(process.pid), "utf-8");
|
|
200
|
+
} catch {}
|
|
201
|
+
|
|
202
|
+
// 清理旧的 server.mjs,确保新实例用最新代码
|
|
203
|
+
log("正在重启代理服务...");
|
|
204
|
+
killPort(SERVER_PORT);
|
|
205
|
+
|
|
206
|
+
// 启动新实例,在当前终端前台运行
|
|
197
207
|
const child = spawn(process.execPath, [process.argv[1], "--pool"], {
|
|
198
208
|
cwd: __dirname,
|
|
199
|
-
stdio: "
|
|
200
|
-
detached: true,
|
|
201
|
-
windowsHide: true,
|
|
209
|
+
stdio: "inherit",
|
|
202
210
|
});
|
|
203
|
-
child.unref();
|
|
204
211
|
|
|
205
|
-
log("
|
|
212
|
+
log("新实例已在后台启动", "OFF");
|
|
206
213
|
process.exit(0);
|
|
207
214
|
}
|
|
208
215
|
|
|
@@ -296,6 +303,39 @@ function stopHeartbeat() {
|
|
|
296
303
|
}
|
|
297
304
|
}
|
|
298
305
|
|
|
306
|
+
// ─── 端口清理 ────────────────────────────────────────────────────────────────
|
|
307
|
+
|
|
308
|
+
function killPort(port) {
|
|
309
|
+
if (process.platform === 'win32') {
|
|
310
|
+
try {
|
|
311
|
+
const out = execSync(`netstat -ano | findstr :${port}`, { stdio: 'pipe', timeout: 3000 }).toString();
|
|
312
|
+
const lines = out.split('\n').filter(l => l.includes('LISTENING'));
|
|
313
|
+
for (const line of lines) {
|
|
314
|
+
const parts = line.trim().split(/\s+/);
|
|
315
|
+
const pid = parts[parts.length - 1];
|
|
316
|
+
if (pid && pid !== '0') {
|
|
317
|
+
try { execSync(`taskkill /F /PID ${pid}`, { stdio: 'pipe' }); log(`已终止端口 ${port} 上的进程 PID ${pid}`, "OK"); } catch {}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
} catch {}
|
|
321
|
+
} else {
|
|
322
|
+
try {
|
|
323
|
+
execSync(`lsof -ti:${port} | xargs -r kill -9 2>/dev/null`, { stdio: 'pipe' });
|
|
324
|
+
} catch {}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function killPid(pid) {
|
|
329
|
+
if (!pid) return;
|
|
330
|
+
try {
|
|
331
|
+
if (process.platform === 'win32') {
|
|
332
|
+
execSync(`taskkill /F /PID ${pid}`, { stdio: 'pipe', timeout: 3000 });
|
|
333
|
+
} else {
|
|
334
|
+
try { process.kill(parseInt(pid), 9); } catch {}
|
|
335
|
+
}
|
|
336
|
+
} catch {}
|
|
337
|
+
}
|
|
338
|
+
|
|
299
339
|
// ─── 检查端口 ────────────────────────────────────────────────────────────────
|
|
300
340
|
|
|
301
341
|
function isPortOpen(port) {
|
|
@@ -310,9 +350,16 @@ function isPortOpen(port) {
|
|
|
310
350
|
// ─── 确保 server.mjs 在运行 ──────────────────────────────────────────────
|
|
311
351
|
|
|
312
352
|
async function ensureServer() {
|
|
353
|
+
// 不管端口是否被占用,都先杀掉确保用最新代码启动
|
|
354
|
+
// 这是因为 cleanupStaleSelf 可能没清干净,或者旧版 server 残留
|
|
313
355
|
if (await isPortOpen(SERVER_PORT)) {
|
|
314
|
-
log(`端口 ${SERVER_PORT}
|
|
315
|
-
|
|
356
|
+
log(`端口 ${SERVER_PORT} 已被占用,正在释放...`, "WARN");
|
|
357
|
+
killPort(SERVER_PORT);
|
|
358
|
+
// 等端口真正释放
|
|
359
|
+
for (let i = 0; i < 10; i++) {
|
|
360
|
+
if (!(await isPortOpen(SERVER_PORT))) break;
|
|
361
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
362
|
+
}
|
|
316
363
|
}
|
|
317
364
|
|
|
318
365
|
const serverPath = path.join(__dirname, "server.mjs");
|
|
@@ -346,10 +393,28 @@ async function ensureServer() {
|
|
|
346
393
|
|
|
347
394
|
function writePid() {
|
|
348
395
|
try {
|
|
396
|
+
if (!fs.existsSync(RUNTIME_DIR)) fs.mkdirSync(RUNTIME_DIR, { recursive: true });
|
|
349
397
|
fs.writeFileSync(PID_FILE, String(process.pid), "utf-8");
|
|
350
398
|
} catch {}
|
|
351
399
|
}
|
|
352
400
|
|
|
401
|
+
// ─── 清理之前的 pool-worker 实例 ──────────────────────────────────────────
|
|
402
|
+
|
|
403
|
+
function cleanupStaleSelf() {
|
|
404
|
+
// 1. 检查 PID 文件
|
|
405
|
+
try {
|
|
406
|
+
if (fs.existsSync(PID_FILE)) {
|
|
407
|
+
const oldPid = fs.readFileSync(PID_FILE, "utf-8").trim();
|
|
408
|
+
if (oldPid && String(process.pid) !== oldPid) {
|
|
409
|
+
log(`发现之前的 pool-worker (PID ${oldPid}),正在清理...`, "WARN");
|
|
410
|
+
killPid(oldPid);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
} catch {}
|
|
414
|
+
// 2. 清理端口 50816(确保 server.mjs 会以最新版本重启)
|
|
415
|
+
killPort(SERVER_PORT);
|
|
416
|
+
}
|
|
417
|
+
|
|
353
418
|
// ─── 优雅退出 ────────────────────────────────────────────────────────────────
|
|
354
419
|
|
|
355
420
|
function gracefulShutdown() {
|
|
@@ -370,11 +435,10 @@ function gracefulShutdown() {
|
|
|
370
435
|
}
|
|
371
436
|
|
|
372
437
|
try { fs.unlinkSync(PID_FILE); } catch {}
|
|
438
|
+
killPort(SERVER_PORT);
|
|
373
439
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
process.exit(0);
|
|
377
|
-
}, 500);
|
|
440
|
+
log("节点已安全下线,再见!", "OFF");
|
|
441
|
+
process.exit(0);
|
|
378
442
|
}
|
|
379
443
|
|
|
380
444
|
// ─── 入口 ────────────────────────────────────────────────────────────────────
|
|
@@ -385,6 +449,9 @@ export async function start() {
|
|
|
385
449
|
log(`设备类型: ${DEVICE_TYPE}`);
|
|
386
450
|
if (assignedId) log(`已注册编号: ${assignedId}`);
|
|
387
451
|
|
|
452
|
+
// 清理残留进程,确保 100% 干净启动
|
|
453
|
+
cleanupStaleSelf();
|
|
454
|
+
|
|
388
455
|
const serverOk = await ensureServer();
|
|
389
456
|
if (!serverOk) {
|
|
390
457
|
log("无法启动代理服务,终止接入", "ERR");
|