cicy-desktop 2.1.143 → 2.1.144
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/src/sidecar/docker.js +1 -1
- package/src/sidecar/wsl-docker.js +43 -7
package/package.json
CHANGED
package/src/sidecar/docker.js
CHANGED
|
@@ -722,5 +722,5 @@ module.exports = {
|
|
|
722
722
|
bootstrap, probeHealth, readContainerToken, dockerDesktopExe, desktopDir, downloadsDir, imageTarballPath,
|
|
723
723
|
launchElevated, wslMissing, ensureWsl,
|
|
724
724
|
// platform-agnostic download/retry primitives, reused by native.js
|
|
725
|
-
ensureDownloaded, curlDownload, withRetry, waitUntil, run,
|
|
725
|
+
ensureDownloaded, curlDownload, withRetry, waitUntil, run, headSize,
|
|
726
726
|
};
|
|
@@ -155,10 +155,24 @@ async function installDistro({ emit } = {}) {
|
|
|
155
155
|
// 1) Download the PRE-BAKED rootfs (Ubuntu+Docker+image baked in, ~444MB) with
|
|
156
156
|
// a real progress bar. curl is ~10× faster than node's downloader on OSS.
|
|
157
157
|
const dest = rootfsPath();
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
// REUSE a complete rootfs already on disk (pre-staged into ~/Downloads, or left by
|
|
159
|
+
// a prior run) BEFORE curlDownload touches it. The bug: curlDownload doesn't skip a
|
|
160
|
+
// complete file (and on a failed curl it truncated the staged 447MB), so a staged
|
|
161
|
+
// rootfs got re-downloaded. headSize uses node http (works even when curl can't
|
|
162
|
+
// resolve the host — the `curl exit 6` we saw), so this skip is reliable.
|
|
163
|
+
let haveComplete = false;
|
|
164
|
+
try {
|
|
165
|
+
const expected = await docker.headSize(ROOTFS_URL);
|
|
166
|
+
const have = fs.statSync(dest).size;
|
|
167
|
+
haveComplete = expected > 0 && have === expected;
|
|
168
|
+
if (haveComplete) emit && emit({ phase: "image", status: "skip", message: "下载运行环境:已有完整包,跳过下载", progress: 100, received: have, total: expected });
|
|
169
|
+
} catch {}
|
|
170
|
+
if (!haveComplete) {
|
|
171
|
+
try { await docker.curlDownload(ROOTFS_URL, dest, { emit, phase: "image", label: "下载运行环境" }); }
|
|
172
|
+
catch (e) {
|
|
173
|
+
emit && emit({ phase: "image", status: "running", message: `下载器异常(${e.message}),改用备用下载…` });
|
|
174
|
+
await docker.ensureDownloaded(ROOTFS_URL, dest, null, { emit, phase: "image", label: "下载运行环境" });
|
|
175
|
+
}
|
|
162
176
|
}
|
|
163
177
|
// 2) Import as an ISOLATED WSL2 distro: its OWN VHDX under a dedicated dir, so
|
|
164
178
|
// it never touches the user's existing distros. `--version 2` sets just THIS
|
|
@@ -252,6 +266,25 @@ const BOOT_SCRIPT_B64 = Buffer.from(
|
|
|
252
266
|
"pgrep dockerd >/dev/null 2>&1 || setsid sh -c 'exec dockerd >/var/log/dockerd.log 2>&1 </dev/null' &\n"
|
|
253
267
|
).toString("base64");
|
|
254
268
|
|
|
269
|
+
// Hold the distro OPEN. The flip side of detaching dockerd: once the launching
|
|
270
|
+
// wsl.exe exits, WSL tears the distro down if no session holds it — killing the
|
|
271
|
+
// just-launched dockerd (the "启动引擎 转圈但 dockerd=none" we saw). A detached,
|
|
272
|
+
// long-lived `wsl … sleep infinity` keeps the distro alive so dockerd (and the
|
|
273
|
+
// container) survive. unref'd so it never blocks the app; survives app exit too.
|
|
274
|
+
let _keepalive = null;
|
|
275
|
+
function ensureKeepalive() {
|
|
276
|
+
if (process.platform !== "win32") return;
|
|
277
|
+
if (_keepalive && _keepalive.exitCode == null && !_keepalive.killed) return;
|
|
278
|
+
try {
|
|
279
|
+
_keepalive = spawn("wsl", ["-d", DISTRO, "-u", "root", "--", "sh", "-c", "exec sleep infinity"],
|
|
280
|
+
{ detached: true, stdio: "ignore", windowsHide: true });
|
|
281
|
+
_keepalive.on("error", (e) => { log.warn(`[keepalive] ${e.message}`); _keepalive = null; });
|
|
282
|
+
_keepalive.on("exit", () => { _keepalive = null; });
|
|
283
|
+
_keepalive.unref();
|
|
284
|
+
log.info("[keepalive] holding distro open (sleep infinity)");
|
|
285
|
+
} catch (e) { log.warn(`[keepalive] spawn failed: ${e.message}`); }
|
|
286
|
+
}
|
|
287
|
+
|
|
255
288
|
async function launchDockerd() {
|
|
256
289
|
await wslRun(
|
|
257
290
|
`echo ${BOOT_SCRIPT_B64} | base64 -d > /usr/local/sbin/start-dockerd.sh 2>/dev/null; chmod +x /usr/local/sbin/start-dockerd.sh 2>/dev/null; ` +
|
|
@@ -260,8 +293,10 @@ async function launchDockerd() {
|
|
|
260
293
|
// Stale /var/run/docker.{pid,sock} from the pre-baked rootfs make a fresh dockerd
|
|
261
294
|
// refuse to start; clear them when dockerd isn't already running.
|
|
262
295
|
"if ! pgrep dockerd >/dev/null 2>&1; then rm -f /var/run/docker.pid /run/docker.pid /var/run/docker.sock /run/docker.sock; fi; " +
|
|
263
|
-
|
|
264
|
-
|
|
296
|
+
// setsid --fork: fork dockerd into a NEW session and have setsid EXIT immediately,
|
|
297
|
+
// so this wsl call returns at once and dockerd is fully orphaned (no `& true`
|
|
298
|
+
// backgrounding race). It only survives because ensureKeepalive() holds the distro.
|
|
299
|
+
"pgrep dockerd >/dev/null 2>&1 || setsid --fork bash -c 'exec dockerd >/var/log/cicy-dockerd.log 2>&1 </dev/null'",
|
|
265
300
|
{ timeout: 20000 });
|
|
266
301
|
}
|
|
267
302
|
|
|
@@ -273,7 +308,8 @@ async function startEngine() {
|
|
|
273
308
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
274
309
|
const at0 = Date.now();
|
|
275
310
|
let stuck = false;
|
|
276
|
-
log.info(`[startEngine] attempt ${attempt}/3 — launch dockerd (detached) + poll socket`);
|
|
311
|
+
log.info(`[startEngine] attempt ${attempt}/3 — keepalive + launch dockerd (detached) + poll socket`);
|
|
312
|
+
ensureKeepalive(); // hold the distro open BEFORE launching, or the teardown kills dockerd
|
|
277
313
|
try { await launchDockerd(); }
|
|
278
314
|
catch (e) { stuck = true; log.warn(`[startEngine] attempt ${attempt} launch errored — WSL stuck? ${e.message}`); }
|
|
279
315
|
if (!stuck) {
|