mslxdff 0.1.34 → 0.1.35
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/bin/mslxdff.js +116 -25
- package/package.json +1 -1
package/bin/mslxdff.js
CHANGED
|
@@ -804,36 +804,85 @@ if (broadbandGroups().length) {
|
|
|
804
804
|
}
|
|
805
805
|
|
|
806
806
|
// Auto-update: periodically check npm for a newer mslxdff and restart.
|
|
807
|
-
//
|
|
808
|
-
//
|
|
809
|
-
// the daemon so no manual intervention is needed.
|
|
807
|
+
// Default: hourly (no env needed). Disable with MSLXDFF_AUTO_UPDATE=0/off/false.
|
|
808
|
+
// Tuning: MSLXDFF_AUTO_UPDATE=1/true → hourly, or MSLXDFF_AUTO_UPDATE_MS=<ms>.
|
|
810
809
|
const autoUpdateMs = autoUpdateIntervalMs();
|
|
810
|
+
function emitAutoUpdate(type, data = {}) {
|
|
811
|
+
const entry = { ts: Date.now(), type, ...data };
|
|
812
|
+
try { bus?.emit(entry); } catch {}
|
|
813
|
+
try { logs?.appendEvent?.(entry); } catch {}
|
|
814
|
+
// also to daemon.log for tail
|
|
815
|
+
const line = `[auto-update] ${type} ${JSON.stringify(data)}`;
|
|
816
|
+
console.log(line);
|
|
817
|
+
}
|
|
811
818
|
if (autoUpdateMs) {
|
|
812
819
|
console.log(`auto-update enabled: checking every ${Math.round(autoUpdateMs / 60000)}m`);
|
|
820
|
+
emitAutoUpdate("auto-update-enabled", { intervalMs: autoUpdateMs, current: VERSION });
|
|
821
|
+
// run once shortly after start (30s) so a newly deployed fix is picked up quickly,
|
|
822
|
+
// then on the regular interval
|
|
823
|
+
setTimeout(() => {
|
|
824
|
+
emitAutoUpdate("auto-update-check", { current: VERSION });
|
|
825
|
+
checkAndAutoUpdate().catch((err) => {
|
|
826
|
+
console.log(`auto-update check failed: ${errMsg(err)}`);
|
|
827
|
+
emitAutoUpdate("auto-update-failed", { error: errMsg(err) });
|
|
828
|
+
});
|
|
829
|
+
}, 30_000).unref?.();
|
|
813
830
|
const autoUpdateTimer = setInterval(() => {
|
|
814
|
-
|
|
831
|
+
emitAutoUpdate("auto-update-check", { current: VERSION });
|
|
832
|
+
checkAndAutoUpdate().catch((err) => {
|
|
833
|
+
console.log(`auto-update check failed: ${errMsg(err)}`);
|
|
834
|
+
emitAutoUpdate("auto-update-failed", { error: errMsg(err) });
|
|
835
|
+
});
|
|
815
836
|
}, autoUpdateMs);
|
|
816
837
|
autoUpdateTimer.unref();
|
|
838
|
+
} else {
|
|
839
|
+
console.log(`auto-update disabled (set MSLXDFF_AUTO_UPDATE=1 to enable hourly)`);
|
|
840
|
+
emitAutoUpdate("auto-update-disabled", { current: VERSION });
|
|
817
841
|
}
|
|
818
842
|
|
|
819
843
|
async function checkAndAutoUpdate() {
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
844
|
+
emitAutoUpdate("auto-update-query", { current: VERSION });
|
|
845
|
+
const info = await run(npmCmd(), ["view", "mslxdff", "dist-tags.latest", "--json"]);
|
|
846
|
+
if (info.err) {
|
|
847
|
+
emitAutoUpdate("auto-update-query-failed", { error: info.err.message || String(info.stderr || "").slice(0, 500) });
|
|
848
|
+
throw new Error(info.err.message || String(info.stderr || "").slice(0, 500));
|
|
849
|
+
}
|
|
850
|
+
let latest = "";
|
|
851
|
+
try {
|
|
852
|
+
latest = JSON.parse(String(info.stdout || "").trim());
|
|
853
|
+
if (Array.isArray(latest)) latest = latest[latest.length - 1];
|
|
854
|
+
latest = String(latest || "").replace(/^v/, "").trim();
|
|
855
|
+
} catch {
|
|
856
|
+
const raw = String(info.stdout || "").trim();
|
|
857
|
+
const m = raw.match(/(\d+\.\d+\.\d+[^\s'"]*)/);
|
|
858
|
+
latest = m ? m[1] : raw.split(/\s+/).pop()?.replace(/['"]/g, "") || "";
|
|
859
|
+
}
|
|
860
|
+
latest = latest.replace(/['"]/g, "").trim();
|
|
861
|
+
emitAutoUpdate("auto-update-queried", { current: VERSION, latest, stdout: String(info.stdout || "").trim().slice(0, 200) });
|
|
862
|
+
if (!latest || latest === VERSION) {
|
|
863
|
+
emitAutoUpdate("auto-update-noop", { current: VERSION, latest });
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (compareSemver(latest, VERSION) <= 0) {
|
|
867
|
+
emitAutoUpdate("auto-update-noop", { current: VERSION, latest, reason: "not newer" });
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
emitAutoUpdate("auto-update-found", { current: VERSION, latest });
|
|
827
871
|
console.log(`auto-update: v${VERSION} -> v${latest}, installing...`);
|
|
872
|
+
emitAutoUpdate("auto-update-installing", { current: VERSION, latest });
|
|
828
873
|
const up = await run(npmCmd(), ["install", "-g", `mslxdff@${latest}`]);
|
|
829
|
-
if (up.err)
|
|
874
|
+
if (up.err) {
|
|
875
|
+
emitAutoUpdate("auto-update-install-failed", { current: VERSION, latest, error: up.err.message || String(up.stderr || "").slice(0, 500) });
|
|
876
|
+
throw new Error(up.err.message || String(up.stderr || "").slice(0, 500));
|
|
877
|
+
}
|
|
878
|
+
emitAutoUpdate("auto-update-installed", { current: VERSION, latest, stdout: String(up.stdout || "").slice(0, 500) });
|
|
830
879
|
console.log(`auto-update: installed v${latest}, restarting daemon...`);
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
// for the current process we just respawn with the new code.
|
|
880
|
+
emitAutoUpdate("auto-update-restarting", { current: VERSION, latest });
|
|
881
|
+
try { stopDaemon(); } catch (e) { emitAutoUpdate("auto-update-stop-failed", { error: errMsg(e) }); }
|
|
834
882
|
const newPid = startDaemon([]);
|
|
835
883
|
await waitForHealth(resolvePort(), 8000);
|
|
836
884
|
console.log(`auto-update: restarted as v${latest} (pid ${newPid})`);
|
|
885
|
+
emitAutoUpdate("auto-update-restarted", { current: VERSION, latest, newPid });
|
|
837
886
|
}
|
|
838
887
|
|
|
839
888
|
function compareSemver(a, b) {
|
|
@@ -906,10 +955,13 @@ function groupSyncIntervalMs() {
|
|
|
906
955
|
|
|
907
956
|
function autoUpdateIntervalMs() {
|
|
908
957
|
const raw = process.env.MSLXDFF_AUTO_UPDATE_MS ?? process.env.MSLXDFF_AUTO_UPDATE;
|
|
909
|
-
|
|
910
|
-
if (raw ===
|
|
958
|
+
// default: hourly when env not set; explicit 0/off/false disables
|
|
959
|
+
if (raw === undefined || raw === null || raw === "") return 60 * 60 * 1000;
|
|
960
|
+
const s = String(raw).trim().toLowerCase();
|
|
961
|
+
if (s === "0" || s === "off" || s === "false" || s === "no" || s === "disable" || s === "disabled") return 0;
|
|
962
|
+
if (s === "1" || s === "true" || s === "on" || s === "yes" || s === "enable" || s === "enabled") return 60 * 60 * 1000;
|
|
911
963
|
const n = Number(raw);
|
|
912
|
-
return Number.isInteger(n) && n > 0 ? n :
|
|
964
|
+
return Number.isInteger(n) && n > 0 ? n : 60 * 60 * 1000;
|
|
913
965
|
}
|
|
914
966
|
|
|
915
967
|
function banWindowMs() {
|
|
@@ -979,7 +1031,7 @@ Environment:
|
|
|
979
1031
|
MSLXDFF_MAX_HOPS max peer-forwarding depth (default 3)
|
|
980
1032
|
MSLXDFF_BAN_THRESHOLD failed joins before an ip is banned (default 5)
|
|
981
1033
|
MSLXDFF_BAN_WINDOW_MS ban duration after too many failures (default 48h)
|
|
982
|
-
MSLXDFF_AUTO_UPDATE auto-update: 1/true
|
|
1034
|
+
MSLXDFF_AUTO_UPDATE auto-update: hourly by default, 0/off/false to disable, 1/true or ms
|
|
983
1035
|
MSLXDFF_AUTO_UPDATE_MS same as above, explicit ms (overrides AUTO_UPDATE)
|
|
984
1036
|
`);
|
|
985
1037
|
}
|
|
@@ -1148,6 +1200,32 @@ function fmtEvent(e) {
|
|
|
1148
1200
|
return `${head} client abort ${m(e.model)} total=${fmtDur(e.totalMs)}`;
|
|
1149
1201
|
case "result":
|
|
1150
1202
|
return `${head} result ${e.status} ${m(e.model)} via=${e.via} 响应耗时 ${fmtDur(e.durationMs)}`;
|
|
1203
|
+
case "auto-update-enabled":
|
|
1204
|
+
return `${head} auto-update enabled every ${Math.round((e.intervalMs||0)/60000)}m current=${e.current}`;
|
|
1205
|
+
case "auto-update-disabled":
|
|
1206
|
+
return `${head} auto-update disabled current=${e.current}`;
|
|
1207
|
+
case "auto-update-check":
|
|
1208
|
+
return `${head} auto-update checking current=${e.current}`;
|
|
1209
|
+
case "auto-update-query":
|
|
1210
|
+
return `${head} auto-update querying npm current=${e.current}`;
|
|
1211
|
+
case "auto-update-queried":
|
|
1212
|
+
return `${head} auto-update queried current=${e.current} latest=${e.latest} raw=${(e.stdout||"").slice(0,80)}`;
|
|
1213
|
+
case "auto-update-noop":
|
|
1214
|
+
return `${head} auto-update noop current=${e.current} latest=${e.latest}${e.reason?` reason=${e.reason}`:""}`;
|
|
1215
|
+
case "auto-update-found":
|
|
1216
|
+
return `${head} auto-update NEW v${e.current} -> v${e.latest} 发现新版本`;
|
|
1217
|
+
case "auto-update-installing":
|
|
1218
|
+
return `${head} auto-update installing v${e.latest}...`;
|
|
1219
|
+
case "auto-update-installed":
|
|
1220
|
+
return `${head} auto-update installed v${e.latest}`;
|
|
1221
|
+
case "auto-update-restarting":
|
|
1222
|
+
return `${head} auto-update restarting daemon to v${e.latest}...`;
|
|
1223
|
+
case "auto-update-restarted":
|
|
1224
|
+
return `${head} auto-update restarted pid=${e.newPid} v${e.current} -> v${e.latest} 升级完成`;
|
|
1225
|
+
case "auto-update-failed":
|
|
1226
|
+
case "auto-update-query-failed":
|
|
1227
|
+
case "auto-update-install-failed":
|
|
1228
|
+
return `${head} auto-update failed ${e.type} error=${e.error||""}`;
|
|
1151
1229
|
default:
|
|
1152
1230
|
return `${head} ${e?.type || "?"} ${JSON.stringify(e || {})}`;
|
|
1153
1231
|
}
|
|
@@ -1167,22 +1245,35 @@ function npmCmd() {
|
|
|
1167
1245
|
}
|
|
1168
1246
|
|
|
1169
1247
|
function run(cmd, args, opts = {}) {
|
|
1248
|
+
const isWin = process.platform === "win32";
|
|
1170
1249
|
return new Promise((resolve) => {
|
|
1171
|
-
|
|
1250
|
+
// npm.cmd is a batch file on Windows — execFile needs shell:true to find it via PATHEXT
|
|
1251
|
+
const execOpts = isWin ? { shell: true, windowsHide: true } : {};
|
|
1252
|
+
execFile(cmd, args, { timeout: 120_000, ...execOpts, ...opts }, (err, stdout, stderr) => resolve({ err, stdout, stderr }));
|
|
1172
1253
|
});
|
|
1173
1254
|
}
|
|
1174
1255
|
|
|
1175
1256
|
async function updateSelf() {
|
|
1176
1257
|
console.log(`mslxdff v${VERSION} — checking for updates…`);
|
|
1177
|
-
const info = await run(npmCmd(), ["view", "mslxdff", "
|
|
1258
|
+
const info = await run(npmCmd(), ["view", "mslxdff", "dist-tags.latest", "--json"]);
|
|
1178
1259
|
if (info.err) {
|
|
1179
|
-
console.error(`could not query npm: ${info.err.message}`);
|
|
1260
|
+
console.error(`could not query npm: ${info.err.message || String(info.stderr || "").slice(0, 500)}`);
|
|
1180
1261
|
process.exit(1);
|
|
1181
1262
|
}
|
|
1182
|
-
|
|
1263
|
+
let latest = "";
|
|
1264
|
+
try {
|
|
1265
|
+
latest = JSON.parse(String(info.stdout || "").trim());
|
|
1266
|
+
if (Array.isArray(latest)) latest = latest[latest.length - 1];
|
|
1267
|
+
latest = String(latest || "").trim();
|
|
1268
|
+
} catch {
|
|
1269
|
+
const m = String(info.stdout || "").trim().match(/(\d+\.\d+\.\d+[^\s'"]*)/);
|
|
1270
|
+
latest = m ? m[1] : "";
|
|
1271
|
+
}
|
|
1272
|
+
latest = String(latest || "").replace(/['"]/g, "").trim();
|
|
1273
|
+
const version = VERSION;
|
|
1183
1274
|
console.log(` installed: ${version}`);
|
|
1184
|
-
console.log(` latest: ${latest}`);
|
|
1185
|
-
if (version === latest) {
|
|
1275
|
+
console.log(` latest: ${latest || "unknown"}`);
|
|
1276
|
+
if (!latest || version === latest || compareSemver(latest, version) <= 0) {
|
|
1186
1277
|
console.log("already up to date");
|
|
1187
1278
|
process.exit(0);
|
|
1188
1279
|
}
|