Revert json ops (#2814)

* Revert "port more ops to JSON (#2809)"

This reverts commit 137f33733d.

* Revert "port ops to JSON: compiler, errors, fetch, files (#2804)"

This reverts commit 79f82cf10e.

* Revert "Port rest of os ops to JSON (#2802)"

This reverts commit 5b2baa5c99.
This commit is contained in:
Ryan Dahl 2019-08-24 13:20:48 -07:00 committed by GitHub
parent bdc0a13261
commit 2235dd795d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 1968 additions and 1045 deletions

View file

@ -7,11 +7,9 @@ import { Console } from "./console";
import { core } from "./core";
import { Diagnostic, fromTypeScriptDiagnostic } from "./diagnostics";
import { cwd } from "./dir";
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
import { msg } from "./dispatch_flatbuffers";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import * as os from "./os";
import { TextEncoder } from "./text_encoding";
import { TextDecoder, TextEncoder } from "./text_encoding";
import { getMappedModuleName, parseTypeDirectives } from "./type_directives";
import { assert, notImplemented } from "./util";
import * as util from "./util";
@ -123,15 +121,35 @@ interface EmitResult {
/** Ops to Rust to resolve and fetch a modules meta data. */
function fetchSourceFile(specifier: string, referrer: string): SourceFile {
util.log("compiler.fetchSourceFile", { specifier, referrer });
const res = sendSync(dispatch.OP_FETCH_SOURCE_FILE, {
specifier,
referrer
});
util.log("fetchSourceFile", { specifier, referrer });
// Send FetchSourceFile message
const builder = flatbuffers.createBuilder();
const specifier_ = builder.createString(specifier);
const referrer_ = builder.createString(referrer);
const inner = msg.FetchSourceFile.createFetchSourceFile(
builder,
specifier_,
referrer_
);
const baseRes = sendSync(builder, msg.Any.FetchSourceFile, inner);
assert(baseRes != null);
assert(
msg.Any.FetchSourceFileRes === baseRes!.innerType(),
`base.innerType() unexpectedly is ${baseRes!.innerType()}`
);
const fetchSourceFileRes = new msg.FetchSourceFileRes();
assert(baseRes!.inner(fetchSourceFileRes) != null);
const dataArray = fetchSourceFileRes.dataArray();
const decoder = new TextDecoder();
const sourceCode = dataArray ? decoder.decode(dataArray) : undefined;
// flatbuffers returns `null` for an empty value, this does not fit well with
// idiomatic TypeScript under strict null checks, so converting to `undefined`
return {
...res,
typeDirectives: parseTypeDirectives(res.sourceCode)
moduleName: fetchSourceFileRes.moduleName() || undefined,
filename: fetchSourceFileRes.filename() || undefined,
mediaType: fetchSourceFileRes.mediaType(),
sourceCode,
typeDirectives: parseTypeDirectives(sourceCode)
};
}
@ -153,7 +171,19 @@ function humanFileSize(bytes: number): string {
/** Ops to rest for caching source map and compiled js */
function cache(extension: string, moduleId: string, contents: string): void {
sendSync(dispatch.OP_CACHE, { extension, moduleId, contents });
util.log("cache", extension, moduleId);
const builder = flatbuffers.createBuilder();
const extension_ = builder.createString(extension);
const moduleId_ = builder.createString(moduleId);
const contents_ = builder.createString(contents);
const inner = msg.Cache.createCache(
builder,
extension_,
moduleId_,
contents_
);
const baseRes = sendSync(builder, msg.Any.Cache, inner);
assert(baseRes == null);
}
const encoder = new TextEncoder();

View file

@ -12,40 +12,6 @@ export const OP_IS_TTY = 4;
export const OP_ENV = 5;
export const OP_EXEC_PATH = 6;
export const OP_UTIME = 7;
export const OP_SET_ENV = 8;
export const OP_HOME_DIR = 9;
export const OP_START = 10;
export const OP_APPLY_SOURCE_MAP = 11;
export const OP_FORMAT_ERROR = 12;
export const OP_CACHE = 13;
export const OP_FETCH_SOURCE_FILE = 14;
export const OP_OPEN = 15;
export const OP_CLOSE = 16;
export const OP_SEEK = 17;
export const OP_FETCH = 18;
export const OP_METRICS = 19;
export const OP_REPL_START = 20;
export const OP_REPL_READLINE = 21;
export const OP_ACCEPT = 22;
export const OP_DIAL = 23;
export const OP_SHUTDOWN = 24;
export const OP_LISTEN = 25;
export const OP_RESOURCES = 26;
export const OP_GET_RANDOM_VALUES = 27;
export const OP_GLOBAL_TIMER_STOP = 28;
export const OP_GLOBAL_TIMER = 29;
export const OP_NOW = 30;
export const OP_PERMISSIONS = 31;
export const OP_REVOKE_PERMISSION = 32;
export const OP_CREATE_WORKER = 33;
export const OP_HOST_GET_WORKER_CLOSED = 34;
export const OP_HOST_POST_MESSAGE = 35;
export const OP_HOST_GET_MESSAGE = 36;
export const OP_WORKER_POST_MESSAGE = 37;
export const OP_WORKER_GET_MESSAGE = 38;
export const OP_RUN = 39;
export const OP_RUN_STATUS = 40;
export const OP_KILL = 41;
export function asyncMsgFromRust(opId: number, ui8: Uint8Array): void {
switch (opId) {
@ -56,26 +22,10 @@ export function asyncMsgFromRust(opId: number, ui8: Uint8Array): void {
case OP_READ:
minimal.asyncMsgFromRust(opId, ui8);
break;
case OP_EXIT:
case OP_IS_TTY:
case OP_ENV:
case OP_EXEC_PATH:
case OP_UTIME:
case OP_OPEN:
case OP_SEEK:
case OP_FETCH:
case OP_REPL_START:
case OP_REPL_READLINE:
case OP_ACCEPT:
case OP_DIAL:
case OP_GLOBAL_TIMER:
case OP_HOST_GET_WORKER_CLOSED:
case OP_HOST_GET_MESSAGE:
case OP_WORKER_GET_MESSAGE:
case OP_RUN_STATUS:
json.asyncMsgFromRust(opId, ui8);
break;
default:
throw Error("bad async opId");
throw Error("bad opId");
}
}

View file

@ -1,8 +1,8 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
// Some of the code here is adapted directly from V8 and licensed under a BSD
// style license available here: https://github.com/v8/v8/blob/24886f2d1c565287d33d71e4109a53bf0b54b75c/LICENSE.v8
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { assert } from "./util";
export interface Location {
@ -17,6 +17,40 @@ export interface Location {
column: number;
}
function req(
filename: string,
line: number,
column: number
): [flatbuffers.Builder, msg.Any.ApplySourceMap, flatbuffers.Offset] {
const builder = flatbuffers.createBuilder();
const filename_ = builder.createString(filename);
const inner = msg.ApplySourceMap.createApplySourceMap(
builder,
filename_,
// On this side, line/column are 1 based, but in the source maps, they are
// 0 based, so we have to convert back and forth
line - 1,
column - 1
);
return [builder, msg.Any.ApplySourceMap, inner];
}
function res(baseRes: msg.Base | null): Location {
assert(baseRes != null);
assert(baseRes!.innerType() === msg.Any.ApplySourceMap);
const res = new msg.ApplySourceMap();
assert(baseRes!.inner(res) != null);
const filename = res.filename()!;
assert(filename != null);
return {
filename,
// On this side, line/column are 1 based, but in the source maps, they are
// 0 based, so we have to convert back and forth
line: res.line() + 1,
column: res.column() + 1
};
}
/** Given a current location in a module, lookup the source location and
* return it.
*
@ -41,18 +75,7 @@ export interface Location {
*/
export function applySourceMap(location: Location): Location {
const { filename, line, column } = location;
// On this side, line/column are 1 based, but in the source maps, they are
// 0 based, so we have to convert back and forth
const res = sendSync(dispatch.OP_APPLY_SOURCE_MAP, {
filename,
line: line - 1,
column: column - 1
});
return {
filename: res.filename,
line: res.line + 1,
column: res.column + 1
};
return res(sendSync(...req(filename, line, column)));
}
/** Mutate the call site so that it returns the location, instead of its

View file

@ -1,5 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { assert, createResolvable, notImplemented, isTypedArray } from "./util";
import { sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers";
import * as domTypes from "./dom_types";
import { TextDecoder, TextEncoder } from "./text_encoding";
import { DenoBlob, bytesSymbol as blobBytesSymbol } from "./blob";
@ -9,8 +10,6 @@ import { read, close } from "./files";
import { Buffer } from "./buffer";
import { FormData } from "./form_data";
import { URLSearchParams } from "./url_search_params";
import * as dispatch from "./dispatch";
import { sendAsync } from "./dispatch_json";
function getHeaderValueParams(value: string): Map<string, string> {
const params = new Map();
@ -321,35 +320,67 @@ export class Response implements domTypes.Response {
}
}
interface FetchResponse {
bodyRid: number;
status: number;
headers: Array<[string, string]>;
function msgHttpRequest(
builder: flatbuffers.Builder,
url: string,
method: null | string,
headers: null | domTypes.Headers
): flatbuffers.Offset {
const methodOffset = !method ? 0 : builder.createString(method);
let fieldsOffset: flatbuffers.Offset = 0;
const urlOffset = builder.createString(url);
if (headers) {
const kvOffsets: flatbuffers.Offset[] = [];
for (const [key, val] of headers.entries()) {
const keyOffset = builder.createString(key);
const valOffset = builder.createString(val);
kvOffsets.push(
msg.KeyValue.createKeyValue(builder, keyOffset, valOffset)
);
}
fieldsOffset = msg.HttpHeader.createFieldsVector(builder, kvOffsets);
} else {
}
return msg.HttpHeader.createHttpHeader(
builder,
true,
methodOffset,
urlOffset,
0,
fieldsOffset
);
}
async function sendFetchReq(
function deserializeHeaderFields(m: msg.HttpHeader): Array<[string, string]> {
const out: Array<[string, string]> = [];
for (let i = 0; i < m.fieldsLength(); i++) {
const item = m.fields(i)!;
out.push([item.key()!, item.value()!]);
}
return out;
}
async function getFetchRes(
url: string,
method: string | null,
headers: domTypes.Headers | null,
body: ArrayBufferView | undefined
): Promise<FetchResponse> {
let headerArray: Array<[string, string]> = [];
if (headers) {
headerArray = Array.from(headers.entries());
}
): Promise<msg.FetchRes> {
// Send Fetch message
const builder = flatbuffers.createBuilder();
const headerOff = msgHttpRequest(builder, url, method, headers);
const resBase = await sendAsync(
builder,
msg.Any.Fetch,
msg.Fetch.createFetch(builder, headerOff),
body
);
let zeroCopy = undefined;
if (body) {
zeroCopy = new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
}
const args = {
method,
url,
headers: headerArray
};
return (await sendAsync(dispatch.OP_FETCH, args, zeroCopy)) as FetchResponse;
// Decode FetchRes
assert(msg.Any.FetchRes === resBase.innerType());
const inner = new msg.FetchRes();
assert(resBase.inner(inner) != null);
return inner;
}
/** Fetch a resource from the network. */
@ -417,13 +448,20 @@ export async function fetch(
}
while (remRedirectCount) {
const fetchResponse = await sendFetchReq(url, method, headers, body);
const inner = await getFetchRes(url, method, headers, body);
const header = inner.header()!;
const bodyRid = inner.bodyRid();
assert(!header.isRequest());
const status = header.status();
const headersList = deserializeHeaderFields(header);
const response = new Response(
url,
fetchResponse.status,
fetchResponse.headers,
fetchResponse.bodyRid,
status,
headersList,
bodyRid,
redirected
);
if ([301, 302, 303, 307, 308].includes(response.status)) {

View file

@ -12,22 +12,37 @@ import {
} from "./io";
import { sendAsyncMinimal } from "./dispatch_minimal";
import { assert } from "./util";
import * as dispatch from "./dispatch";
import {
sendSync as sendSyncJson,
sendAsync as sendAsyncJson
} from "./dispatch_json";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { sendAsync, sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { OP_READ, OP_WRITE } from "./dispatch";
function reqOpen(
filename: string,
mode: OpenMode
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
const builder = flatbuffers.createBuilder();
const filename_ = builder.createString(filename);
const mode_ = builder.createString(mode);
const inner = msg.Open.createOpen(builder, filename_, 0, mode_);
return [builder, msg.Any.Open, inner];
}
function resOpen(baseRes: null | msg.Base): File {
assert(baseRes != null);
assert(msg.Any.OpenRes === baseRes!.innerType());
const res = new msg.OpenRes();
assert(baseRes!.inner(res) != null);
const rid = res.rid();
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return new File(rid);
}
/** Open a file and return an instance of the `File` object
* synchronously.
*
* const file = Deno.openSync("/foo/bar.txt");
*/
export function openSync(filename: string, mode: OpenMode = "r"): File {
const rid = sendSyncJson(dispatch.OP_OPEN, { filename, mode });
return new File(rid);
return resOpen(sendSync(...reqOpen(filename, mode)));
}
/** Open a file and return an instance of the `File` object.
@ -40,8 +55,7 @@ export async function open(
filename: string,
mode: OpenMode = "r"
): Promise<File> {
const rid = await sendAsyncJson(dispatch.OP_OPEN, { filename, mode });
return new File(rid);
return resOpen(await sendAsync(...reqOpen(filename, mode)));
}
function reqRead(
@ -151,13 +165,23 @@ export async function write(rid: number, p: Uint8Array): Promise<number> {
}
}
function reqSeek(
rid: number,
offset: number,
whence: SeekMode
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
const builder = flatbuffers.createBuilder();
const inner = msg.Seek.createSeek(builder, rid, offset, whence);
return [builder, msg.Any.Seek, inner];
}
/** Seek a file ID synchronously to the given offset under mode given by `whence`.
*
* const file = Deno.openSync("/foo/bar.txt");
* Deno.seekSync(file.rid, 0, 0);
*/
export function seekSync(rid: number, offset: number, whence: SeekMode): void {
sendSyncJson(dispatch.OP_SEEK, { rid, offset, whence });
sendSync(...reqSeek(rid, offset, whence));
}
/** Seek a file ID to the given offset under mode given by `whence`.
@ -172,12 +196,14 @@ export async function seek(
offset: number,
whence: SeekMode
): Promise<void> {
await sendAsyncJson(dispatch.OP_SEEK, { rid, offset, whence });
await sendAsync(...reqSeek(rid, offset, whence));
}
/** Close the file ID. */
export function close(rid: number): void {
sendSyncJson(dispatch.OP_CLOSE, { rid });
const builder = flatbuffers.createBuilder();
const inner = msg.Close.createClose(builder, rid);
sendSync(builder, msg.Any.Close, inner);
}
/** The Deno abstraction for reading and writing files. */

View file

@ -1,9 +1,17 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { assert } from "./util";
// TODO(bartlomieju): move to `repl.ts`?
export function formatError(errString: string): string {
const res = sendSync(dispatch.OP_FORMAT_ERROR, { error: errString });
return res.error;
const builder = flatbuffers.createBuilder();
const errString_ = builder.createString(errString);
const offset = msg.FormatError.createFormatError(builder, errString_);
const baseRes = sendSync(builder, msg.Any.FormatError, offset);
assert(baseRes != null);
assert(msg.Any.FormatErrorRes === baseRes!.innerType());
const formatErrorResMsg = new msg.FormatErrorRes();
assert(baseRes!.inner(formatErrorResMsg) != null);
const formattedError = formatErrorResMsg.error();
assert(formatError != null);
return formattedError!;
}

View file

@ -1,8 +1,15 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { assert } from "./util";
function req(
typedArray: ArrayBufferView
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset, ArrayBufferView] {
const builder = flatbuffers.createBuilder();
const inner = msg.GetRandomValues.createGetRandomValues(builder);
return [builder, msg.Any.GetRandomValues, inner, typedArray];
}
/** Synchronously collects cryptographically secure random values. The
* underlying CSPRNG in use is Rust's `rand::rngs::ThreadRng`.
*
@ -21,11 +28,6 @@ export function getRandomValues<
>(typedArray: T): T {
assert(typedArray !== null, "Input must not be null");
assert(typedArray.length <= 65536, "Input must not be longer than 65536");
const ui8 = new Uint8Array(
typedArray.buffer,
typedArray.byteOffset,
typedArray.byteLength
);
sendSync(dispatch.OP_GET_RANDOM_VALUES, {}, ui8);
sendSync(...req(typedArray as ArrayBufferView));
return typedArray;
}

View file

@ -22,12 +22,12 @@ export default function denoMain(
preserveDenoNamespace: boolean = true,
name?: string
): void {
const s = os.start(preserveDenoNamespace, name);
const startResMsg = os.start(preserveDenoNamespace, name);
setVersions(s.denoVersion, s.v8Version);
setVersions(startResMsg.denoVersion()!, startResMsg.v8Version()!);
// handle `--version`
if (s.versionFlag) {
if (startResMsg.versionFlag()) {
console.log("deno:", deno.version.deno);
console.log("v8:", deno.version.v8);
console.log("typescript:", deno.version.typescript);
@ -36,22 +36,24 @@ export default function denoMain(
setPrepareStackTrace(Error);
if (s.mainModule) {
assert(s.mainModule.length > 0);
setLocation(s.mainModule);
const mainModule = startResMsg.mainModule();
if (mainModule) {
assert(mainModule.length > 0);
setLocation(mainModule);
}
log("cwd", s.cwd);
const cwd = startResMsg.cwd();
log("cwd", cwd);
for (let i = 1; i < s.argv.length; i++) {
args.push(s.argv[i]);
for (let i = 1; i < startResMsg.argvLength(); i++) {
args.push(startResMsg.argv(i));
}
log("args", args);
Object.freeze(args);
if (window["_xevalWrapper"] !== undefined) {
xevalMain(window["_xevalWrapper"] as XevalFunc, s.xevalDelim);
} else if (!s.mainModule) {
xevalMain(window["_xevalWrapper"] as XevalFunc, startResMsg.xevalDelim());
} else if (!mainModule) {
replLoop();
}
}

View file

@ -1,6 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
import { assert } from "./util";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
export interface Metrics {
opsDispatched: number;
@ -10,6 +10,27 @@ export interface Metrics {
bytesReceived: number;
}
function req(): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
const builder = flatbuffers.createBuilder();
const inner = msg.Metrics.createMetrics(builder);
return [builder, msg.Any.Metrics, inner];
}
function res(baseRes: null | msg.Base): Metrics {
assert(baseRes !== null);
assert(msg.Any.MetricsRes === baseRes!.innerType());
const res = new msg.MetricsRes();
assert(baseRes!.inner(res) !== null);
return {
opsDispatched: res.opsDispatched().toFloat64(),
opsCompleted: res.opsCompleted().toFloat64(),
bytesSentControl: res.bytesSentControl().toFloat64(),
bytesSentData: res.bytesSentData().toFloat64(),
bytesReceived: res.bytesReceived().toFloat64()
};
}
/** Receive metrics from the privileged side of Deno.
*
* > console.table(Deno.metrics())
@ -24,5 +45,5 @@ export interface Metrics {
*
*/
export function metrics(): Metrics {
return sendSync(dispatch.OP_METRICS);
return res(sendSync(...req()));
}

View file

@ -1,9 +1,8 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { EOF, Reader, Writer, Closer } from "./io";
import { notImplemented } from "./util";
import { assert, notImplemented } from "./util";
import { sendSync, sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { read, write, close } from "./files";
import * as dispatch from "./dispatch";
import { sendSync, sendAsync } from "./dispatch_json";
export type Network = "tcp";
// TODO support other types:
@ -37,7 +36,10 @@ enum ShutdownMode {
}
function shutdown(rid: number, how: ShutdownMode): void {
sendSync(dispatch.OP_SHUTDOWN, { rid, how });
const builder = flatbuffers.createBuilder();
const inner = msg.Shutdown.createShutdown(builder, rid, how);
const baseRes = sendSync(builder, msg.Any.Shutdown, inner);
assert(baseRes == null);
}
class ConnImpl implements Conn {
@ -78,9 +80,14 @@ class ListenerImpl implements Listener {
constructor(readonly rid: number) {}
async accept(): Promise<Conn> {
const res = await sendAsync(dispatch.OP_ACCEPT, { rid: this.rid });
// TODO(bartlomieju): add remoteAddr and localAddr on Rust side
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
const builder = flatbuffers.createBuilder();
const inner = msg.Accept.createAccept(builder, this.rid);
const baseRes = await sendAsync(builder, msg.Any.Accept, inner);
assert(baseRes != null);
assert(msg.Any.NewConn === baseRes!.innerType());
const res = new msg.NewConn();
assert(baseRes!.inner(res) != null);
return new ConnImpl(res.rid(), res.remoteAddr()!, res.localAddr()!);
}
close(): void {
@ -136,8 +143,16 @@ export interface Conn extends Reader, Writer, Closer {
* See `dial()` for a description of the network and address parameters.
*/
export function listen(network: Network, address: string): Listener {
const rid = sendSync(dispatch.OP_LISTEN, { network, address });
return new ListenerImpl(rid);
const builder = flatbuffers.createBuilder();
const network_ = builder.createString(network);
const address_ = builder.createString(address);
const inner = msg.Listen.createListen(builder, network_, address_);
const baseRes = sendSync(builder, msg.Any.Listen, inner);
assert(baseRes != null);
assert(msg.Any.ListenRes === baseRes!.innerType());
const res = new msg.ListenRes();
assert(baseRes!.inner(res) != null);
return new ListenerImpl(res.rid());
}
/** Dial connects to the address on the named network.
@ -168,9 +183,16 @@ export function listen(network: Network, address: string): Listener {
* dial("tcp", ":80")
*/
export async function dial(network: Network, address: string): Promise<Conn> {
const res = await sendAsync(dispatch.OP_DIAL, { network, address });
// TODO(bartlomieju): add remoteAddr and localAddr on Rust side
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
const builder = flatbuffers.createBuilder();
const network_ = builder.createString(network);
const address_ = builder.createString(address);
const inner = msg.Dial.createDial(builder, network_, address_);
const baseRes = await sendAsync(builder, msg.Any.Dial, inner);
assert(baseRes != null);
assert(msg.Any.NewConn === baseRes!.innerType());
const res = new msg.NewConn();
assert(baseRes!.inner(res) != null);
return new ConnImpl(res.rid(), res.remoteAddr()!, res.localAddr()!);
}
/** **RESERVED** */

View file

@ -1,7 +1,8 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { core } from "./core";
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
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,17 +24,21 @@ function setGlobals(pid_: number, noColor_: boolean): void {
* console.log(Deno.isTTY().stdout);
*/
export function isTTY(): { stdin: boolean; stdout: boolean; stderr: boolean } {
return sendSync(dispatch.OP_IS_TTY);
return dispatchJson.sendSync(dispatch.OP_IS_TTY);
}
/** Exit the Deno process with optional exit code. */
export function exit(code = 0): never {
sendSync(dispatch.OP_EXIT, { code });
dispatchJson.sendSync(dispatch.OP_EXIT, { code });
return util.unreachable();
}
function setEnv(key: string, value: string): void {
sendSync(dispatch.OP_SET_ENV, { key, value });
const builder = flatbuffers.createBuilder();
const key_ = builder.createString(key);
const value_ = builder.createString(value);
const inner = msg.SetEnv.createSetEnv(builder, key_, value_);
sendSync(builder, msg.Any.SetEnv, inner);
}
/** Returns a snapshot of the environment variables at invocation. Mutating a
@ -48,7 +53,7 @@ function setEnv(key: string, value: string): void {
* console.log(myEnv.TEST_VAR == newEnv.TEST_VAR);
*/
export function env(): { [index: string]: string } {
const env = sendSync(dispatch.OP_ENV);
const env = dispatchJson.sendSync(dispatch.OP_ENV);
return new Proxy(env, {
set(obj, prop: string, value: string): boolean {
setEnv(prop, value);
@ -57,35 +62,35 @@ export function env(): { [index: string]: string } {
});
}
interface Start {
cwd: string;
pid: number;
argv: string[];
mainModule: string; // Absolute URL.
debugFlag: boolean;
depsFlag: boolean;
typesFlag: boolean;
versionFlag: boolean;
denoVersion: string;
v8Version: string;
noColor: boolean;
xevalDelim: string;
/** Send to the privileged side that we have setup and are ready. */
function sendStart(): msg.StartRes {
const builder = flatbuffers.createBuilder();
const startOffset = msg.Start.createStart(builder, 0 /* unused */);
const baseRes = sendSync(builder, msg.Any.Start, startOffset);
assert(baseRes != null);
assert(msg.Any.StartRes === baseRes!.innerType());
const startResMsg = new msg.StartRes();
assert(baseRes!.inner(startResMsg) != null);
return startResMsg;
}
// This function bootstraps an environment within Deno, it is shared both by
// the runtime and the compiler environments.
// @internal
export function start(preserveDenoNamespace = true, source?: string): Start {
export function start(
preserveDenoNamespace = true,
source?: string
): msg.StartRes {
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
// args and other info.
const s = sendSync(dispatch.OP_START);
const startResMsg = sendStart();
util.setLogDebug(s.debugFlag, source);
util.setLogDebug(startResMsg.debugFlag(), source);
setGlobals(s.pid, s.noColor);
setGlobals(startResMsg.pid(), startResMsg.noColor());
if (preserveDenoNamespace) {
util.immutableDefine(window, "Deno", window.Deno);
@ -100,7 +105,7 @@ export function start(preserveDenoNamespace = true, source?: string): Start {
assert(window.Deno === undefined);
}
return s;
return startResMsg;
}
/**
@ -108,10 +113,18 @@ export function start(preserveDenoNamespace = true, source?: string): Start {
* Requires the `--allow-env` flag.
*/
export function homeDir(): string {
const path = sendSync(dispatch.OP_HOME_DIR);
const builder = flatbuffers.createBuilder();
const inner = msg.HomeDir.createHomeDir(builder);
const baseRes = sendSync(builder, msg.Any.HomeDir, inner)!;
assert(msg.Any.HomeDirRes === baseRes.innerType());
const res = new msg.HomeDirRes();
assert(baseRes.inner(res) != null);
const path = res.path();
if (!path) {
throw new Error("Could not get home directory.");
}
return path;
}
@ -120,5 +133,5 @@ export function homeDir(): string {
* Requires the `--allow-env` flag.
*/
export function execPath(): string {
return sendSync(dispatch.OP_EXEC_PATH);
return dispatchJson.sendSync(dispatch.OP_EXEC_PATH);
}

View file

@ -1,11 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
interface NowResponse {
seconds: number;
subsecNanos: number;
}
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { assert } from "./util";
export class Performance {
/** Returns a current time from Deno's start in milliseconds.
@ -16,7 +11,12 @@ export class Performance {
* console.log(`${t} ms since start!`);
*/
now(): number {
const res = sendSync(dispatch.OP_NOW) as NowResponse;
return res.seconds * 1e3 + res.subsecNanos / 1e6;
const builder = flatbuffers.createBuilder();
const inner = msg.Now.createNow(builder);
const baseRes = sendSync(builder, msg.Any.Now, inner)!;
assert(msg.Any.NowRes === baseRes.innerType());
const res = new msg.NowRes();
assert(baseRes.inner(res) != null);
return res.seconds().toFloat64() * 1e3 + res.subsecNanos() / 1e6;
}
}

View file

@ -1,6 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { assert } from "./util";
/** Permissions as granted by the caller */
export interface Permissions {
@ -15,6 +15,23 @@ export interface Permissions {
export type Permission = keyof Permissions;
function getReq(): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
const builder = flatbuffers.createBuilder();
const inner = msg.Permissions.createPermissions(builder);
return [builder, msg.Any.Permissions, inner];
}
function createPermissions(inner: msg.PermissionsRes): Permissions {
return {
read: inner.read(),
write: inner.write(),
net: inner.net(),
env: inner.env(),
run: inner.run(),
hrtime: inner.hrtime()
};
}
/** Inspect granted permissions for the current program.
*
* if (Deno.permissions().read) {
@ -23,7 +40,24 @@ export type Permission = keyof Permissions;
* }
*/
export function permissions(): Permissions {
return sendSync(dispatch.OP_PERMISSIONS) as Permissions;
const baseRes = sendSync(...getReq())!;
assert(msg.Any.PermissionsRes === baseRes.innerType());
const res = new msg.PermissionsRes();
assert(baseRes.inner(res) != null);
// TypeScript cannot track assertion above, therefore not null assertion
return createPermissions(res);
}
function revokeReq(
permission: string
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
const builder = flatbuffers.createBuilder();
const permission_ = builder.createString(permission);
const inner = msg.PermissionRevoke.createPermissionRevoke(
builder,
permission_
);
return [builder, msg.Any.PermissionRevoke, inner];
}
/** Revoke a permission. When the permission was already revoked nothing changes
@ -35,5 +69,5 @@ export function permissions(): Permissions {
* Deno.readFile("example.test"); // -> error or permission prompt
*/
export function revokePermission(permission: Permission): void {
sendSync(dispatch.OP_REVOKE_PERMISSION, { permission });
sendSync(...revokeReq(permission));
}

View file

@ -1,6 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { sendSync, sendAsync } from "./dispatch_json";
import * as dispatch from "./dispatch";
import { sendSync, sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { File, close } from "./files";
import { ReadCloser, WriteCloser } from "./io";
import { readAll } from "./buffer";
@ -31,22 +31,21 @@ export interface RunOptions {
stdin?: ProcessStdio | number;
}
interface RunStatusResponse {
gotSignal: boolean;
exitCode: number;
exitSignal: number;
}
async function runStatus(rid: number): Promise<ProcessStatus> {
const res = (await sendAsync(dispatch.OP_RUN_STATUS, {
rid
})) as RunStatusResponse;
const builder = flatbuffers.createBuilder();
const inner = msg.RunStatus.createRunStatus(builder, rid);
if (res.gotSignal) {
const signal = res.exitSignal;
const baseRes = await sendAsync(builder, msg.Any.RunStatus, inner);
assert(baseRes != null);
assert(msg.Any.RunStatusRes === baseRes!.innerType());
const res = new msg.RunStatusRes();
assert(baseRes!.inner(res) != null);
if (res.gotSignal()) {
const signal = res.exitSignal();
return { signal, success: false };
} else {
const code = res.exitCode;
const code = res.exitCode();
return { code, success: code === 0 };
}
}
@ -57,7 +56,9 @@ async function runStatus(rid: number): Promise<ProcessStatus> {
* Requires the `--allow-run` flag.
*/
export function kill(pid: number, signo: number): void {
sendSync(dispatch.OP_KILL, { pid, signo });
const builder = flatbuffers.createBuilder();
const inner = msg.Kill.createKill(builder, pid, signo);
sendSync(builder, msg.Any.Kill, inner);
}
export class Process {
@ -68,20 +69,20 @@ export class Process {
readonly stderr?: ReadCloser;
// @internal
constructor(res: RunResponse) {
this.rid = res.rid;
this.pid = res.pid;
constructor(res: msg.RunRes) {
this.rid = res.rid();
this.pid = res.pid();
if (res.stdinRid && res.stdinRid > 0) {
this.stdin = new File(res.stdinRid);
if (res.stdinRid() > 0) {
this.stdin = new File(res.stdinRid());
}
if (res.stdoutRid && res.stdoutRid > 0) {
this.stdout = new File(res.stdoutRid);
if (res.stdoutRid() > 0) {
this.stdout = new File(res.stdoutRid());
}
if (res.stderrRid && res.stderrRid > 0) {
this.stderr = new File(res.stderrRid);
if (res.stderrRid() > 0) {
this.stderr = new File(res.stderrRid());
}
}
@ -134,13 +135,14 @@ export interface ProcessStatus {
signal?: number; // TODO: Make this a string, e.g. 'SIGTERM'.
}
// TODO: this method is only used to validate proper option, probably can be renamed
function stdioMap(s: string): string {
function stdioMap(s: ProcessStdio): msg.ProcessStdio {
switch (s) {
case "inherit":
return msg.ProcessStdio.Inherit;
case "piped":
return msg.ProcessStdio.Piped;
case "null":
return s;
return msg.ProcessStdio.Null;
default:
return unreachable();
}
@ -150,13 +152,6 @@ function isRid(arg: unknown): arg is number {
return !isNaN(arg as number);
}
interface RunResponse {
rid: number;
pid: number;
stdinRid: number | null;
stdoutRid: number | null;
stderrRid: number | null;
}
/**
* Spawns new subprocess.
*
@ -171,56 +166,71 @@ interface RunResponse {
* they can be set to either `ProcessStdio` or `rid` of open file.
*/
export function run(opt: RunOptions): Process {
assert(opt.args.length > 0);
let env: Array<[string, string]> = [];
const builder = flatbuffers.createBuilder();
const argsOffset = msg.Run.createArgsVector(
builder,
opt.args.map((a): number => builder.createString(a))
);
const cwdOffset = opt.cwd == null ? 0 : builder.createString(opt.cwd);
const kvOffset: flatbuffers.Offset[] = [];
if (opt.env) {
env = Array.from(Object.entries(opt.env));
for (const [key, val] of Object.entries(opt.env)) {
const keyOffset = builder.createString(key);
const valOffset = builder.createString(String(val));
kvOffset.push(msg.KeyValue.createKeyValue(builder, keyOffset, valOffset));
}
}
const envOffset = msg.Run.createEnvVector(builder, kvOffset);
let stdin = stdioMap("inherit");
let stdout = stdioMap("inherit");
let stderr = stdioMap("inherit");
let stdinRid = 0;
let stdoutRid = 0;
let stderrRid = 0;
let stdInOffset = stdioMap("inherit");
let stdOutOffset = stdioMap("inherit");
let stdErrOffset = stdioMap("inherit");
let stdinRidOffset = 0;
let stdoutRidOffset = 0;
let stderrRidOffset = 0;
if (opt.stdin) {
if (isRid(opt.stdin)) {
stdinRid = opt.stdin;
stdinRidOffset = opt.stdin;
} else {
stdin = stdioMap(opt.stdin);
stdInOffset = stdioMap(opt.stdin);
}
}
if (opt.stdout) {
if (isRid(opt.stdout)) {
stdoutRid = opt.stdout;
stdoutRidOffset = opt.stdout;
} else {
stdout = stdioMap(opt.stdout);
stdOutOffset = stdioMap(opt.stdout);
}
}
if (opt.stderr) {
if (isRid(opt.stderr)) {
stderrRid = opt.stderr;
stderrRidOffset = opt.stderr;
} else {
stderr = stdioMap(opt.stderr);
stdErrOffset = stdioMap(opt.stderr);
}
}
const req = {
args: opt.args.map(String),
cwd: opt.cwd,
env,
stdin,
stdout,
stderr,
stdinRid,
stdoutRid,
stderrRid
};
const inner = msg.Run.createRun(
builder,
argsOffset,
cwdOffset,
envOffset,
stdInOffset,
stdOutOffset,
stdErrOffset,
stdinRidOffset,
stdoutRidOffset,
stderrRidOffset
);
const baseRes = sendSync(builder, msg.Any.Run, inner);
assert(baseRes != null);
assert(msg.Any.RunRes === baseRes!.innerType());
const res = new msg.RunRes();
assert(baseRes!.inner(res) != null);
const res = sendSync(dispatch.OP_RUN, req) as RunResponse;
return new Process(res);
}

View file

@ -1,12 +1,12 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { assert } from "./util";
import { close } from "./files";
import { sendSync, sendAsync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { exit } from "./os";
import { window } from "./window";
import { core } from "./core";
import { formatError } from "./format_error";
import { stringifyArgs } from "./console";
import * as dispatch from "./dispatch";
import { sendSync, sendAsync } from "./dispatch_json";
/**
* REPL logging.
@ -43,12 +43,34 @@ const replCommands = {
};
function startRepl(historyFile: string): number {
return sendSync(dispatch.OP_REPL_START, { historyFile });
const builder = flatbuffers.createBuilder();
const historyFile_ = builder.createString(historyFile);
const inner = msg.ReplStart.createReplStart(builder, historyFile_);
const baseRes = sendSync(builder, msg.Any.ReplStart, inner);
assert(baseRes != null);
assert(msg.Any.ReplStartRes === baseRes!.innerType());
const innerRes = new msg.ReplStartRes();
assert(baseRes!.inner(innerRes) != null);
const rid = innerRes.rid();
return rid;
}
// @internal
export async function readline(rid: number, prompt: string): Promise<string> {
return sendAsync(dispatch.OP_REPL_READLINE, { rid, prompt });
const builder = flatbuffers.createBuilder();
const prompt_ = builder.createString(prompt);
const inner = msg.ReplReadline.createReplReadline(builder, rid, prompt_);
const baseRes = await sendAsync(builder, msg.Any.ReplReadline, inner);
assert(baseRes != null);
assert(msg.Any.ReplReadlineRes === baseRes!.innerType());
const innerRes = new msg.ReplReadlineRes();
assert(baseRes!.inner(innerRes) != null);
const line = innerRes.line();
assert(line !== null);
return line || "";
}
// Error messages that allow users to continue input

View file

@ -1,6 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as dispatch from "./dispatch";
import { sendSync } from "./dispatch_json";
import { assert } from "./util";
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
export interface ResourceMap {
[rid: number]: string;
@ -10,10 +10,20 @@ export interface ResourceMap {
* representation.
*/
export function resources(): ResourceMap {
const res = sendSync(dispatch.OP_RESOURCES) as Array<[number, string]>;
const builder = flatbuffers.createBuilder();
const inner = msg.Resource.createResource(builder, 0, 0);
const baseRes = sendSync(builder, msg.Any.Resources, inner);
assert(baseRes !== null);
assert(msg.Any.ResourcesRes === baseRes!.innerType());
const res = new msg.ResourcesRes();
assert(baseRes!.inner(res) !== null);
const resources: ResourceMap = {};
for (const resourceTuple of res) {
resources[resourceTuple[0]] = resourceTuple[1];
for (let i = 0; i < res.resourcesLength(); i++) {
const item = res.resources(i)!;
resources[item.rid()!] = item.repr()!;
}
return resources;
}

View file

@ -1,8 +1,7 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { assert } from "./util";
import { sendAsync, sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { window } from "./window";
import * as dispatch from "./dispatch";
import { sendSync, sendAsync } from "./dispatch_json";
interface Timer {
id: number;
@ -38,8 +37,11 @@ function getTime(): number {
}
function clearGlobalTimeout(): void {
const builder = flatbuffers.createBuilder();
const inner = msg.GlobalTimerStop.createGlobalTimerStop(builder);
globalTimeoutDue = null;
sendSync(dispatch.OP_GLOBAL_TIMER_STOP);
let res = sendSync(builder, msg.Any.GlobalTimerStop, inner);
assert(res == null);
}
async function setGlobalTimeout(due: number, now: number): Promise<void> {
@ -50,8 +52,12 @@ async function setGlobalTimeout(due: number, now: number): Promise<void> {
assert(timeout >= 0);
// Send message to the backend.
const builder = flatbuffers.createBuilder();
msg.GlobalTimer.startGlobalTimer(builder);
msg.GlobalTimer.addTimeout(builder, timeout);
const inner = msg.GlobalTimer.endGlobalTimer(builder);
globalTimeoutDue = due;
await sendAsync(dispatch.OP_GLOBAL_TIMER, { timeout });
await sendAsync(builder, msg.Any.GlobalTimer, inner);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
fireTimers();
}

View file

@ -1,8 +1,7 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as dispatch from "./dispatch";
import { sendAsync, sendSync } from "./dispatch_json";
import { log } from "./util";
import { sendAsync, sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
import { assert, log } from "./util";
import { TextDecoder, TextEncoder } from "./text_encoding";
import { window } from "./window";
import { blobURLMap } from "./url";
@ -27,28 +26,61 @@ function createWorker(
hasSourceCode: boolean,
sourceCode: Uint8Array
): number {
return sendSync(dispatch.OP_CREATE_WORKER, {
specifier,
const builder = flatbuffers.createBuilder();
const specifier_ = builder.createString(specifier);
const sourceCode_ = builder.createString(sourceCode);
const inner = msg.CreateWorker.createCreateWorker(
builder,
specifier_,
includeDenoNamespace,
hasSourceCode,
sourceCode: new TextDecoder().decode(sourceCode)
});
sourceCode_
);
const baseRes = sendSync(builder, msg.Any.CreateWorker, inner);
assert(baseRes != null);
assert(
msg.Any.CreateWorkerRes === baseRes!.innerType(),
`base.innerType() unexpectedly is ${baseRes!.innerType()}`
);
const res = new msg.CreateWorkerRes();
assert(baseRes!.inner(res) != null);
return res.rid();
}
async function hostGetWorkerClosed(rid: number): Promise<void> {
await sendAsync(dispatch.OP_HOST_GET_WORKER_CLOSED, { rid });
const builder = flatbuffers.createBuilder();
const inner = msg.HostGetWorkerClosed.createHostGetWorkerClosed(builder, rid);
await sendAsync(builder, msg.Any.HostGetWorkerClosed, inner);
}
function hostPostMessage(rid: number, data: any): void {
const dataIntArray = encodeMessage(data);
sendSync(dispatch.OP_HOST_POST_MESSAGE, { rid }, dataIntArray);
const builder = flatbuffers.createBuilder();
const inner = msg.HostPostMessage.createHostPostMessage(builder, rid);
const baseRes = sendSync(
builder,
msg.Any.HostPostMessage,
inner,
dataIntArray
);
assert(baseRes != null);
}
async function hostGetMessage(rid: number): Promise<any> {
const res = await sendAsync(dispatch.OP_HOST_GET_MESSAGE, { rid });
const builder = flatbuffers.createBuilder();
const inner = msg.HostGetMessage.createHostGetMessage(builder, rid);
const baseRes = await sendAsync(builder, msg.Any.HostGetMessage, inner);
assert(baseRes != null);
assert(
msg.Any.HostGetMessageRes === baseRes!.innerType(),
`base.innerType() unexpectedly is ${baseRes!.innerType()}`
);
const res = new msg.HostGetMessageRes();
assert(baseRes!.inner(res) != null);
if (res.data != null) {
return decodeMessage(new Uint8Array(res.data));
const dataArray = res.dataArray();
if (dataArray != null) {
return decodeMessage(dataArray);
} else {
return null;
}
@ -59,15 +91,36 @@ export let onmessage: (e: { data: any }) => void = (): void => {};
export function postMessage(data: any): void {
const dataIntArray = encodeMessage(data);
sendSync(dispatch.OP_WORKER_POST_MESSAGE, {}, dataIntArray);
const builder = flatbuffers.createBuilder();
const inner = msg.WorkerPostMessage.createWorkerPostMessage(builder);
const baseRes = sendSync(
builder,
msg.Any.WorkerPostMessage,
inner,
dataIntArray
);
assert(baseRes != null);
}
export async function getMessage(): Promise<any> {
log("getMessage");
const res = await sendAsync(dispatch.OP_WORKER_GET_MESSAGE);
const builder = flatbuffers.createBuilder();
const inner = msg.WorkerGetMessage.createWorkerGetMessage(
builder,
0 /* unused */
);
const baseRes = await sendAsync(builder, msg.Any.WorkerGetMessage, inner);
assert(baseRes != null);
assert(
msg.Any.WorkerGetMessageRes === baseRes!.innerType(),
`base.innerType() unexpectedly is ${baseRes!.innerType()}`
);
const res = new msg.WorkerGetMessageRes();
assert(baseRes!.inner(res) != null);
if (res.data != null) {
return decodeMessage(new Uint8Array(res.data));
const dataArray = res.dataArray();
if (dataArray != null) {
return decodeMessage(dataArray);
} else {
return null;
}