@dsh-sup/dsh-core-linux-x64 0.1.6-BETA.4 → 0.1.6-BETA.5
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/core.cjs +102 -31
- package/package.json +1 -1
package/core.cjs
CHANGED
|
@@ -929,7 +929,7 @@ var require_version = __commonJS({
|
|
|
929
929
|
var fs2 = require("node:fs");
|
|
930
930
|
var path2 = require("node:path");
|
|
931
931
|
function guardVersion() {
|
|
932
|
-
if (true) return String("0.1.6-BETA.
|
|
932
|
+
if (true) return String("0.1.6-BETA.5");
|
|
933
933
|
try {
|
|
934
934
|
return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
|
|
935
935
|
} catch {
|
|
@@ -3723,6 +3723,18 @@ var require_pool = __commonJS({
|
|
|
3723
3723
|
this._save();
|
|
3724
3724
|
return p;
|
|
3725
3725
|
}
|
|
3726
|
+
/** 登记固定端口,并保证该 role 在全表唯一(先清除同 role 的其它端口记录再登记)。
|
|
3727
|
+
* 登记表以端口号为键,避让/重绑后新端口是**追加**记录;只 release 旧端口不足以立住不变式
|
|
3728
|
+
* (该调用在内核侧被 catch{} 包住且忽略返回值),残留两条同 role 记录时任何「按 role 取号」
|
|
3729
|
+
* 的读法(本表 get、桌面壳读 ports.json)都可能拿到一个没人监听的端口。
|
|
3730
|
+
* @returns {number} port */
|
|
3731
|
+
registerSole(role, port) {
|
|
3732
|
+
const p = Number(port);
|
|
3733
|
+
for (const [existing, r] of [...this._records]) {
|
|
3734
|
+
if (r.role === role && existing !== p) this._records.delete(existing);
|
|
3735
|
+
}
|
|
3736
|
+
return this.register(role, p);
|
|
3737
|
+
}
|
|
3726
3738
|
/** 登记用户配置端口(实例内部端口等);冲突(固定/保留池/已占)抛错。 */
|
|
3727
3739
|
registerUser(port, owner) {
|
|
3728
3740
|
const p = Number(port);
|
|
@@ -3757,10 +3769,15 @@ var require_pool = __commonJS({
|
|
|
3757
3769
|
return true;
|
|
3758
3770
|
}
|
|
3759
3771
|
/* 查询 */
|
|
3760
|
-
/** 按 role
|
|
3772
|
+
/** 按 role 取端口(固定端口)。同 role 有多条(老版本避让留下的残留记录)时取**最新登记**:
|
|
3773
|
+
* 桌面壳读 ports.json 用的是同一判据,两侧不许对「哪个端口是当前的」给出不同答案。 */
|
|
3761
3774
|
get(role) {
|
|
3762
|
-
|
|
3763
|
-
|
|
3775
|
+
let best = null;
|
|
3776
|
+
for (const r of this._records.values()) {
|
|
3777
|
+
if (r.role !== role) continue;
|
|
3778
|
+
if (!best || (r.createdAt || 0) >= (best.createdAt || 0)) best = r;
|
|
3779
|
+
}
|
|
3780
|
+
return best ? best.port : null;
|
|
3764
3781
|
}
|
|
3765
3782
|
isRegistered(port) {
|
|
3766
3783
|
return this._records.has(Number(port));
|
|
@@ -6278,7 +6295,7 @@ var require_bootstrap = __commonJS({
|
|
|
6278
6295
|
}
|
|
6279
6296
|
function _registerFixedPorts(host2) {
|
|
6280
6297
|
ports.register("dsh-main", host2.config.targetPort);
|
|
6281
|
-
ports.
|
|
6298
|
+
ports.registerSole("supervisor-api", host2.config.apiPort);
|
|
6282
6299
|
}
|
|
6283
6300
|
function _bindNativeDshCommand(host2) {
|
|
6284
6301
|
try {
|
|
@@ -6362,9 +6379,9 @@ var require_api_rebind = __commonJS({
|
|
|
6362
6379
|
bind._tries = 0;
|
|
6363
6380
|
host2.api = server;
|
|
6364
6381
|
try {
|
|
6365
|
-
portsShared.
|
|
6382
|
+
portsShared.registerSole("supervisor-api", host2.config.apiPort);
|
|
6366
6383
|
} catch (e) {
|
|
6367
|
-
host2.logger.warn("ports.
|
|
6384
|
+
host2.logger.warn("ports.registerSole(supervisor-api) \u5931\u8D25: " + (e && e.message || e));
|
|
6368
6385
|
}
|
|
6369
6386
|
host2.events.append("api_listening", { host: host2.config.apiHost, port: host2.config.apiPort });
|
|
6370
6387
|
host2.logger.info("api listening on " + host2.config.apiHost + ":" + host2.config.apiPort);
|
|
@@ -6392,17 +6409,13 @@ var require_api_rebind = __commonJS({
|
|
|
6392
6409
|
host2.api = server;
|
|
6393
6410
|
const prev = host2.config.apiPort;
|
|
6394
6411
|
if (port !== prev) {
|
|
6395
|
-
try {
|
|
6396
|
-
portsShared.release(prev, "system:supervisor-api");
|
|
6397
|
-
} catch {
|
|
6398
|
-
}
|
|
6399
6412
|
host2.config.apiPort = port;
|
|
6400
6413
|
if (host2.configPath) host2.persistConfigPatch({ apiPort: port });
|
|
6401
6414
|
}
|
|
6402
6415
|
try {
|
|
6403
|
-
portsShared.
|
|
6416
|
+
portsShared.registerSole("supervisor-api", port);
|
|
6404
6417
|
} catch (e) {
|
|
6405
|
-
host2.logger.warn("ports.
|
|
6418
|
+
host2.logger.warn("ports.registerSole(supervisor-api) \u5931\u8D25: " + e.message);
|
|
6406
6419
|
}
|
|
6407
6420
|
host2.events.append("api_listening", { host: host2.config.apiHost, port });
|
|
6408
6421
|
host2.logger.info("api listening on " + host2.config.apiHost + ":" + port);
|
|
@@ -10201,7 +10214,7 @@ var require_identity = __commonJS({
|
|
|
10201
10214
|
return null;
|
|
10202
10215
|
}
|
|
10203
10216
|
}
|
|
10204
|
-
function
|
|
10217
|
+
function pidAlive2(pid) {
|
|
10205
10218
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
10206
10219
|
try {
|
|
10207
10220
|
process.kill(pid, 0);
|
|
@@ -10233,7 +10246,7 @@ var require_identity = __commonJS({
|
|
|
10233
10246
|
if (attempt()) return true;
|
|
10234
10247
|
const holder = lockPid(p);
|
|
10235
10248
|
if (holder === process.pid) return true;
|
|
10236
|
-
if (holder !== null &&
|
|
10249
|
+
if (holder !== null && pidAlive2(holder)) return false;
|
|
10237
10250
|
try {
|
|
10238
10251
|
fs2.unlinkSync(p);
|
|
10239
10252
|
} catch {
|
|
@@ -10271,7 +10284,7 @@ var require_identity = __commonJS({
|
|
|
10271
10284
|
}
|
|
10272
10285
|
module2.exports = {
|
|
10273
10286
|
// 测试缝:锁的取/放/读主是纯 fs + kill(0) 语义,直接导出给回归用。
|
|
10274
|
-
_lockPrimitives: { acquireLock: acquireLock2, releaseLock: releaseLock2, lockPid, pidAlive },
|
|
10287
|
+
_lockPrimitives: { acquireLock: acquireLock2, releaseLock: releaseLock2, lockPid, pidAlive: pidAlive2 },
|
|
10275
10288
|
methods: {
|
|
10276
10289
|
_lanLockPath() {
|
|
10277
10290
|
const d = depsOf(this);
|
|
@@ -25995,7 +26008,8 @@ var require_static = __commonJS({
|
|
|
25995
26008
|
".png": "image/png",
|
|
25996
26009
|
".ico": "image/x-icon"
|
|
25997
26010
|
};
|
|
25998
|
-
var
|
|
26011
|
+
var FRAME_ANCESTORS = "tauri://localhost http://tauri.localhost https://tauri.localhost";
|
|
26012
|
+
var CSP = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; frame-ancestors " + FRAME_ANCESTORS;
|
|
25999
26013
|
function serveStatic(res, file, corsOrigin) {
|
|
26000
26014
|
if (!UI_DIR) {
|
|
26001
26015
|
res.writeHead(503, { "Content-Type": "text/plain; charset=utf-8" });
|
|
@@ -27946,6 +27960,41 @@ function readLock() {
|
|
|
27946
27960
|
function isOwnGuardEntry(cmdline) {
|
|
27947
27961
|
return typeof cmdline === "string" && cmdline.includes("dsh-supervisor");
|
|
27948
27962
|
}
|
|
27963
|
+
var LOCK_HEARTBEAT_MS = 2e3;
|
|
27964
|
+
var LOCK_STALE_MS = LOCK_HEARTBEAT_MS * 15;
|
|
27965
|
+
function lockSilentMs() {
|
|
27966
|
+
try {
|
|
27967
|
+
return Math.max(0, Date.now() - fs.statSync(LOCK_FILE).mtimeMs);
|
|
27968
|
+
} catch {
|
|
27969
|
+
return null;
|
|
27970
|
+
}
|
|
27971
|
+
}
|
|
27972
|
+
function pidAlive(pid) {
|
|
27973
|
+
try {
|
|
27974
|
+
process.kill(pid, 0);
|
|
27975
|
+
return true;
|
|
27976
|
+
} catch (e) {
|
|
27977
|
+
return e.code === "EPERM";
|
|
27978
|
+
}
|
|
27979
|
+
}
|
|
27980
|
+
var LOCK_TAKE_RETRY_MS = 8e3;
|
|
27981
|
+
var LOCK_TAKE_NAP_MS = 250;
|
|
27982
|
+
function napSync(ms) {
|
|
27983
|
+
try {
|
|
27984
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
27985
|
+
} catch {
|
|
27986
|
+
}
|
|
27987
|
+
}
|
|
27988
|
+
function startLockHeartbeat() {
|
|
27989
|
+
const t = setInterval(() => {
|
|
27990
|
+
try {
|
|
27991
|
+
const d = /* @__PURE__ */ new Date();
|
|
27992
|
+
fs.utimesSync(LOCK_FILE, d, d);
|
|
27993
|
+
} catch {
|
|
27994
|
+
}
|
|
27995
|
+
}, LOCK_HEARTBEAT_MS);
|
|
27996
|
+
if (t.unref) t.unref();
|
|
27997
|
+
}
|
|
27949
27998
|
function acquireLock() {
|
|
27950
27999
|
fs.mkdirSync(SUPERVISOR_DIR, { recursive: true });
|
|
27951
28000
|
const tryCreate = () => {
|
|
@@ -27960,26 +28009,47 @@ function acquireLock() {
|
|
|
27960
28009
|
process.exit(1);
|
|
27961
28010
|
}
|
|
27962
28011
|
};
|
|
27963
|
-
|
|
28012
|
+
const take = () => {
|
|
28013
|
+
if (!tryCreate()) return null;
|
|
28014
|
+
startLockHeartbeat();
|
|
28015
|
+
return true;
|
|
28016
|
+
};
|
|
28017
|
+
const first = take();
|
|
28018
|
+
if (first) return true;
|
|
27964
28019
|
const held = readLock();
|
|
27965
28020
|
if (held) {
|
|
27966
|
-
|
|
27967
|
-
|
|
27968
|
-
|
|
27969
|
-
|
|
27970
|
-
|
|
27971
|
-
|
|
28021
|
+
if (!pidAlive(held.pid)) {
|
|
28022
|
+
console.log("[supervisor] \u6E05\u7406\u9648\u65E7\u5B88\u536B\u9501\uFF08\u6301\u6709 pid " + held.pid + " \u5DF2\u9000\u51FA\uFF09");
|
|
28023
|
+
} else {
|
|
28024
|
+
const cmdline = readCmdline(held.pid);
|
|
28025
|
+
if (cmdline && isOwnGuardEntry(cmdline)) {
|
|
28026
|
+
const deadline = Date.now() + LOCK_TAKE_RETRY_MS;
|
|
28027
|
+
while (pidAlive(held.pid)) {
|
|
28028
|
+
if (Date.now() >= deadline) {
|
|
28029
|
+
return "\u6301\u6709 pid " + held.pid + " \u5B58\u6D3B\u3001\u547D\u4EE4\u884C\u662F\u672C\u4EA7\u54C1\u7684\u5B88\u536B\u5165\u53E3\uFF0C\u6709\u754C\u7B49\u5F85 " + Math.round(LOCK_TAKE_RETRY_MS / 1e3) + "s \u540E\u4ECD\u672A\u8BA9\u51FA";
|
|
28030
|
+
}
|
|
28031
|
+
napSync(LOCK_TAKE_NAP_MS);
|
|
28032
|
+
}
|
|
28033
|
+
console.log("[supervisor] \u524D\u4EFB\u5B88\u536B pid " + held.pid + " \u5728\u7B49\u5F85\u4E2D\u9000\u51FA -> \u63A5\u7BA1\u5B88\u536B\u9501");
|
|
28034
|
+
} else if (cmdline) {
|
|
28035
|
+
console.log("[supervisor] \u6E05\u7406\u9648\u65E7\u5B88\u536B\u9501\uFF08\u6301\u6709 pid " + held.pid + " \u5B58\u6D3B\u4F46\u547D\u4EE4\u884C\u4E0D\u662F\u672C\u4EA7\u54C1\u7684\u5B88\u536B\u5165\u53E3\uFF1A" + cmdline + "\uFF09");
|
|
28036
|
+
} else {
|
|
28037
|
+
const silent = lockSilentMs();
|
|
28038
|
+
if (silent !== null && silent >= LOCK_STALE_MS) {
|
|
28039
|
+
console.log("[supervisor] \u6E05\u7406\u9648\u65E7\u5B88\u536B\u9501\uFF08\u6301\u6709 pid " + held.pid + " \u5B58\u6D3B\u4F46\u547D\u4EE4\u884C\u8BFB\u4E0D\u5230\uFF0C\u4E14\u9501\u5DF2 " + Math.round(silent / 1e3) + "s \u672A\u7EED\u7EA6 -> \u5224\u5B9A\u539F\u6301\u6709\u8005\u5DF2\u6B7B\uFF09");
|
|
28040
|
+
} else {
|
|
28041
|
+
return "\u6301\u6709 pid " + held.pid + " \u5B58\u6D3B\u3001\u547D\u4EE4\u884C\u8BFB\u4E0D\u5230\uFF0C" + (silent === null ? "\u9501\u72B6\u6001\u4E0D\u53EF\u7EDF\u8BA1\uFF08\u4FDD\u5B88\u8BA9\u4F4D\uFF09" : "\u9501 " + Math.round(silent / 1e3) + "s \u524D\u4ECD\u5728\u7EED\u7EA6\uFF08\u4FDD\u5B88\u8BA9\u4F4D\uFF09");
|
|
28042
|
+
}
|
|
28043
|
+
}
|
|
27972
28044
|
}
|
|
27973
|
-
const cmdline = alive ? readCmdline(held.pid) : null;
|
|
27974
|
-
if (alive && !cmdline) return false;
|
|
27975
|
-
if (alive && isOwnGuardEntry(cmdline)) return false;
|
|
27976
|
-
console.log("[supervisor] \u6E05\u7406\u9648\u65E7\u5B88\u536B\u9501\uFF08\u6301\u6709 pid " + held.pid + (alive ? " \u5B58\u6D3B\u4F46\u547D\u4EE4\u884C\u4E0D\u662F\u672C\u4EA7\u54C1\u7684\u5B88\u536B\u5165\u53E3\uFF1A" + cmdline : " \u5DF2\u9000\u51FA") + "\uFF09");
|
|
27977
28045
|
}
|
|
27978
28046
|
try {
|
|
27979
28047
|
fs.unlinkSync(LOCK_FILE);
|
|
27980
28048
|
} catch {
|
|
27981
28049
|
}
|
|
27982
|
-
|
|
28050
|
+
const again = take();
|
|
28051
|
+
if (again) return true;
|
|
28052
|
+
return "\u6E05\u7406\u9648\u65E7\u9501\u540E\u4ECD\u521B\u5EFA\u4E0D\u4E86\uFF08" + LOCK_FILE + " \u4E0D\u53EF\u5199\uFF1F\uFF09";
|
|
27983
28053
|
}
|
|
27984
28054
|
function releaseLock() {
|
|
27985
28055
|
try {
|
|
@@ -27991,8 +28061,9 @@ function releaseLock() {
|
|
|
27991
28061
|
function cmdDaemon() {
|
|
27992
28062
|
const moved = stateRoot.migrateLegacy();
|
|
27993
28063
|
for (const m of moved) console.log("[migrate] \u72B6\u6001\u76EE\u5F55\u8FC1\u79FB: " + m);
|
|
27994
|
-
|
|
27995
|
-
|
|
28064
|
+
const lock = acquireLock();
|
|
28065
|
+
if (lock !== true) {
|
|
28066
|
+
console.error("[supervisor] \u672C\u8FDB\u7A0B\u9000\u51FA\uFF1A\u672A\u53D6\u5F97\u5B88\u536B\u9501\uFF08\u9501 " + LOCK_FILE + "\uFF09\u2014\u2014 " + lock);
|
|
27996
28067
|
process.exit(1);
|
|
27997
28068
|
}
|
|
27998
28069
|
process.on("exit", releaseLock);
|
package/package.json
CHANGED