diff options
Diffstat (limited to 'cli/js')
-rw-r--r-- | cli/js/compiler.ts | 2 | ||||
-rw-r--r-- | cli/js/globals.ts | 11 | ||||
-rw-r--r-- | cli/js/lib.deno_runtime.d.ts | 35 | ||||
-rw-r--r-- | cli/js/worker_main.ts | 98 | ||||
-rw-r--r-- | cli/js/workers.ts | 128 |
5 files changed, 144 insertions, 130 deletions
diff --git a/cli/js/compiler.ts b/cli/js/compiler.ts index 79b9fdaf6..7addfc5ca 100644 --- a/cli/js/compiler.ts +++ b/cli/js/compiler.ts @@ -32,7 +32,7 @@ import { fromTypeScriptDiagnostic } from "./diagnostics_util.ts"; import * as os from "./os.ts"; import { assert } from "./util.ts"; import * as util from "./util.ts"; -import { postMessage, workerClose, workerMain } from "./workers.ts"; +import { postMessage, workerClose, workerMain } from "./worker_main.ts"; const self = globalThis; diff --git a/cli/js/globals.ts b/cli/js/globals.ts index 5754002c0..0f364b8e0 100644 --- a/cli/js/globals.ts +++ b/cli/js/globals.ts @@ -21,6 +21,7 @@ import * as textEncoding from "./text_encoding.ts"; import * as timers from "./timers.ts"; import * as url from "./url.ts"; import * as urlSearchParams from "./url_search_params.ts"; +import * as workerRuntime from "./worker_main.ts"; import * as workers from "./workers.ts"; import * as performanceUtil from "./performance.ts"; import * as request from "./request.ts"; @@ -194,12 +195,12 @@ const globalProperties = { Response: nonEnumerable(fetchTypes.Response), performance: writable(new performanceUtil.Performance()), - onmessage: writable(workers.onmessage), - onerror: writable(workers.onerror), + onmessage: writable(workerRuntime.onmessage), + onerror: writable(workerRuntime.onerror), - workerMain: nonEnumerable(workers.workerMain), - workerClose: nonEnumerable(workers.workerClose), - postMessage: writable(workers.postMessage), + workerMain: nonEnumerable(workerRuntime.workerMain), + workerClose: nonEnumerable(workerRuntime.workerClose), + postMessage: writable(workerRuntime.postMessage), Worker: nonEnumerable(workers.WorkerImpl), [domTypes.eventTargetHost]: nonEnumerable(null), diff --git a/cli/js/lib.deno_runtime.d.ts b/cli/js/lib.deno_runtime.d.ts index 0fa183348..05553ffb7 100644 --- a/cli/js/lib.deno_runtime.d.ts +++ b/cli/js/lib.deno_runtime.d.ts @@ -2128,9 +2128,9 @@ declare interface Window { performance: __performanceUtil.Performance; onmessage: (e: { data: any }) => void; onerror: undefined | typeof onerror; - workerMain: typeof __workers.workerMain; - workerClose: typeof __workers.workerClose; - postMessage: typeof __workers.postMessage; + workerMain: typeof __workerMain.workerMain; + workerClose: typeof __workerMain.workerClose; + postMessage: typeof __workerMain.postMessage; Worker: typeof __workers.WorkerImpl; addEventListener: ( type: string, @@ -2187,9 +2187,9 @@ declare let onerror: e: Event ) => boolean | void) | undefined; -declare const workerMain: typeof __workers.workerMain; -declare const workerClose: typeof __workers.workerClose; -declare const postMessage: typeof __workers.postMessage; +declare const workerMain: typeof __workerMain.workerMain; +declare const workerClose: typeof __workerMain.workerClose; +declare const postMessage: typeof __workerMain.postMessage; declare const Worker: typeof __workers.WorkerImpl; declare const addEventListener: ( type: string, @@ -3437,31 +3437,25 @@ declare namespace __url { }; } -declare namespace __workers { - // @url js/workers.d.ts - - export function encodeMessage(data: any): Uint8Array; - export function decodeMessage(dataIntArray: Uint8Array): any; +declare namespace __workerMain { export let onmessage: (e: { data: any }) => void; export function postMessage(data: any): void; export function getMessage(): Promise<any>; export let isClosing: boolean; export function workerClose(): void; export function workerMain(): Promise<void>; +} + +declare namespace __workers { + // @url js/workers.d.ts export interface Worker { onerror?: (e: Event) => void; onmessage?: (e: { data: any }) => void; onmessageerror?: () => void; postMessage(data: any): void; - closed: Promise<void>; } - export interface WorkerOptions {} - /** Extended Deno Worker initialization options. - * `noDenoNamespace` hides global `window.Deno` namespace for - * spawned worker and nested workers spawned by it (default: false). - */ - export interface DenoWorkerOptions extends WorkerOptions { - noDenoNamespace?: boolean; + export interface WorkerOptions { + type?: "classic" | "module"; } export class WorkerImpl implements Worker { private readonly id; @@ -3470,8 +3464,7 @@ declare namespace __workers { onerror?: (e: Event) => void; onmessage?: (data: any) => void; onmessageerror?: () => void; - constructor(specifier: string, options?: DenoWorkerOptions); - readonly closed: Promise<void>; + constructor(specifier: string, options?: WorkerOptions); postMessage(data: any): void; private run; } diff --git a/cli/js/worker_main.ts b/cli/js/worker_main.ts new file mode 100644 index 000000000..cb70057ea --- /dev/null +++ b/cli/js/worker_main.ts @@ -0,0 +1,98 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { core } from "./core.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"; + +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); + +function encodeMessage(data: any): Uint8Array { + const dataJson = JSON.stringify(data); + return encoder.encode(dataJson); +} + +function decodeMessage(dataIntArray: Uint8Array): any { + const dataJson = decoder.decode(dataIntArray); + return JSON.parse(dataJson); +} + +// 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 dataIntArray = encodeMessage(data); + 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) { + return decodeMessage(new Uint8Array(res.data)); + } else { + return null; + } +} + +export let isClosing = false; + +export function workerClose(): void { + isClosing = true; +} + +export async function workerMain(): Promise<void> { + const ops = core.ops(); + // TODO(bartlomieju): this is a prototype, we should come up with + // something a bit more sophisticated + for (const [name, opId] of Object.entries(ops)) { + const opName = `OP_${name.toUpperCase()}`; + // Assign op ids to actual variables + // TODO(ry) This type casting is gross and should be fixed. + ((dispatch as unknown) as { [key: string]: number })[opName] = opId; + core.setAsyncHandler(opId, dispatch.getAsyncHandler(opName)); + } + + log("workerMain"); + + while (!isClosing) { + const data = await getMessage(); + if (data == null) { + log("workerMain 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; + } + } +} diff --git a/cli/js/workers.ts b/cli/js/workers.ts index 7e8219e19..60ef73da0 100644 --- a/cli/js/workers.ts +++ b/cli/js/workers.ts @@ -2,35 +2,35 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as dispatch from "./dispatch.ts"; import { sendAsync, sendSync } from "./dispatch_json.ts"; -import { log, createResolvable, Resolvable } from "./util.ts"; +import { log } from "./util.ts"; import { TextDecoder, TextEncoder } from "./text_encoding.ts"; +/* import { blobURLMap } from "./url.ts"; import { blobBytesWeakMap } from "./blob.ts"; +*/ import { Event } from "./event.ts"; import { EventTarget } from "./event_target.ts"; const encoder = new TextEncoder(); const decoder = new TextDecoder(); -export function encodeMessage(data: any): Uint8Array { +function encodeMessage(data: any): Uint8Array { const dataJson = JSON.stringify(data); return encoder.encode(dataJson); } -export function decodeMessage(dataIntArray: Uint8Array): any { +function decodeMessage(dataIntArray: Uint8Array): any { const dataJson = decoder.decode(dataIntArray); return JSON.parse(dataJson); } function createWorker( specifier: string, - includeDenoNamespace: boolean, hasSourceCode: boolean, sourceCode: Uint8Array ): { id: number; loaded: boolean } { return sendSync(dispatch.OP_CREATE_WORKER, { specifier, - includeDenoNamespace, hasSourceCode, sourceCode: new TextDecoder().decode(sourceCode) }); @@ -67,92 +67,15 @@ async function hostGetMessage(id: number): Promise<any> { } } -// 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 dataIntArray = encodeMessage(data); - 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) { - return decodeMessage(new Uint8Array(res.data)); - } else { - return null; - } -} - -export let isClosing = false; - -export function workerClose(): void { - isClosing = true; -} - -export async function workerMain(): Promise<void> { - log("workerMain"); - - while (!isClosing) { - const data = await getMessage(); - if (data == null) { - log("workerMain 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 interface Worker { onerror?: (e: any) => void; onmessage?: (e: { data: any }) => void; onmessageerror?: () => void; postMessage(data: any): void; - // TODO(bartlomieju): remove this - closed: Promise<void>; } -// TODO(kevinkassimo): Maybe implement reasonable web worker options? -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface WorkerOptions {} - -/** Extended Deno Worker initialization options. - * `noDenoNamespace` hides global `globalThis.Deno` namespace for - * spawned worker and nested workers spawned by it (default: false). - */ -export interface DenoWorkerOptions extends WorkerOptions { - noDenoNamespace?: boolean; +export interface WorkerOptions { + type?: "classic" | "module"; } export class WorkerImpl extends EventTarget implements Worker { @@ -160,20 +83,29 @@ export class WorkerImpl extends EventTarget implements Worker { private isClosing = false; private messageBuffer: any[] = []; private ready = false; - private readonly isClosedPromise: Resolvable<void>; public onerror?: (e: any) => void; public onmessage?: (data: any) => void; public onmessageerror?: () => void; - constructor(specifier: string, options?: DenoWorkerOptions) { + constructor(specifier: string, options?: WorkerOptions) { super(); - let hasSourceCode = false; - let sourceCode = new Uint8Array(); - let includeDenoNamespace = true; - if (options && options.noDenoNamespace) { - includeDenoNamespace = false; + let type = "classic"; + + if (options?.type) { + type = options.type; + } + + if (type !== "module") { + throw new Error( + 'Not yet implemented: only "module" type workers are supported' + ); } + + const hasSourceCode = false; + const sourceCode = new Uint8Array(); + + /* TODO(bartlomieju): // Handle blob URL. if (specifier.startsWith("blob:")) { hasSourceCode = true; @@ -187,23 +119,14 @@ export class WorkerImpl extends EventTarget implements Worker { } sourceCode = blobBytes!; } + */ - const { id, loaded } = createWorker( - specifier, - includeDenoNamespace, - hasSourceCode, - sourceCode - ); + const { id, loaded } = createWorker(specifier, hasSourceCode, sourceCode); this.id = id; this.ready = loaded; - this.isClosedPromise = createResolvable(); this.poll(); } - get closed(): Promise<void> { - return this.isClosedPromise; - } - private handleError(e: any): boolean { // TODO: this is being handled in a type unsafe way, it should be type safe // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -259,7 +182,6 @@ export class WorkerImpl extends EventTarget implements Worker { } else { this.isClosing = true; hostCloseWorker(this.id); - this.isClosedPromise.resolve(); break; } } |