A handler is a live reference, held by the VatAdmin DO; workerd evicts an idle DO within seconds, and with it the handler, so a vat's page went 503 almost at once. createVat now keeps a vat's params when they hold only data and ingresses (an ingress by its key: the VatAdmin can make it again), and which vat was given which ingress. A request for a mount with no handler restarts that vat with its params; it rebuilds its root, serves again, and the request is answered. A vat whose params hold another peer's objects isn't restartable yet. The test crashes its own toybox (a crash ends every session to it), and the creator waits for the root's handoff before it disconnects, as scripts/hello.js now does too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
60 lines
1.9 KiB
JavaScript
60 lines
1.9 KiB
JavaScript
/**
|
|
* @file The runtime of an OCapN vat: SES, an OCapN peer, and the vat's own
|
|
* module (`vat.js`), which exports `buildRootObject(vatPowers, params)`.
|
|
*
|
|
* Bundled (see build.js) and loaded as the facet's main module beside the
|
|
* vat's code. The vat's designator is its id; it reaches other peers, and
|
|
* they reach it, through the vatAdmin's router (`env.router`).
|
|
*/
|
|
import "@endo/init";
|
|
import { DurableObject } from "cloudflare:workers";
|
|
import { E, Far } from "@endo/far";
|
|
import { makeClient } from "@endo/ocapn";
|
|
import { makeRpcNetLayer } from "./netlayer.js";
|
|
import * as vat from "./vat.js";
|
|
|
|
/**
|
|
* The swissnum of a vat's bootstrap: the vatAdmin starts the vat through it.
|
|
* Not exported: workerd takes every export of a main module for an entrypoint.
|
|
*/
|
|
const VAT_SWISSNUM = "vat";
|
|
|
|
export class App extends DurableObject {
|
|
#gateway;
|
|
|
|
constructor(ctx, env) {
|
|
super(ctx, env);
|
|
this.#gateway = this.#boot();
|
|
}
|
|
|
|
async #boot() {
|
|
const { vatId, router } = this.env;
|
|
let root;
|
|
const vatPowers = Object.freeze({ E, Far, storage: this.ctx.storage.kv });
|
|
const bootstrap = Far("vatBootstrap", {
|
|
/** (Re)build the root: on creation, and when the vatAdmin restarts the vat. */
|
|
start: (params) => {
|
|
root = vat.buildRootObject(vatPowers, params);
|
|
return root;
|
|
},
|
|
});
|
|
// workerd runs FinalizationRegistry callbacks outside any request, where
|
|
// sending the resulting GC message is forbidden I/O. So imports are
|
|
// never collected here; they go when their session does.
|
|
const ocapn = makeClient({
|
|
debugLabel: vatId.slice(0, 8),
|
|
swissnumTable: new Map([[VAT_SWISSNUM, bootstrap]]),
|
|
enableImportCollection: false,
|
|
});
|
|
const netlayer = await ocapn.registerNetlayer(
|
|
makeRpcNetLayer({ designator: vatId, openGateway: (designator) => router.gateway(designator) }),
|
|
);
|
|
return netlayer.gateway;
|
|
}
|
|
|
|
/** This vat's OCapN gateway, for the router. */
|
|
gateway() {
|
|
return this.#gateway;
|
|
}
|
|
}
|