@ai-ecoverse/slicc-kernel 1.54.7 → 1.54.9
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/README.md +5 -3
- package/dist/index.js +40 -10
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +213 -40
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.js +51 -26
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +253 -50
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +68 -43
- package/dist/process-worker.js.map +3 -3
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -947,9 +947,9 @@ var KernelSocket = class _KernelSocket {
|
|
|
947
947
|
case SO_TYPE:
|
|
948
948
|
return SOCK_STREAM;
|
|
949
949
|
case SO_ERROR: {
|
|
950
|
-
const
|
|
950
|
+
const failed2 = this.failed;
|
|
951
951
|
this.failed = void 0;
|
|
952
|
-
return
|
|
952
|
+
return failed2 ? wasiErrno(failed2) : 0;
|
|
953
953
|
}
|
|
954
954
|
case SO_ACCEPTCONN:
|
|
955
955
|
return this.state === "listening" ? 1 : 0;
|
|
@@ -2813,7 +2813,7 @@ var OpfsFs = class {
|
|
|
2813
2813
|
const swap = targetStat?.isDirectory === true;
|
|
2814
2814
|
const staging = swap ? `.${name2}.${crypto.randomUUID()}` : name2;
|
|
2815
2815
|
this.forget(destination);
|
|
2816
|
-
const
|
|
2816
|
+
const timed2 = await this.explicitTimes(source.path);
|
|
2817
2817
|
const moved2 = await this.place(source.handle, dir, staging);
|
|
2818
2818
|
if (swap) await this.rm(destination, { recursive: true });
|
|
2819
2819
|
await this.meta.move(source.path, destination, carry);
|
|
@@ -2825,7 +2825,7 @@ var OpfsFs = class {
|
|
|
2825
2825
|
if (!placed) await dir.removeEntry(staging, { recursive: true });
|
|
2826
2826
|
copied ||= !placed;
|
|
2827
2827
|
}
|
|
2828
|
-
if (copied) await this.restamp(destination,
|
|
2828
|
+
if (copied) await this.restamp(destination, timed2);
|
|
2829
2829
|
this.changed(source.path, destination);
|
|
2830
2830
|
this.touch(parentOf2(source.path), parent.path);
|
|
2831
2831
|
}
|
|
@@ -2834,16 +2834,16 @@ var OpfsFs = class {
|
|
|
2834
2834
|
return handle.kind === "file" ? (await handle.getFile()).lastModified : 0;
|
|
2835
2835
|
}
|
|
2836
2836
|
async explicitTimes(path) {
|
|
2837
|
-
const
|
|
2837
|
+
const timed2 = [];
|
|
2838
2838
|
for (const entry of await this.meta.under(path)) {
|
|
2839
2839
|
if (entry.mtimeFor === void 0 || entry.link !== void 0) continue;
|
|
2840
2840
|
const current = await this.modified(entry.path).catch(() => void 0);
|
|
2841
|
-
if (current === entry.mtimeFor)
|
|
2841
|
+
if (current === entry.mtimeFor) timed2.push(entry.path.slice(path.length));
|
|
2842
2842
|
}
|
|
2843
|
-
return
|
|
2843
|
+
return timed2;
|
|
2844
2844
|
}
|
|
2845
|
-
async restamp(path,
|
|
2846
|
-
for (const rest2 of
|
|
2845
|
+
async restamp(path, timed2) {
|
|
2846
|
+
for (const rest2 of timed2) {
|
|
2847
2847
|
const mtimeFor = await this.modified(path + rest2);
|
|
2848
2848
|
await this.meta.update(path + rest2, (entry) => entry && { ...entry, mtimeFor });
|
|
2849
2849
|
}
|
|
@@ -6456,6 +6456,7 @@ function* procWalk(path, follow2) {
|
|
|
6456
6456
|
let done4 = [];
|
|
6457
6457
|
let todo = path.split("/").filter((part) => part !== "");
|
|
6458
6458
|
let hops = 0;
|
|
6459
|
+
let broken;
|
|
6459
6460
|
while (todo.length > 0) {
|
|
6460
6461
|
const part = todo.shift();
|
|
6461
6462
|
if (part === ".") continue;
|
|
@@ -6465,19 +6466,31 @@ function* procWalk(path, follow2) {
|
|
|
6465
6466
|
}
|
|
6466
6467
|
const at = `/${[...done4, part].join("/")}`;
|
|
6467
6468
|
const whole = normalize(`/${[...done4, part, ...todo].join("/")}`);
|
|
6468
|
-
if (inProc(at) && inProc(whole)) return whole;
|
|
6469
|
+
if (inProc(at) && inProc(whole)) return broken ?? whole;
|
|
6469
6470
|
if (!follow2 && todo.length === 0) return void 0;
|
|
6470
|
-
const target = yield at;
|
|
6471
|
-
if (target ===
|
|
6472
|
-
if (target === void 0) done4.push(part);
|
|
6473
|
-
else {
|
|
6471
|
+
const target = yield { at, check: todo.find((next2) => next2 !== ".") === ".." };
|
|
6472
|
+
if (typeof target === "string") {
|
|
6474
6473
|
if (++hops > MAX_HOPS2) return void 0;
|
|
6475
|
-
|
|
6476
|
-
|
|
6474
|
+
[done4, todo] = throughLink(target, done4, todo);
|
|
6475
|
+
} else {
|
|
6476
|
+
broken ??= refusalOf(target);
|
|
6477
|
+
done4.push(part);
|
|
6477
6478
|
}
|
|
6478
6479
|
}
|
|
6479
6480
|
return void 0;
|
|
6480
6481
|
}
|
|
6482
|
+
function failed(err) {
|
|
6483
|
+
const code = err?.code;
|
|
6484
|
+
return { refused: typeof code === "string" ? code : "ENOENT" };
|
|
6485
|
+
}
|
|
6486
|
+
function refusalOf(found) {
|
|
6487
|
+
if (found === true) return void 0;
|
|
6488
|
+
return found === false ? { refused: "ENOTDIR" } : found;
|
|
6489
|
+
}
|
|
6490
|
+
function throughLink(target, done4, todo) {
|
|
6491
|
+
const parts = target.split("/").filter((part) => part !== "");
|
|
6492
|
+
return [target.startsWith("/") ? [] : done4, [...parts, ...todo]];
|
|
6493
|
+
}
|
|
6481
6494
|
async function procAlias(fs, path, follow2) {
|
|
6482
6495
|
const { readlink, lstat } = fs;
|
|
6483
6496
|
if (!readlink || !lstat) return void 0;
|
|
@@ -6489,7 +6502,10 @@ async function procAlias(fs, path, follow2) {
|
|
|
6489
6502
|
const walk = procWalk(path, follow2);
|
|
6490
6503
|
let step = walk.next();
|
|
6491
6504
|
while (!step.done) {
|
|
6492
|
-
const
|
|
6505
|
+
const { at, check } = step.value;
|
|
6506
|
+
const link2 = await readlink.call(fs, at).catch(() => void 0);
|
|
6507
|
+
const isDir = (st) => st.isDirectory === true;
|
|
6508
|
+
const target = link2 ?? (check ? await lstat.call(fs, at).then(isDir, failed) : true);
|
|
6493
6509
|
step = walk.next(target);
|
|
6494
6510
|
}
|
|
6495
6511
|
return step.value;
|
|
@@ -9856,6 +9872,8 @@ var WasmProcess = class {
|
|
|
9856
9872
|
async openVfs(req) {
|
|
9857
9873
|
if (inProc(req.path)) return this.openProc(req, req.path);
|
|
9858
9874
|
const alias = req.orphan ? void 0 : await procAlias(this.options.fs, req.path, !req.exclusive);
|
|
9875
|
+
if (typeof alias === "object")
|
|
9876
|
+
throw Object.assign(new Error(alias.refused), { code: alias.refused });
|
|
9859
9877
|
if (alias !== void 0) return this.openProc(req, alias);
|
|
9860
9878
|
await refuseReadonly(this.options.fs, req.path, req.flags, req);
|
|
9861
9879
|
const fd = this.fds.install(heldFile(), 3);
|
|
@@ -11512,22 +11530,22 @@ async function mountFstab(lines2, mount, signal, retries = FSTAB_RETRIES, discar
|
|
|
11512
11530
|
);
|
|
11513
11531
|
}
|
|
11514
11532
|
async function mountLine({ line, spec, invalid }, mount, signal, retries, discard) {
|
|
11515
|
-
let
|
|
11533
|
+
let failed2 = invalid;
|
|
11516
11534
|
for (let attempt = 0; !invalid && attempt <= retries.length && !signal.aborted; attempt++) {
|
|
11517
11535
|
try {
|
|
11518
11536
|
const entry = await mount(spec);
|
|
11519
11537
|
if (!signal.aborted) return { line, target: spec.target, entry };
|
|
11520
11538
|
discard(entry);
|
|
11521
|
-
|
|
11539
|
+
failed2 = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
|
|
11522
11540
|
break;
|
|
11523
11541
|
} catch (err) {
|
|
11524
|
-
|
|
11542
|
+
failed2 = err;
|
|
11525
11543
|
if (FINAL.has(codeOf3(err)) || attempt === retries.length) break;
|
|
11526
11544
|
await wait(retries[attempt], signal);
|
|
11527
11545
|
}
|
|
11528
11546
|
}
|
|
11529
|
-
const code = codeOf3(
|
|
11530
|
-
return { line, target: spec.target, code, error: String(
|
|
11547
|
+
const code = codeOf3(failed2);
|
|
11548
|
+
return { line, target: spec.target, code, error: String(failed2?.message ?? code) };
|
|
11531
11549
|
}
|
|
11532
11550
|
|
|
11533
11551
|
// src/mount/hostfs.ts
|
|
@@ -11555,11 +11573,24 @@ var HostfsClient = class {
|
|
|
11555
11573
|
get maxIo() {
|
|
11556
11574
|
return this.capabilities.maxIo ?? HOSTFS_IO;
|
|
11557
11575
|
}
|
|
11558
|
-
|
|
11576
|
+
retired;
|
|
11577
|
+
stop = new AbortController();
|
|
11578
|
+
get gone() {
|
|
11579
|
+
return this.retired !== void 0;
|
|
11580
|
+
}
|
|
11581
|
+
retire(why) {
|
|
11582
|
+
this.retired ??= why;
|
|
11583
|
+
this.stop.abort();
|
|
11584
|
+
}
|
|
11585
|
+
async send(path, init, handle = false, retried = false, cleanup = false) {
|
|
11586
|
+
if (this.retired && !cleanup) throw fsError2("ENOTCONN", this.retired);
|
|
11587
|
+
const stop = cleanup ? void 0 : this.stop.signal;
|
|
11588
|
+
const signal = init.signal && stop ? AbortSignal.any([init.signal, stop]) : init.signal ?? stop;
|
|
11559
11589
|
let response;
|
|
11560
11590
|
try {
|
|
11561
11591
|
response = await this.fetch(`${this.grant.url}${path}`, {
|
|
11562
11592
|
...init,
|
|
11593
|
+
...signal ? { signal } : {},
|
|
11563
11594
|
credentials: "omit",
|
|
11564
11595
|
headers: {
|
|
11565
11596
|
...init.headers,
|
|
@@ -11596,6 +11627,20 @@ var HostfsClient = class {
|
|
|
11596
11627
|
);
|
|
11597
11628
|
return await response.json();
|
|
11598
11629
|
}
|
|
11630
|
+
async cleanup(op, body) {
|
|
11631
|
+
const response = await this.send(
|
|
11632
|
+
"/api/hostfs",
|
|
11633
|
+
{
|
|
11634
|
+
method: "POST",
|
|
11635
|
+
headers: { "Content-Type": "application/json" },
|
|
11636
|
+
body: JSON.stringify({ op, ...body })
|
|
11637
|
+
},
|
|
11638
|
+
true,
|
|
11639
|
+
false,
|
|
11640
|
+
true
|
|
11641
|
+
);
|
|
11642
|
+
await response.body?.cancel();
|
|
11643
|
+
}
|
|
11599
11644
|
async read(fh, offset, size, ifMatch) {
|
|
11600
11645
|
const response = await this.send(
|
|
11601
11646
|
"/api/hostfs",
|
|
@@ -11663,6 +11708,11 @@ function hostfsHandlers(current) {
|
|
|
11663
11708
|
return fresh(remote);
|
|
11664
11709
|
};
|
|
11665
11710
|
const call = (op, body = {}) => current().call(op, body);
|
|
11711
|
+
const settle = (client, restore) => client.call("setattr", restore).catch((err) => {
|
|
11712
|
+
if (!client.gone || !client.cleanup) throw err;
|
|
11713
|
+
void client.cleanup("setattr", restore).catch(() => {
|
|
11714
|
+
});
|
|
11715
|
+
});
|
|
11666
11716
|
async function writable(client, path, flags) {
|
|
11667
11717
|
const { ifMatch: _, ...asked } = flags;
|
|
11668
11718
|
const opening = () => client.call("open", { path: rel(path), ...asked });
|
|
@@ -11673,9 +11723,9 @@ function hostfsHandlers(current) {
|
|
|
11673
11723
|
const mode = (await client.call("stat", { path: rel(path) })).mode ?? 0;
|
|
11674
11724
|
if (mode & 128) throw err;
|
|
11675
11725
|
const restore = { path: rel(path), mode };
|
|
11676
|
-
await client.call("setattr", { path: rel(path), mode: mode | 128 })
|
|
11677
|
-
|
|
11678
|
-
|
|
11726
|
+
const opened2 = await client.call("setattr", { path: rel(path), mode: mode | 128 }).then(opening).catch(async (again) => {
|
|
11727
|
+
await settle(client, restore).catch(() => {
|
|
11728
|
+
});
|
|
11679
11729
|
throw again;
|
|
11680
11730
|
});
|
|
11681
11731
|
return { opened: opened2, restore };
|
|
@@ -11730,7 +11780,7 @@ function hostfsHandlers(current) {
|
|
|
11730
11780
|
try {
|
|
11731
11781
|
await fresh(remote).client.call("release", { fh: remote.fh }, true);
|
|
11732
11782
|
} finally {
|
|
11733
|
-
if (remote.restore) await current()
|
|
11783
|
+
if (remote.restore) await settle(current(), remote.restore);
|
|
11734
11784
|
}
|
|
11735
11785
|
},
|
|
11736
11786
|
mkdir: async (path) => void await call("mkdir", { path: rel(path) }),
|
|
@@ -11860,6 +11910,73 @@ function invalidation(event) {
|
|
|
11860
11910
|
return event.paths ?? true;
|
|
11861
11911
|
}
|
|
11862
11912
|
var PORT_REQUEST_MS = 6e4;
|
|
11913
|
+
var HOSTFS_CALL_MS = 2e4;
|
|
11914
|
+
var PORT_BEAT_MS = 1e3;
|
|
11915
|
+
var PORT_DEAD_MS = 1e4;
|
|
11916
|
+
var PORT_LINGER_MS = 1e3;
|
|
11917
|
+
function timed(transport, ms) {
|
|
11918
|
+
const inflight = /* @__PURE__ */ new Set();
|
|
11919
|
+
const guard = (name2, run2, late, expire) => new Promise((resolve, reject) => {
|
|
11920
|
+
let expired = false;
|
|
11921
|
+
const running = run2();
|
|
11922
|
+
inflight.add(running);
|
|
11923
|
+
const done4 = () => inflight.delete(running);
|
|
11924
|
+
running.then(done4, done4);
|
|
11925
|
+
const timer = setTimeout(() => {
|
|
11926
|
+
expired = true;
|
|
11927
|
+
const why = `the host folder did not answer ${name2} within ${ms} ms`;
|
|
11928
|
+
transport.retire?.(why);
|
|
11929
|
+
expire?.(running);
|
|
11930
|
+
reject(fsError2("ENOTCONN", why));
|
|
11931
|
+
}, ms);
|
|
11932
|
+
running.then(
|
|
11933
|
+
(value) => {
|
|
11934
|
+
clearTimeout(timer);
|
|
11935
|
+
if (expired) late?.(value);
|
|
11936
|
+
resolve(value);
|
|
11937
|
+
},
|
|
11938
|
+
(err) => {
|
|
11939
|
+
clearTimeout(timer);
|
|
11940
|
+
reject(err);
|
|
11941
|
+
}
|
|
11942
|
+
);
|
|
11943
|
+
});
|
|
11944
|
+
const cleanup = async (op, body, skip) => {
|
|
11945
|
+
await Promise.allSettled([...inflight].filter((work) => work !== skip));
|
|
11946
|
+
await transport.cleanup?.(op, body);
|
|
11947
|
+
};
|
|
11948
|
+
const release = (opened2) => {
|
|
11949
|
+
const fh = opened2?.fh;
|
|
11950
|
+
if (typeof fh === "number") void cleanup("release", { fh }).catch(() => {
|
|
11951
|
+
});
|
|
11952
|
+
};
|
|
11953
|
+
return {
|
|
11954
|
+
get capabilities() {
|
|
11955
|
+
return transport.capabilities;
|
|
11956
|
+
},
|
|
11957
|
+
get token() {
|
|
11958
|
+
return transport.token;
|
|
11959
|
+
},
|
|
11960
|
+
get maxIo() {
|
|
11961
|
+
return transport.maxIo;
|
|
11962
|
+
},
|
|
11963
|
+
get gone() {
|
|
11964
|
+
return transport.gone;
|
|
11965
|
+
},
|
|
11966
|
+
retire: (why) => transport.retire?.(why),
|
|
11967
|
+
...transport.cleanup ? { cleanup } : {},
|
|
11968
|
+
call: (op, body, handle) => guard(
|
|
11969
|
+
op,
|
|
11970
|
+
() => transport.call(op, body, handle),
|
|
11971
|
+
op === "open" ? release : void 0,
|
|
11972
|
+
op === "release" ? (running) => void cleanup("release", body ?? {}, running).catch(() => {
|
|
11973
|
+
}) : void 0
|
|
11974
|
+
),
|
|
11975
|
+
read: (fh, offset, size, ifMatch) => guard("read", () => transport.read(fh, offset, size, ifMatch)),
|
|
11976
|
+
write: (fh, offset, bytes) => guard("write", () => transport.write(fh, offset, bytes)),
|
|
11977
|
+
watch: (signal, onEvent, onOpen) => transport.watch(signal, onEvent, onOpen)
|
|
11978
|
+
};
|
|
11979
|
+
}
|
|
11863
11980
|
var PORT_MS_PER_MIB = 1e3;
|
|
11864
11981
|
var nextPortToken = 0;
|
|
11865
11982
|
var PortTransport = class {
|
|
@@ -11870,13 +11987,25 @@ var PortTransport = class {
|
|
|
11870
11987
|
waiting = /* @__PURE__ */ new Map();
|
|
11871
11988
|
next = 0;
|
|
11872
11989
|
dead;
|
|
11873
|
-
|
|
11990
|
+
beatMs;
|
|
11991
|
+
deadMs;
|
|
11992
|
+
lingerMs;
|
|
11993
|
+
beat;
|
|
11994
|
+
answers = false;
|
|
11995
|
+
pinged;
|
|
11996
|
+
constructor(grant, liveness = {}) {
|
|
11874
11997
|
this.port = grant.port;
|
|
11875
|
-
this.requestMs = requestMs;
|
|
11998
|
+
this.requestMs = liveness.requestMs ?? PORT_REQUEST_MS;
|
|
11999
|
+
this.beatMs = liveness.beatMs ?? PORT_BEAT_MS;
|
|
12000
|
+
this.deadMs = liveness.deadMs ?? PORT_DEAD_MS;
|
|
12001
|
+
this.lingerMs = liveness.lingerMs ?? PORT_LINGER_MS;
|
|
11876
12002
|
this.capabilities = grant.capabilities ?? {};
|
|
11877
12003
|
this.token = grant.token ?? `port-${++nextPortToken}`;
|
|
11878
12004
|
this.port.addEventListener("message", (event) => {
|
|
11879
|
-
|
|
12005
|
+
if (event.data?.pong) {
|
|
12006
|
+
this.answers = true;
|
|
12007
|
+
this.pinged = void 0;
|
|
12008
|
+
} else this.waiting.get(event.data?.id)?.(event.data);
|
|
11880
12009
|
});
|
|
11881
12010
|
this.port.addEventListener("close", () => this.fail("the folder's port closed"));
|
|
11882
12011
|
this.port.start();
|
|
@@ -11887,8 +12016,51 @@ var PortTransport = class {
|
|
|
11887
12016
|
get gone() {
|
|
11888
12017
|
return this.dead !== void 0;
|
|
11889
12018
|
}
|
|
12019
|
+
retire(why) {
|
|
12020
|
+
this.fail(why);
|
|
12021
|
+
}
|
|
12022
|
+
ping() {
|
|
12023
|
+
if (this.pinged !== void 0) return;
|
|
12024
|
+
this.pinged = Date.now();
|
|
12025
|
+
try {
|
|
12026
|
+
this.port.postMessage({ id: 0, op: "ping" });
|
|
12027
|
+
} catch {
|
|
12028
|
+
}
|
|
12029
|
+
}
|
|
12030
|
+
watchBeat() {
|
|
12031
|
+
if (this.beat || this.dead) return;
|
|
12032
|
+
this.ping();
|
|
12033
|
+
this.beat = setInterval(() => {
|
|
12034
|
+
if (this.waiting.size === 0) {
|
|
12035
|
+
clearInterval(this.beat);
|
|
12036
|
+
this.beat = void 0;
|
|
12037
|
+
return;
|
|
12038
|
+
}
|
|
12039
|
+
if (this.answers && this.pinged !== void 0 && Date.now() - this.pinged > this.deadMs) {
|
|
12040
|
+
this.fail("the folder's port stopped answering");
|
|
12041
|
+
return;
|
|
12042
|
+
}
|
|
12043
|
+
this.ping();
|
|
12044
|
+
}, this.beatMs);
|
|
12045
|
+
}
|
|
12046
|
+
async cleanup(op, body) {
|
|
12047
|
+
if (this.closed) throw fsError2("ENOTCONN", "the folder's port is closed");
|
|
12048
|
+
this.port.postMessage({ id: 0, op: "cleanup", name: op, body });
|
|
12049
|
+
}
|
|
12050
|
+
closed = false;
|
|
11890
12051
|
fail(why) {
|
|
11891
|
-
if (this.dead === void 0)
|
|
12052
|
+
if (this.dead === void 0) {
|
|
12053
|
+
setTimeout(() => {
|
|
12054
|
+
try {
|
|
12055
|
+
this.port.postMessage({ id: 0, op: "bye" });
|
|
12056
|
+
} catch {
|
|
12057
|
+
}
|
|
12058
|
+
this.closed = true;
|
|
12059
|
+
this.port.close();
|
|
12060
|
+
}, this.lingerMs);
|
|
12061
|
+
}
|
|
12062
|
+
clearInterval(this.beat);
|
|
12063
|
+
this.beat = void 0;
|
|
11892
12064
|
this.dead ??= why;
|
|
11893
12065
|
for (const settle of [...this.waiting.values()])
|
|
11894
12066
|
settle({ id: 0, error: { code: "ENOTCONN", message: why } });
|
|
@@ -11905,6 +12077,7 @@ var PortTransport = class {
|
|
|
11905
12077
|
},
|
|
11906
12078
|
this.requestMs + Math.ceil(bytes / 1048576) * PORT_MS_PER_MIB
|
|
11907
12079
|
);
|
|
12080
|
+
this.watchBeat();
|
|
11908
12081
|
this.waiting.set(id2, (reply) => {
|
|
11909
12082
|
clearTimeout(timer);
|
|
11910
12083
|
this.waiting.delete(id2);
|
|
@@ -11951,6 +12124,7 @@ var PortTransport = class {
|
|
|
11951
12124
|
}
|
|
11952
12125
|
resolve();
|
|
11953
12126
|
};
|
|
12127
|
+
this.watchBeat();
|
|
11954
12128
|
this.waiting.set(id2, (reply) => {
|
|
11955
12129
|
if (reply.open) return onOpen();
|
|
11956
12130
|
if (reply.event) return onEvent(reply.event);
|
|
@@ -11974,11 +12148,38 @@ var errorOf = (err) => ({
|
|
|
11974
12148
|
});
|
|
11975
12149
|
function serveHostfsPort(port, transport) {
|
|
11976
12150
|
const watches = /* @__PURE__ */ new Map();
|
|
12151
|
+
const handles = /* @__PURE__ */ new Set();
|
|
12152
|
+
let stopped = false;
|
|
12153
|
+
const closeHandles = () => {
|
|
12154
|
+
for (const fh of handles) void transport.call("release", { fh }, true).catch(() => {
|
|
12155
|
+
});
|
|
12156
|
+
handles.clear();
|
|
12157
|
+
};
|
|
11977
12158
|
const send = (reply, transfer = []) => port.postMessage(reply, transfer);
|
|
12159
|
+
const pending = /* @__PURE__ */ new Set();
|
|
12160
|
+
const track = (work) => {
|
|
12161
|
+
pending.add(work);
|
|
12162
|
+
const done4 = () => pending.delete(work);
|
|
12163
|
+
work.then(done4, done4);
|
|
12164
|
+
return work;
|
|
12165
|
+
};
|
|
12166
|
+
const answer = async (name2, body) => {
|
|
12167
|
+
const result = await track(transport.call(name2, body));
|
|
12168
|
+
const opened2 = result?.fh;
|
|
12169
|
+
if (name2 === "open" && typeof opened2 === "number") handles.add(opened2);
|
|
12170
|
+
if (name2 === "release") handles.delete(body?.fh);
|
|
12171
|
+
if (stopped) closeHandles();
|
|
12172
|
+
return result;
|
|
12173
|
+
};
|
|
11978
12174
|
const listener = async ({
|
|
11979
12175
|
data
|
|
11980
12176
|
}) => {
|
|
11981
12177
|
const { id: id2, op } = data;
|
|
12178
|
+
if (op === "ping") return send({ id: id2, pong: true });
|
|
12179
|
+
if (op === "bye") return stop();
|
|
12180
|
+
if (op === "cleanup")
|
|
12181
|
+
return void Promise.allSettled([...pending]).then(() => answer(data.name, data.body)).catch(() => {
|
|
12182
|
+
});
|
|
11982
12183
|
if (op === "unwatch") return watches.get(id2)?.abort();
|
|
11983
12184
|
if (op === "watch") {
|
|
11984
12185
|
const stop2 = new AbortController();
|
|
@@ -11999,32 +12200,35 @@ function serveHostfsPort(port, transport) {
|
|
|
11999
12200
|
}
|
|
12000
12201
|
try {
|
|
12001
12202
|
if (op === "read") {
|
|
12002
|
-
const read = await
|
|
12003
|
-
|
|
12004
|
-
|
|
12005
|
-
|
|
12006
|
-
|
|
12203
|
+
const read = await track(
|
|
12204
|
+
transport.read(
|
|
12205
|
+
data.fh,
|
|
12206
|
+
data.offset,
|
|
12207
|
+
data.size,
|
|
12208
|
+
data.ifMatch
|
|
12209
|
+
)
|
|
12007
12210
|
);
|
|
12008
12211
|
const bytes = read.slice();
|
|
12009
12212
|
return send({ id: id2, bytes }, [bytes.buffer]);
|
|
12010
12213
|
}
|
|
12011
12214
|
if (op === "write") {
|
|
12012
|
-
await
|
|
12215
|
+
await track(
|
|
12216
|
+
transport.write(data.fh, data.offset, data.bytes)
|
|
12217
|
+
);
|
|
12013
12218
|
return send({ id: id2 });
|
|
12014
12219
|
}
|
|
12015
12220
|
if (op !== "call") throw fsError2("EINVAL", `unknown hostfs port op ${op}`);
|
|
12016
|
-
send({
|
|
12017
|
-
id: id2,
|
|
12018
|
-
result: await transport.call(data.name, data.body)
|
|
12019
|
-
});
|
|
12221
|
+
send({ id: id2, result: await answer(data.name, data.body) });
|
|
12020
12222
|
} catch (err) {
|
|
12021
12223
|
send({ id: id2, error: errorOf(err) });
|
|
12022
12224
|
}
|
|
12023
12225
|
};
|
|
12024
12226
|
const stop = () => {
|
|
12227
|
+
stopped = true;
|
|
12025
12228
|
port.removeEventListener("message", listener);
|
|
12026
12229
|
port.removeEventListener("close", stop);
|
|
12027
12230
|
for (const watch of watches.values()) watch.abort();
|
|
12231
|
+
closeHandles();
|
|
12028
12232
|
port.close();
|
|
12029
12233
|
};
|
|
12030
12234
|
port.addEventListener("message", listener);
|
|
@@ -12032,10 +12236,10 @@ function serveHostfsPort(port, transport) {
|
|
|
12032
12236
|
port.start();
|
|
12033
12237
|
return stop;
|
|
12034
12238
|
}
|
|
12035
|
-
function grantConnect(hook, fetch2,
|
|
12239
|
+
function grantConnect(hook, fetch2, liveness = {}) {
|
|
12036
12240
|
return async (source, options) => {
|
|
12037
12241
|
const first = await hook(source, options);
|
|
12038
|
-
if ("port" in first) return new PortTransport(first,
|
|
12242
|
+
if ("port" in first) return new PortTransport(first, liveness);
|
|
12039
12243
|
const grant = async () => {
|
|
12040
12244
|
const again = await hook(source, options);
|
|
12041
12245
|
if ("port" in again)
|
|
@@ -12055,7 +12259,10 @@ async function openHostfs(spec, connect, timing = {}) {
|
|
|
12055
12259
|
const stop = new AbortController();
|
|
12056
12260
|
let active;
|
|
12057
12261
|
const handlers = hostfsHandlers(() => active);
|
|
12058
|
-
const ranged2 = () =>
|
|
12262
|
+
const ranged2 = () => ({
|
|
12263
|
+
...active?.capabilities.ranges === true ? { ranges: true } : {},
|
|
12264
|
+
...active ? { maxIo: Math.min(active.maxIo, HOSTFS_IO) } : {}
|
|
12265
|
+
});
|
|
12059
12266
|
const served = serveFilesystem(
|
|
12060
12267
|
port2,
|
|
12061
12268
|
{ ...slot.handlers, mount: ranged2 },
|
|
@@ -12071,7 +12278,7 @@ async function openHostfs(spec, connect, timing = {}) {
|
|
|
12071
12278
|
{
|
|
12072
12279
|
connect: () => connect(spec.source, { readonly: readonly2 }),
|
|
12073
12280
|
up(client) {
|
|
12074
|
-
active = client;
|
|
12281
|
+
active = timed(client, timing.callMs ?? HOSTFS_CALL_MS);
|
|
12075
12282
|
slot.insert(client, handlers);
|
|
12076
12283
|
served.invalidate(true);
|
|
12077
12284
|
},
|
|
@@ -13100,11 +13307,7 @@ var Launcher = class {
|
|
|
13100
13307
|
throw fsError("ENODEV", "this kernel has no hostfs hook (createKernel({ hostfs }))");
|
|
13101
13308
|
return openHostfs(
|
|
13102
13309
|
spec,
|
|
13103
|
-
grantConnect(
|
|
13104
|
-
hostfs,
|
|
13105
|
-
hostfsFetch ?? ((url, init) => fetch(url, init)),
|
|
13106
|
-
hostfsTiming?.requestMs
|
|
13107
|
-
),
|
|
13310
|
+
grantConnect(hostfs, hostfsFetch ?? ((url, init) => fetch(url, init)), hostfsTiming),
|
|
13108
13311
|
hostfsTiming
|
|
13109
13312
|
);
|
|
13110
13313
|
}
|