diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2019-08-21 20:42:48 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-21 20:42:48 -0400 |
commit | bdc97b3976786bb744a27e59b0f4f28554a682df (patch) | |
tree | bf4635ad903de542c10620e95adb72eee03d9204 /js/dispatch_flatbuffers.ts | |
parent | b764d1b8ffc4bf5e2ab89bdbd978d708a6da0f24 (diff) |
Organize dispatch a bit (#2796)
Just some clean up reorganization around flatbuffer/minimal dispatch
code. This is prep for adding a JSON dispatcher.
Diffstat (limited to 'js/dispatch_flatbuffers.ts')
-rw-r--r-- | js/dispatch_flatbuffers.ts | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/js/dispatch_flatbuffers.ts b/js/dispatch_flatbuffers.ts new file mode 100644 index 000000000..87a01037c --- /dev/null +++ b/js/dispatch_flatbuffers.ts @@ -0,0 +1,151 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +import * as flatbuffers from "./flatbuffers"; +import { DenoError } from "./errors"; +import { core } from "./core"; +import * as msg from "gen/cli/msg_generated"; +import * as util from "./util"; +import { OP_FLATBUFFER } from "./dispatch"; +export { msg, flatbuffers }; + +const promiseTable = new Map<number, util.Resolvable<msg.Base>>(); +let _nextPromiseId = 1; + +export function nextPromiseId(): number { + return _nextPromiseId++; +} + +interface FlatbufferRecord { + promiseId: number; + base: msg.Base; +} + +export function handleAsyncMsgFromRust(opId: number, ui8: Uint8Array): void { + let { promiseId, base } = flatbufferRecordFromBuf(ui8); + const promise = promiseTable.get(promiseId); + util.assert(promise != null, `Expecting promise in table. ${promiseId}`); + promiseTable.delete(promiseId); + const err = maybeError(base); + if (err != null) { + promise!.reject(err); + } else { + promise!.resolve(base); + } +} + +function flatbufferRecordFromBuf(buf: Uint8Array): FlatbufferRecord { + const bb = new flatbuffers.ByteBuffer(buf); + const base = msg.Base.getRootAsBase(bb); + return { + promiseId: base.cmdId(), + base + }; +} + +function ui8FromArrayBufferView(abv: ArrayBufferView): Uint8Array { + return new Uint8Array(abv.buffer, abv.byteOffset, abv.byteLength); +} + +function sendInternal( + builder: flatbuffers.Builder, + innerType: msg.Any, + inner: flatbuffers.Offset, + zeroCopy: undefined | ArrayBufferView, + isSync: true +): Uint8Array; +function sendInternal( + builder: flatbuffers.Builder, + innerType: msg.Any, + inner: flatbuffers.Offset, + zeroCopy: undefined | ArrayBufferView, + isSync: false +): Promise<msg.Base>; +function sendInternal( + builder: flatbuffers.Builder, + innerType: msg.Any, + inner: flatbuffers.Offset, + zeroCopy: undefined | ArrayBufferView, + isSync: boolean +): Promise<msg.Base> | Uint8Array { + const cmdId = nextPromiseId(); + msg.Base.startBase(builder); + msg.Base.addInner(builder, inner); + msg.Base.addInnerType(builder, innerType); + msg.Base.addSync(builder, isSync); + msg.Base.addCmdId(builder, cmdId); + builder.finish(msg.Base.endBase(builder)); + + const control = builder.asUint8Array(); + + const response = core.dispatch( + OP_FLATBUFFER, // TODO(ry) Use actual opId later. + control, + zeroCopy ? ui8FromArrayBufferView(zeroCopy) : undefined + ); + + builder.inUse = false; + + if (response == null) { + util.assert(!isSync); + const promise = util.createResolvable<msg.Base>(); + promiseTable.set(cmdId, promise); + return promise; + } else { + if (!isSync) { + // We can easily and correctly allow for sync responses to async calls + // by creating and returning a promise from the sync response. + const bb = new flatbuffers.ByteBuffer(response); + const base = msg.Base.getRootAsBase(bb); + const err = maybeError(base); + if (err != null) { + return Promise.reject(err); + } else { + return Promise.resolve(base); + } + } + return response; + } +} + +// @internal +export function sendAsync( + builder: flatbuffers.Builder, + innerType: msg.Any, + inner: flatbuffers.Offset, + data?: ArrayBufferView +): Promise<msg.Base> { + return sendInternal(builder, innerType, inner, data, false); +} + +// @internal +export function sendSync( + builder: flatbuffers.Builder, + innerType: msg.Any, + inner: flatbuffers.Offset, + data?: ArrayBufferView +): null | msg.Base { + const response = sendInternal(builder, innerType, inner, data, true); + if (response!.length === 0) { + return null; + } else { + const bb = new flatbuffers.ByteBuffer(response!); + const baseRes = msg.Base.getRootAsBase(bb); + maybeThrowError(baseRes); + return baseRes; + } +} + +function maybeError(base: msg.Base): null | DenoError<msg.ErrorKind> { + const kind = base.errorKind(); + if (kind === msg.ErrorKind.NoError) { + return null; + } else { + return new DenoError(kind, base.error()!); + } +} + +function maybeThrowError(base: msg.Base): void { + const err = maybeError(base); + if (err != null) { + throw err; + } +} |