UNPKG

@metamask/ocap-kernel

Version:
274 lines 14.1 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _KernelRouter_instances, _KernelRouter_kernelStore, _KernelRouter_kernelQueue, _KernelRouter_getVat, _KernelRouter_routeMessage, _KernelRouter_deliverSend, _KernelRouter_deliverNotify, _KernelRouter_deliverGCAction, _KernelRouter_deliverBringOutYourDead; Object.defineProperty(exports, "__esModule", { value: true }); exports.KernelRouter = void 0; const KernelQueue_ts_1 = require("./KernelQueue.cjs"); const kernel_marshal_ts_1 = require("./services/kernel-marshal.cjs"); const extract_ref_ts_1 = require("./store/utils/extract-ref.cjs"); const parse_ref_ts_1 = require("./store/utils/parse-ref.cjs"); const promise_ref_ts_1 = require("./store/utils/promise-ref.cjs"); const types_ts_1 = require("./types.cjs"); const assert_ts_1 = require("./utils/assert.cjs"); const VatHandle_ts_1 = require("./VatHandle.cjs"); /** * The KernelRouter is responsible for routing messages to the correct vat. * * This class is responsible for routing messages to the correct vat, including * sending messages, resolving promises, and dropping imports. */ class KernelRouter { /** * Construct a new KernelRouter. * * @param kernelStore - The kernel's store. * @param kernelQueue - The kernel's queue. * @param getVat - A function that returns a vat handle for a given vat id. */ constructor(kernelStore, kernelQueue, getVat) { _KernelRouter_instances.add(this); /** The kernel's store. */ _KernelRouter_kernelStore.set(this, void 0); /** The kernel's queue. */ _KernelRouter_kernelQueue.set(this, void 0); /** A function that returns a vat handle for a given vat id. */ _KernelRouter_getVat.set(this, void 0); __classPrivateFieldSet(this, _KernelRouter_kernelStore, kernelStore, "f"); __classPrivateFieldSet(this, _KernelRouter_kernelQueue, kernelQueue, "f"); __classPrivateFieldSet(this, _KernelRouter_getVat, getVat, "f"); } /** * Deliver a run queue item to its target. * * If the item being delivered is message whose target is a promise, it is * delivered based on the kernel's model of the promise's state: * - unresolved: it is put onto the queue that the kernel maintains for that promise * - fulfilled: it is forwarded to the promise resolution target * - rejected: the result promise of the message is in turn rejected according * to the kernel's model of the promise's rejection value * * If the item being delivered is a notification, the kernel's model of the * state of the promise being notified is updated, and any queue items * enqueued for that promise are placed onto the run queue. The notification * is also forwarded to all of the promise's registered subscribers. * * @param item - The message/notification to deliver. * @returns The crank outcome. */ async deliver(item) { switch (item.type) { case 'send': return await __classPrivateFieldGet(this, _KernelRouter_instances, "m", _KernelRouter_deliverSend).call(this, item); case 'notify': return await __classPrivateFieldGet(this, _KernelRouter_instances, "m", _KernelRouter_deliverNotify).call(this, item); case 'dropExports': case 'retireExports': case 'retireImports': return await __classPrivateFieldGet(this, _KernelRouter_instances, "m", _KernelRouter_deliverGCAction).call(this, item); case 'bringOutYourDead': return await __classPrivateFieldGet(this, _KernelRouter_instances, "m", _KernelRouter_deliverBringOutYourDead).call(this, item); default: // @ts-expect-error Runtime does not respect "never". (0, assert_ts_1.Fail) `unsupported or unknown run queue item type ${item.type}`; } return undefined; } } exports.KernelRouter = KernelRouter; _KernelRouter_kernelStore = new WeakMap(), _KernelRouter_kernelQueue = new WeakMap(), _KernelRouter_getVat = new WeakMap(), _KernelRouter_instances = new WeakSet(), _KernelRouter_routeMessage = function _KernelRouter_routeMessage(item) { const { target, message } = item; (0, types_ts_1.insistMessage)(message); const routeAsSplat = (error) => { if (message.result && error) { __classPrivateFieldGet(this, _KernelRouter_kernelQueue, "f").resolvePromises(undefined, [ [message.result, true, error], ]); } return null; }; const routeAsSend = (targetObject) => { if (__classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").isRevoked(targetObject)) { return routeAsSplat((0, kernel_marshal_ts_1.kser)('revoked object')); } const vatId = __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").getOwner(targetObject); if (!vatId) { return routeAsSplat((0, kernel_marshal_ts_1.kser)('no vat')); } return { vatId, target: targetObject }; }; const routeAsRequeue = (targetObject) => { return { target: targetObject }; }; if ((0, promise_ref_ts_1.isPromiseRef)(target)) { const promise = __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").getKernelPromise(target); switch (promise.state) { case 'fulfilled': { if (promise.value) { const targetObject = (0, extract_ref_ts_1.extractSingleRef)(promise.value); if (targetObject) { if ((0, promise_ref_ts_1.isPromiseRef)(targetObject)) { return routeAsRequeue(targetObject); } return routeAsSend(targetObject); } } return routeAsSplat((0, kernel_marshal_ts_1.kser)('no object')); } case 'rejected': return routeAsSplat(promise.value); case 'unresolved': return routeAsRequeue(target); default: throw (0, assert_ts_1.Fail) `unknown promise state ${promise.state}`; } } else { return routeAsSend(target); } }, _KernelRouter_deliverSend = /** * Deliver a 'send' run queue item. * * @param item - The send item to deliver. * @returns The crank outcome. */ async function _KernelRouter_deliverSend(item) { const route = __classPrivateFieldGet(this, _KernelRouter_instances, "m", _KernelRouter_routeMessage).call(this, item); let crankResults; // Message went splat if (!route) { __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").decrementRefCount(item.target, 'deliver|splat|target'); if (item.message.result) { __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").decrementRefCount(item.message.result, 'deliver|splat|result'); } for (const slot of item.message.methargs.slots) { __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").decrementRefCount(slot, 'deliver|splat|slot'); } console.log(`@@@@ message went splat ${item.target}<-${JSON.stringify(item.message)}`); return crankResults; } const { vatId, target } = route; const { message } = item; console.log(`@@@@ deliver ${vatId} send ${target}<-${JSON.stringify(message)}`); if (vatId) { const vat = __classPrivateFieldGet(this, _KernelRouter_getVat, "f").call(this, vatId); if (vat) { if (message.result) { if (typeof message.result !== 'string') { throw TypeError('message result must be a string'); } __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").setPromiseDecider(message.result, vatId); __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").decrementRefCount(message.result, 'deliver|send|result'); } const vatTarget = __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").translateRefKtoV(vatId, target, false); const vatMessage = __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").translateMessageKtoV(vatId, message); crankResults = await vat.deliverMessage(vatTarget, vatMessage); __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").decrementRefCount(target, 'deliver|send|target'); for (const slot of message.methargs.slots) { __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").decrementRefCount(slot, 'deliver|send|slot'); } } else { (0, assert_ts_1.Fail) `no owner for kernel object ${target}`; } } else { __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").enqueuePromiseMessage(target, message); } console.log(`@@@@ done ${vatId} send ${target}<-${JSON.stringify(message)}`); return crankResults; }, _KernelRouter_deliverNotify = /** * Deliver a 'notify' run queue item. * * @param item - The notify item to deliver. * @returns The crank outcome. */ async function _KernelRouter_deliverNotify(item) { const { vatId, kpid } = item; (0, types_ts_1.insistVatId)(vatId); const { context, isPromise } = (0, parse_ref_ts_1.parseRef)(kpid); (0, assert_ts_1.assert)(context === 'kernel' && isPromise, `${kpid} is not a kernel promise`); console.log(`@@@@ deliver ${vatId} notify ${vatId} ${kpid}`); const promise = __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").getKernelPromise(kpid); const { state, value } = promise; (0, assert_ts_1.assert)(value, `no value for promise ${kpid}`); if (state === 'unresolved') { (0, assert_ts_1.Fail) `notification on unresolved promise ${kpid}`; } if (!__classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").krefToEref(vatId, kpid)) { // no c-list entry, already done return { didDelivery: vatId }; } const targets = __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").getKpidsToRetire(kpid, value); if (targets.length === 0) { // no kpids to retire, already done return { didDelivery: vatId }; } const resolutions = []; for (const toResolve of targets) { const tPromise = __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").getKernelPromise(toResolve); if (tPromise.state === 'unresolved') { (0, assert_ts_1.Fail) `target promise ${toResolve} is unresolved`; } if (!tPromise.value) { throw (0, assert_ts_1.Fail) `target promise ${toResolve} has no value`; } resolutions.push([ __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").translateRefKtoV(vatId, toResolve, true), tPromise.state === 'rejected', __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").translateCapDataKtoV(vatId, tPromise.value), ]); // decrement refcount for the promise being notified if (toResolve !== kpid) { __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").decrementRefCount(toResolve, 'deliver|notify|slot'); } } const vat = __classPrivateFieldGet(this, _KernelRouter_getVat, "f").call(this, vatId); const crankResults = await vat.deliverNotify(resolutions); // Decrement reference count for processed 'notify' item __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").decrementRefCount(kpid, 'deliver|notify'); console.log(`@@@@ done ${vatId} notify ${vatId} ${kpid}`); return crankResults; }, _KernelRouter_deliverGCAction = /** * Deliver a Garbage Collection action run queue item. * * @param item - The dropExports | retireExports | retireImports item to deliver. * @returns The crank outcome. */ async function _KernelRouter_deliverGCAction(item) { const { type, vatId, krefs } = item; console.log(`@@@@ deliver ${vatId} ${type}`, krefs); const vat = __classPrivateFieldGet(this, _KernelRouter_getVat, "f").call(this, vatId); const vrefs = __classPrivateFieldGet(this, _KernelRouter_kernelStore, "f").krefsToExistingErefs(vatId, krefs); const method = `deliver${type[0].toUpperCase()}${type.slice(1)}`; const crankResults = await vat[method](vrefs); console.log(`@@@@ done ${vatId} ${type}`, krefs); return crankResults; }, _KernelRouter_deliverBringOutYourDead = /** * Deliver a 'bringOutYourDead' run queue item. * * @param item - The bringOutYourDead item to deliver. * @returns The crank outcome. */ async function _KernelRouter_deliverBringOutYourDead(item) { const { vatId } = item; console.log(`@@@@ deliver ${vatId} bringOutYourDead`); const vat = __classPrivateFieldGet(this, _KernelRouter_getVat, "f").call(this, vatId); const crankResults = await vat.deliverBringOutYourDead(); console.log(`@@@@ done ${vatId} bringOutYourDead`); return crankResults; }; //# sourceMappingURL=KernelRouter.cjs.map