mirror of
https://github.com/denoland/deno
synced 2024-08-27 20:09:17 +00:00
Add resources op (#1119)
This commit is contained in:
parent
8b39d2c99e
commit
946acbc559
1
BUILD.gn
1
BUILD.gn
|
@ -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",
|
||||
|
|
|
@ -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
25
js/resources.ts
Normal 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
43
js/resources_test.ts
Normal 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");
|
||||
});
|
|
@ -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";
|
||||
|
|
13
src/msg.fbs
13
src/msg.fbs
|
@ -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;
|
||||
|
|
48
src/ops.rs
48
src/ops.rs
|
@ -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()
|
||||
},
|
||||
))
|
||||
}
|
||||
|
|
|
@ -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
1
tests/hello.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Hello world!
|
Loading…
Reference in a new issue