Add resources op (#1119)

This commit is contained in:
Bartek Iwańczuk 2018-10-30 20:58:55 +01:00 committed by Ryan Dahl
parent 8b39d2c99e
commit 946acbc559
9 changed files with 167 additions and 0 deletions

View file

@ -102,6 +102,7 @@ ts_sources = [
"js/read_link.ts",
"js/remove.ts",
"js/rename.ts",
"js/resources.ts",
"js/stat.ts",
"js/symlink.ts",
"js/text_encoding.ts",

View file

@ -38,6 +38,7 @@ export { truncateSync, truncate } from "./truncate";
export { FileInfo } from "./file_info";
export { connect, dial, listen, Listener, Conn } from "./net";
export { metrics } from "./metrics";
export { resources } from "./resources";
export const args: string[] = [];
// Provide the compiler API in an obfuscated way

25
js/resources.ts Normal file
View file

@ -0,0 +1,25 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import * as msg from "gen/msg_generated";
import * as flatbuffers from "./flatbuffers";
import { assert } from "./util";
import * as dispatch from "./dispatch";
export function resources(): { [key: number]: string } {
const builder = flatbuffers.createBuilder();
msg.Resources.startResources(builder);
const inner = msg.Resource.endResource(builder);
const baseRes = dispatch.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: { [key: number]: string } = {};
for (let i = 0; i < res.resourcesLength(); i++) {
const item = res.resources(i)!;
resources[item.rid()!] = item.repr()!;
}
return resources;
}

43
js/resources_test.ts Normal file
View file

@ -0,0 +1,43 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import { test, testPerm, assert, assertEqual } from "./test_util.ts";
import * as deno from "deno";
test(function resourcesStdio() {
const res = deno.resources();
assertEqual(res[0], "stdin");
assertEqual(res[1], "stdout");
assertEqual(res[2], "stderr");
});
testPerm({ net: true }, async function resourcesNet() {
const addr = "127.0.0.1:4501";
const listener = deno.listen("tcp", addr);
const dialerConn = await deno.dial("tcp", addr);
const listenerConn = await listener.accept();
const res = deno.resources();
assertEqual(Object.values(res).filter(r => r === "tcpListener").length, 1);
assertEqual(Object.values(res).filter(r => r === "tcpStream").length, 2);
listenerConn.close();
dialerConn.close();
listener.close();
});
test(async function resourcesFile() {
const resourcesBefore = deno.resources();
await deno.open("tests/hello.txt");
const resourcesAfter = deno.resources();
// check that exactly one new resource (file) was added
assertEqual(
Object.keys(resourcesAfter).length,
Object.keys(resourcesBefore).length + 1
);
const newRid = Object.keys(resourcesAfter).find(rid => {
return !resourcesBefore.hasOwnProperty(rid);
});
assertEqual(resourcesAfter[newRid], "fsFile");
});

View file

@ -22,6 +22,7 @@ import "./read_dir_test.ts";
import "./read_file_test.ts";
import "./read_link_test.ts";
import "./rename_test.ts";
import "./resources_test.ts";
import "./stat_test.ts";
import "./symlink_test.ts";
import "./text_encoding_test.ts";

View file

@ -24,6 +24,8 @@ union Any {
Rename,
Readlink,
ReadlinkRes,
Resources,
ResourcesRes,
Symlink,
Stat,
StatRes,
@ -270,6 +272,17 @@ table ReadlinkRes {
path: string;
}
table Resources {}
table Resource {
rid: int;
repr: string;
}
table ResourcesRes {
resources: [Resource];
}
table Symlink {
oldname: string;
newname: string;

View file

@ -19,6 +19,7 @@ use futures::Poll;
use hyper;
use hyper::rt::{Future, Stream};
use remove_dir_all::remove_dir_all;
use resources::table_entries;
use std;
use std::fs;
use std::net::{Shutdown, SocketAddr};
@ -94,6 +95,7 @@ pub fn dispatch(
msg::Any::Read => op_read,
msg::Any::Remove => op_remove,
msg::Any::Rename => op_rename,
msg::Any::Resources => op_resources,
msg::Any::SetEnv => op_set_env,
msg::Any::Shutdown => op_shutdown,
msg::Any::Start => op_start,
@ -1288,3 +1290,49 @@ fn op_metrics(
},
))
}
fn op_resources(
_state: Arc<IsolateState>,
base: &msg::Base,
data: &'static mut [u8],
) -> Box<Op> {
assert_eq!(data.len(), 0);
let cmd_id = base.cmd_id();
let builder = &mut FlatBufferBuilder::new();
let serialized_resources = table_entries();
let res: Vec<_> = serialized_resources
.iter()
.map(|(key, value)| {
let repr = builder.create_string(value);
msg::Resource::create(
builder,
&msg::ResourceArgs {
rid: key.clone(),
repr: Some(repr),
..Default::default()
},
)
}).collect();
let resources = builder.create_vector(&res);
let inner = msg::ResourcesRes::create(
builder,
&msg::ResourcesResArgs {
resources: Some(resources),
..Default::default()
},
);
ok_future(serialize_response(
cmd_id,
builder,
msg::BaseArgs {
inner: Some(inner.as_union_value()),
inner_type: msg::Any::ResourcesRes,
..Default::default()
},
))
}

View file

@ -58,6 +58,40 @@ enum Repr {
TcpStream(tokio::net::TcpStream),
}
pub fn table_entries() -> Vec<(i32, String)> {
let table = RESOURCE_TABLE.lock().unwrap();
let tuples = table
.iter()
.map(|(key, value)| (key.clone(), inspect_repr(&value)))
.collect();
tuples
}
#[test]
fn test_table_entries() {
let mut entries = table_entries();
entries.sort();
assert_eq!(entries.len(), 3);
assert_eq!(entries[0], (0, String::from("stdin")));
assert_eq!(entries[1], (1, String::from("stdout")));
assert_eq!(entries[2], (2, String::from("stderr")));
}
fn inspect_repr(repr: &Repr) -> String {
let h_repr = match repr {
Repr::Stdin(_) => "stdin",
Repr::Stdout(_) => "stdout",
Repr::Stderr(_) => "stderr",
Repr::FsFile(_) => "fsFile",
Repr::TcpListener(_) => "tcpListener",
Repr::TcpStream(_) => "tcpStream",
};
String::from(h_repr)
}
// Abstract async file interface.
// Ideally in unix, if Resource represents an OS rid, it will be the same.
#[derive(Debug)]

1
tests/hello.txt Normal file
View file

@ -0,0 +1 @@
Hello world!