diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2020-01-28 03:12:25 +0100 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2020-01-27 21:12:25 -0500 |
commit | ac10d79d231d3b66b918764b9706597321850687 (patch) | |
tree | 6a781c58075ee0c68091e71d2ffd2bb898dc9dfd /cli/js/runtime_worker.ts | |
parent | f604becaba0c747fdf8dd9d0d744c7bd19322e41 (diff) |
refactor: isomorphic snapshot for CLI (#3728)
Diffstat (limited to 'cli/js/runtime_worker.ts')
-rw-r--r-- | cli/js/runtime_worker.ts | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/cli/js/runtime_worker.ts b/cli/js/runtime_worker.ts new file mode 100644 index 000000000..7f1d1b69c --- /dev/null +++ b/cli/js/runtime_worker.ts @@ -0,0 +1,126 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +// This module is the entry point for "worker" isolate, ie. the one +// that is created using `new Worker()` JS API. +// +// It provides two functions that should be called by Rust: +// - `bootstrapWorkerRuntime` - must be called once, when Isolate is created. +// It sets up runtime by providing globals for `DedicatedWorkerScope`. +// - `runWorkerMessageLoop` - starts receiving messages from parent worker, +// can be called multiple times - eg. to restart worker execution after +// exception occurred and was handled by parent worker + +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + readOnly, + writable, + nonEnumerable, + windowOrWorkerGlobalScopeMethods, + windowOrWorkerGlobalScopeProperties, + eventTargetProperties +} from "./globals.ts"; +import * as dispatch from "./dispatch.ts"; +import { sendAsync, sendSync } from "./dispatch_json.ts"; +import { log } from "./util.ts"; +import { TextDecoder, TextEncoder } from "./text_encoding.ts"; +import * as runtime from "./runtime.ts"; + +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); + +// TODO(bartlomieju): remove these funtions +// Stuff for workers +export const onmessage: (e: { data: any }) => void = (): void => {}; +export const onerror: (e: { data: any }) => void = (): void => {}; + +export function postMessage(data: any): void { + const dataJson = JSON.stringify(data); + const dataIntArray = encoder.encode(dataJson); + sendSync(dispatch.OP_WORKER_POST_MESSAGE, {}, dataIntArray); +} + +export async function getMessage(): Promise<any> { + log("getMessage"); + const res = await sendAsync(dispatch.OP_WORKER_GET_MESSAGE); + if (res.data != null) { + const dataIntArray = new Uint8Array(res.data); + const dataJson = decoder.decode(dataIntArray); + return JSON.parse(dataJson); + } else { + return null; + } +} + +let isClosing = false; +let hasBootstrapped = false; + +export function workerClose(): void { + isClosing = true; +} + +export async function runWorkerMessageLoop(): Promise<void> { + while (!isClosing) { + const data = await getMessage(); + if (data == null) { + log("runWorkerMessageLoop got null message. quitting."); + break; + } + + let result: void | Promise<void>; + const event = { data }; + + try { + if (!globalThis["onmessage"]) { + break; + } + result = globalThis.onmessage!(event); + if (result && "then" in result) { + await result; + } + if (!globalThis["onmessage"]) { + break; + } + } catch (e) { + if (globalThis["onerror"]) { + const result = globalThis.onerror( + e.message, + e.fileName, + e.lineNumber, + e.columnNumber, + e + ); + if (result === true) { + continue; + } + } + throw e; + } + } +} + +export const workerRuntimeGlobalProperties = { + self: readOnly(globalThis), + onmessage: writable(onmessage), + onerror: writable(onerror), + workerClose: nonEnumerable(workerClose), + postMessage: writable(postMessage) +}; + +/** + * Main method to initialize worker runtime. + * + * It sets up global variables for DedicatedWorkerScope, + * and initializes ops. + */ +export function bootstrapWorkerRuntime(name: string): void { + if (hasBootstrapped) { + throw new Error("Worker runtime already bootstrapped"); + } + log("bootstrapWorkerRuntime"); + hasBootstrapped = true; + Object.defineProperties(globalThis, windowOrWorkerGlobalScopeMethods); + Object.defineProperties(globalThis, windowOrWorkerGlobalScopeProperties); + Object.defineProperties(globalThis, workerRuntimeGlobalProperties); + Object.defineProperties(globalThis, eventTargetProperties); + runtime.start(false, name); +} |