@jkcfg/std
Version:
jk standard library
110 lines (109 loc) • 4.38 kB
JavaScript
import { __std } from './__std_generated';
import { flatbuffers } from './flatbuffers';
const deferreds = new Map();
function recv(buf) {
const data = new flatbuffers.ByteBuffer(new Uint8Array(buf));
const reso = __std.Fulfilment.getRootAsFulfilment(data);
const ser = reso.serial().toFloat64();
let callback;
let value;
switch (reso.valueType()) {
case __std.FulfilmentValue.Data: {
({ data: callback } = deferreds.get(ser));
const val = new __std.Data();
reso.value(val);
value = val.bytesArray();
break;
}
case __std.FulfilmentValue.Error: {
const { error: errorCallback } = deferreds.get(ser);
if (errorCallback === undefined) {
return;
}
const err = new __std.Error();
reso.value(err);
const error = new Error(err.message());
errorCallback(error);
return;
}
case __std.FulfilmentValue.EndOfStream:
({ end: callback } = deferreds.get(ser));
break;
default:
throw new Error('Unknown message received from runtime');
}
if (callback === undefined) {
// for now, drop it, on the presumption that cancelation is
// underway.
return;
}
callback(value);
}
// `recv` is our handler for bytes sent ad-hoc from the runtime.
V8Worker2.recv(recv);
// registerCallbacks records callbacks for the three possible outcomes
// of a deferred, which is identified by a serial number returned from
// Go.
function registerCallbacks(serial, onData, onError, onEnd) {
deferreds.set(serial, { data: onData, error: onError, end: onEnd });
}
function panic(msg) {
return () => { throw new Error(msg); };
}
// sendRequest sends an ArrayBuffer to the jk runtime and returns the
// ArrayBuffer response.
function sendRequest(buf) {
return V8Worker2.send(buf);
}
// requestAsPromise performs the request given, and wraps the deferred
// result in a promise. If the request provokes an error, the Promise
// is rejected immediately; otherwise, the Promise will later be
// resolved or rejected depending on what is sent by the runtime.
function requestAsPromise(req, tx) {
const buf = req();
const data = new flatbuffers.ByteBuffer(new Uint8Array(buf));
const resp = __std.DeferredResponse.getRootAsDeferredResponse(data);
switch (resp.retvalType()) {
case __std.DeferredRetval.Error: {
const err = new __std.Error();
resp.retval(err);
return Promise.reject(new Error(err.message()));
}
case __std.DeferredRetval.Deferred: {
const stackCapture = new Error();
const defer = new __std.Deferred();
resp.retval(defer);
const ser = defer.serial().toFloat64();
return new Promise((resolve, reject) => {
function removeThenCall(v) {
deferreds.delete(ser);
return this(v);
}
function rejectWithStack(err) {
/* eslint-disable no-param-reassign */
err.stack += stackCapture.stack.substring(stackCapture.stack.indexOf('\n'));
/* eslint-enable */
reject(err);
}
const ondata = (bytes) => resolve(tx(bytes));
registerCallbacks(ser, removeThenCall.bind(ondata), removeThenCall.bind(rejectWithStack), removeThenCall.bind(panic('Unexpected EndOfStream for promisified deferred')));
});
}
default:
return Promise.reject(new Error('Failed to decode response from request'));
}
}
// TODO
function cancel(serial) {
const builder = new flatbuffers.Builder(512);
__std.CancelArgs.startCancelArgs(builder);
__std.CancelArgs.addSerial(builder, builder.createLong(serial, 0));
const argsOffset = __std.CancelArgs.endCancelArgs(builder);
__std.Message.startMessage(builder);
__std.Message.addArgsType(builder, __std.Args.CancelArgs);
__std.Message.addArgs(builder, argsOffset);
const messageOffset = __std.Message.endMessage(builder);
builder.finish(messageOffset);
return sendRequest(builder.asArrayBuffer());
}
export { requestAsPromise, sendRequest, cancel, };