All files / kernel-browser-runtime/src/kernel-worker kernel-worker.ts

0% Statements 0/31
0% Branches 0/2
0% Functions 0/11
0% Lines 0/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                                                                                                                                                                                                                           
import { JsonRpcServer } from '@metamask/json-rpc-engine/v2';
import { makeSQLKernelDatabase } from '@metamask/kernel-store/sqlite/wasm';
import { isJsonRpcMessage, stringify } from '@metamask/kernel-utils';
import type { JsonRpcMessage } from '@metamask/kernel-utils';
import { Logger } from '@metamask/logger';
import { Kernel } from '@metamask/ocap-kernel';
import type { PostMessageTarget } from '@metamask/streams/browser';
import {
  MessagePortDuplexStream,
  receiveMessagePort,
} from '@metamask/streams/browser';
 
import {
  isCapTPNotification,
  makeCapTPNotification,
} from '../background-captp.ts';
import type { CapTPMessage } from '../background-captp.ts';
import { receiveInternalConnections } from '../internal-comms/internal-connections.ts';
import { PlatformServicesClient } from '../PlatformServicesClient.ts';
import { setupConsoleForwarding } from '../utils/console-forwarding.ts';
import { makeKernelCapTP } from './captp/index.ts';
import { makeLoggingMiddleware } from './middleware/logging.ts';
import { makePanelMessageMiddleware } from './middleware/panel-message.ts';
import { getRelaysFromCurrentLocation } from '../utils/relay-query-string.ts';
 
const logger = new Logger('kernel-worker');
const DB_FILENAME = 'store.db';
 
main().catch(logger.error);
 
/**
 * Run the kernel.
 */
async function main(): Promise<void> {
  const port = await receiveMessagePort(
    (listener) => globalThis.addEventListener('message', listener),
    (listener) => globalThis.removeEventListener('message', listener),
  );
 
  const [messageStream, platformServicesClient, kernelDatabase] =
    await Promise.all([
      MessagePortDuplexStream.make<JsonRpcMessage, JsonRpcMessage>(
        port,
        isJsonRpcMessage,
      ),
      PlatformServicesClient.make(globalThis as PostMessageTarget),
      makeSQLKernelDatabase({ dbFilename: DB_FILENAME }),
    ]);
 
  // Set up console forwarding - messages flow through offscreen to background
  setupConsoleForwarding({
    source: 'kernel-worker',
    onMessage: (message) => {
      messageStream.write(message).catch(() => undefined);
    },
  });
 
  const resetStorage =
    new URLSearchParams(globalThis.location.search).get('reset-storage') ===
    'true';
 
  const kernelP = Kernel.make(platformServicesClient, kernelDatabase, {
    resetStorage,
  });
 
  const handlerP = kernelP.then((kernel) => {
    const server = new JsonRpcServer({
      middleware: [
        makeLoggingMiddleware(logger.subLogger('internal-rpc')),
        makePanelMessageMiddleware(kernel, kernelDatabase),
      ],
    });
    return async (request: JsonRpcMessage) => server.handle(request);
  });
 
  receiveInternalConnections({
    handlerPromise: handlerP,
    logger,
  });
 
  const kernel = await kernelP;
 
  const kernelCapTP = makeKernelCapTP({
    kernel,
    send: (captpMessage: CapTPMessage) => {
      const notification = makeCapTPNotification(captpMessage);
      messageStream.write(notification).catch((error) => {
        logger.error('Failed to send CapTP message:', error);
      });
    },
  });
 
  messageStream
    .drain((message) => {
      if (isCapTPNotification(message)) {
        const captpMessage = message.params[0];
        kernelCapTP.dispatch(captpMessage);
      } else {
        throw new Error(`Unexpected message: ${stringify(message)}`);
      }
    })
    .catch((error) => {
      kernelCapTP.abort(error);
      logger.error('Message stream error:', error);
    });
 
  const relays = getRelaysFromCurrentLocation();
  await kernel.initRemoteComms({ relays });
}