summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/dispatch.ts15
-rw-r--r--js/dispatch_flatbuffers.ts2
-rw-r--r--js/dispatch_json.ts94
-rw-r--r--js/dispatch_minimal.ts2
-rw-r--r--js/os.ts63
-rw-r--r--js/utime.ts37
6 files changed, 137 insertions, 76 deletions
diff --git a/js/dispatch.ts b/js/dispatch.ts
index 423469d38..0c5c59553 100644
--- a/js/dispatch.ts
+++ b/js/dispatch.ts
@@ -1,20 +1,29 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as minimal from "./dispatch_minimal";
import * as flatbuffers from "./dispatch_flatbuffers";
+import * as json from "./dispatch_json";
// These consts are shared with Rust. Update with care.
export const OP_FLATBUFFER = 44;
export const OP_READ = 1;
export const OP_WRITE = 2;
+export const OP_EXIT = 3;
+export const OP_IS_TTY = 4;
+export const OP_ENV = 5;
+export const OP_EXEC_PATH = 6;
+export const OP_UTIME = 7;
-export function handleAsyncMsgFromRust(opId: number, ui8: Uint8Array): void {
+export function asyncMsgFromRust(opId: number, ui8: Uint8Array): void {
switch (opId) {
case OP_FLATBUFFER:
- flatbuffers.handleAsyncMsgFromRust(opId, ui8);
+ flatbuffers.asyncMsgFromRust(opId, ui8);
break;
case OP_WRITE:
case OP_READ:
- minimal.handleAsyncMsgFromRust(opId, ui8);
+ minimal.asyncMsgFromRust(opId, ui8);
+ break;
+ case OP_UTIME:
+ json.asyncMsgFromRust(opId, ui8);
break;
default:
throw Error("bad opId");
diff --git a/js/dispatch_flatbuffers.ts b/js/dispatch_flatbuffers.ts
index 87a01037c..0e375dbdf 100644
--- a/js/dispatch_flatbuffers.ts
+++ b/js/dispatch_flatbuffers.ts
@@ -19,7 +19,7 @@ interface FlatbufferRecord {
base: msg.Base;
}
-export function handleAsyncMsgFromRust(opId: number, ui8: Uint8Array): void {
+export function asyncMsgFromRust(opId: number, ui8: Uint8Array): void {
let { promiseId, base } = flatbufferRecordFromBuf(ui8);
const promise = promiseTable.get(promiseId);
util.assert(promise != null, `Expecting promise in table. ${promiseId}`);
diff --git a/js/dispatch_json.ts b/js/dispatch_json.ts
new file mode 100644
index 000000000..e8c976164
--- /dev/null
+++ b/js/dispatch_json.ts
@@ -0,0 +1,94 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+// Do not add flatbuffer dependencies to this module.
+// TODO(ry) Currently ErrorKind enum is defined in FlatBuffers. Therefore
+// we must still reference the msg_generated.ts. This should be removed!
+import { ErrorKind } from "gen/cli/msg_generated";
+import * as util from "./util";
+import { TextEncoder, TextDecoder } from "./text_encoding";
+import { core } from "./core";
+import { DenoError } from "./errors";
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+type Ok = any;
+
+interface JsonError {
+ kind: ErrorKind;
+ message: string;
+}
+
+interface JsonResponse {
+ ok?: Ok;
+ err?: JsonError;
+ promiseId?: number; // only present in async mesasges.
+}
+
+const promiseTable = new Map<number, util.Resolvable<number>>();
+let _nextPromiseId = 1;
+
+function nextPromiseId(): number {
+ return _nextPromiseId++;
+}
+
+function decode(ui8: Uint8Array): JsonResponse {
+ const s = new TextDecoder().decode(ui8);
+ return JSON.parse(s) as JsonResponse;
+}
+
+function encode(args: object): Uint8Array {
+ const s = JSON.stringify(args);
+ return new TextEncoder().encode(s);
+}
+
+function toDenoError(err: JsonError): DenoError<ErrorKind> {
+ return new DenoError(err.kind, err.message);
+}
+
+export function asyncMsgFromRust(opId: number, res: Uint8Array): void {
+ const { ok, err, promiseId } = decode(res);
+ const promise = promiseTable.get(promiseId!)!;
+ if (!promise) {
+ throw Error(`Async op ${opId} had bad promiseId`);
+ }
+ promiseTable.delete(promiseId!);
+
+ if (err) {
+ promise.reject(toDenoError(err));
+ } else if (ok) {
+ promise.resolve(ok);
+ } else {
+ util.unreachable();
+ }
+}
+
+export function sendSync(
+ opId: number,
+ args: object = {},
+ zeroCopy?: Uint8Array
+): Ok {
+ const argsUi8 = encode(args);
+ const res = core.dispatch(opId, argsUi8, zeroCopy);
+ if (!res) {
+ return;
+ }
+ const { ok, err, promiseId } = decode(res);
+ util.assert(!promiseId);
+ if (err) {
+ throw toDenoError(err);
+ }
+ return ok;
+}
+
+export function sendAsync(
+ opId: number,
+ args: object = {},
+ zeroCopy?: Uint8Array
+): Promise<Ok> {
+ const promiseId = nextPromiseId();
+ args = Object.assign(args, { promiseId });
+ const argsUi8 = encode(args);
+ const promise = util.createResolvable<Ok>();
+ promiseTable.set(promiseId, promise);
+ const r = core.dispatch(opId, argsUi8, zeroCopy);
+ util.assert(!r);
+ return promise;
+}
diff --git a/js/dispatch_minimal.ts b/js/dispatch_minimal.ts
index fc3fc61b9..9a310fd22 100644
--- a/js/dispatch_minimal.ts
+++ b/js/dispatch_minimal.ts
@@ -40,7 +40,7 @@ const scratchBytes = new Uint8Array(
);
util.assert(scratchBytes.byteLength === scratch32.length * 4);
-export function handleAsyncMsgFromRust(opId: number, ui8: Uint8Array): void {
+export function asyncMsgFromRust(opId: number, ui8: Uint8Array): void {
const buf32 = new Int32Array(ui8.buffer, ui8.byteOffset, ui8.byteLength / 4);
const record = recordFromBufMinimal(opId, buf32);
const { promiseId, result } = record;
diff --git a/js/os.ts b/js/os.ts
index 59c44145d..f8938ab70 100644
--- a/js/os.ts
+++ b/js/os.ts
@@ -1,7 +1,8 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { core } from "./core";
-import { handleAsyncMsgFromRust } from "./dispatch";
+import * as dispatch from "./dispatch";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
+import * as dispatchJson from "./dispatch_json";
import { assert } from "./util";
import * as util from "./util";
import { window } from "./window";
@@ -23,21 +24,12 @@ function setGlobals(pid_: number, noColor_: boolean): void {
* console.log(Deno.isTTY().stdout);
*/
export function isTTY(): { stdin: boolean; stdout: boolean; stderr: boolean } {
- const builder = flatbuffers.createBuilder();
- const inner = msg.IsTTY.createIsTTY(builder);
- const baseRes = sendSync(builder, msg.Any.IsTTY, inner)!;
- assert(msg.Any.IsTTYRes === baseRes.innerType());
- const res = new msg.IsTTYRes();
- assert(baseRes.inner(res) != null);
-
- return { stdin: res.stdin(), stdout: res.stdout(), stderr: res.stderr() };
+ return dispatchJson.sendSync(dispatch.OP_IS_TTY);
}
/** Exit the Deno process with optional exit code. */
-export function exit(exitCode = 0): never {
- const builder = flatbuffers.createBuilder();
- const inner = msg.Exit.createExit(builder, exitCode);
- sendSync(builder, msg.Any.Exit, inner);
+export function exit(code = 0): never {
+ dispatchJson.sendSync(dispatch.OP_EXIT, { code });
return util.unreachable();
}
@@ -49,22 +41,6 @@ function setEnv(key: string, value: string): void {
sendSync(builder, msg.Any.SetEnv, inner);
}
-function createEnv(inner: msg.EnvironRes): { [index: string]: string } {
- const env: { [index: string]: string } = {};
-
- for (let i = 0; i < inner.mapLength(); i++) {
- const item = inner.map(i)!;
- env[item.key()!] = item.value()!;
- }
-
- return new Proxy(env, {
- set(obj, prop: string, value: string): boolean {
- setEnv(prop, value);
- return Reflect.set(obj, prop, value);
- }
- });
-}
-
/** Returns a snapshot of the environment variables at invocation. Mutating a
* property in the object will set that variable in the environment for
* the process. The environment object will only accept `string`s
@@ -77,19 +53,13 @@ function createEnv(inner: msg.EnvironRes): { [index: string]: string } {
* console.log(myEnv.TEST_VAR == newEnv.TEST_VAR);
*/
export function env(): { [index: string]: string } {
- /* Ideally we could write
- const res = sendSync({
- command: msg.Command.ENV,
+ const env = dispatchJson.sendSync(dispatch.OP_ENV);
+ return new Proxy(env, {
+ set(obj, prop: string, value: string): boolean {
+ setEnv(prop, value);
+ return Reflect.set(obj, prop, value);
+ }
});
- */
- const builder = flatbuffers.createBuilder();
- const inner = msg.Environ.createEnviron(builder);
- const baseRes = sendSync(builder, msg.Any.Environ, inner)!;
- assert(msg.Any.EnvironRes === baseRes.innerType());
- const res = new msg.EnvironRes();
- assert(baseRes.inner(res) != null);
- // TypeScript cannot track assertion above, therefore not null assertion
- return createEnv(res);
}
/** Send to the privileged side that we have setup and are ready. */
@@ -111,7 +81,7 @@ export function start(
preserveDenoNamespace = true,
source?: string
): msg.StartRes {
- core.setAsyncHandler(handleAsyncMsgFromRust);
+ core.setAsyncHandler(dispatch.asyncMsgFromRust);
// First we send an empty `Start` message to let the privileged side know we
// are ready. The response should be a `StartRes` message containing the CLI
@@ -163,12 +133,5 @@ export function homeDir(): string {
* Requires the `--allow-env` flag.
*/
export function execPath(): string {
- const builder = flatbuffers.createBuilder();
- const inner = msg.ExecPath.createExecPath(builder);
- const baseRes = sendSync(builder, msg.Any.ExecPath, inner)!;
- assert(msg.Any.ExecPathRes === baseRes.innerType());
- const res = new msg.ExecPathRes();
- assert(baseRes.inner(res) != null);
- const path = res.path()!;
- return path;
+ return dispatchJson.sendSync(dispatch.OP_EXEC_PATH);
}
diff --git a/js/utime.ts b/js/utime.ts
index 89914b4ca..c71710458 100644
--- a/js/utime.ts
+++ b/js/utime.ts
@@ -1,24 +1,9 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-import { sendSync, sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers";
-import * as util from "./util";
+import { sendSync, sendAsync } from "./dispatch_json";
+import { OP_UTIME } from "./dispatch";
-function req(
- filename: string,
- atime: number | Date,
- mtime: number | Date
-): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
- const atimeSec = atime instanceof Date ? Math.floor(+atime / 1000) : atime;
- const mtimeSec = mtime instanceof Date ? Math.floor(+mtime / 1000) : mtime;
-
- const builder = flatbuffers.createBuilder();
- const filename_ = builder.createString(filename);
- const atimeParts = util.splitNumberToParts(atimeSec);
- const atimeMS_ = builder.createLong(atimeParts[0], atimeParts[1]);
- const mtimeParts = util.splitNumberToParts(mtimeSec);
- const mtimeMS_ = builder.createLong(mtimeParts[0], mtimeParts[1]);
-
- const inner = msg.Utime.createUtime(builder, filename_, atimeMS_, mtimeMS_);
- return [builder, msg.Any.Utime, inner];
+function toSecondsFromEpoch(v: number | Date): number {
+ return v instanceof Date ? v.valueOf() / 1000 : v;
}
/** Synchronously changes the access and modification times of a file system
@@ -32,7 +17,12 @@ export function utimeSync(
atime: number | Date,
mtime: number | Date
): void {
- sendSync(...req(filename, atime, mtime));
+ sendSync(OP_UTIME, {
+ filename,
+ // TODO(ry) split atime, mtime into [seconds, nanoseconds] tuple
+ atime: toSecondsFromEpoch(atime),
+ mtime: toSecondsFromEpoch(mtime)
+ });
}
/** Changes the access and modification times of a file system object
@@ -46,5 +36,10 @@ export async function utime(
atime: number | Date,
mtime: number | Date
): Promise<void> {
- await sendAsync(...req(filename, atime, mtime));
+ await sendAsync(OP_UTIME, {
+ filename,
+ // TODO(ry) split atime, mtime into [seconds, nanoseconds] tuple
+ atime: toSecondsFromEpoch(atime),
+ mtime: toSecondsFromEpoch(mtime)
+ });
}