1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

Use gotham-like state for ops (#7385)

Provides a concrete state type that can be dynamically added. This is necessary for op crates.
* renames BasicState to OpState
* async ops take `Rc<RefCell<OpState>>`
* sync ops take `&mut OpState`
* removes `OpRegistry`, `OpRouter` traits
* `get_error_class_fn` moved to OpState
* ResourceTable moved to OpState
This commit is contained in:
Ryan Dahl 2020-09-10 09:57:45 -04:00 committed by GitHub
parent 6f70e6e72b
commit 7c2e7c6608
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 1576 additions and 1348 deletions

View file

@ -3,9 +3,7 @@
mod op_fetch_asset; mod op_fetch_asset;
use deno_core::js_check; use deno_core::js_check;
use deno_core::BasicState;
use deno_core::JsRuntime; use deno_core::JsRuntime;
use deno_core::OpRegistry;
use deno_core::StartupData; use deno_core::StartupData;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
@ -39,8 +37,7 @@ fn create_snapshot(
} }
fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<PathBuf>) { fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<PathBuf>) {
let state = BasicState::new(); let isolate = JsRuntime::new(StartupData::None, true);
let isolate = JsRuntime::new(state, StartupData::None, true);
create_snapshot(isolate, snapshot_path, files); create_snapshot(isolate, snapshot_path, files);
} }
@ -73,13 +70,11 @@ fn create_compiler_snapshot(
cwd.join("dts/lib.deno.unstable.d.ts"), cwd.join("dts/lib.deno.unstable.d.ts"),
); );
let state = BasicState::new(); let mut isolate = JsRuntime::new(StartupData::None, true);
state.register_op( isolate.register_op(
"op_fetch_asset", "op_fetch_asset",
op_fetch_asset::op_fetch_asset(custom_libs), op_fetch_asset::op_fetch_asset(custom_libs),
); );
let isolate = JsRuntime::new(state, StartupData::None, true);
create_snapshot(isolate, snapshot_path, files); create_snapshot(isolate, snapshot_path, files);
} }

View file

@ -14,7 +14,6 @@ pub static UNSTABLE_NS_LIB: &str = include_str!("dts/lib.deno.unstable.d.ts");
#[test] #[test]
fn cli_snapshot() { fn cli_snapshot() {
let mut isolate = deno_core::JsRuntime::new( let mut isolate = deno_core::JsRuntime::new(
deno_core::BasicState::new(),
deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(CLI_SNAPSHOT)), deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(CLI_SNAPSHOT)),
false, false,
); );
@ -32,7 +31,6 @@ fn cli_snapshot() {
#[test] #[test]
fn compiler_snapshot() { fn compiler_snapshot() {
let mut isolate = deno_core::JsRuntime::new( let mut isolate = deno_core::JsRuntime::new(
deno_core::BasicState::new(),
deno_core::StartupData::Snapshot(deno_core::Snapshot::Static( deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(
COMPILER_SNAPSHOT, COMPILER_SNAPSHOT,
)), )),

View file

@ -71,3 +71,60 @@ impl Metrics {
self.op_completed(bytes_received); self.op_completed(bytes_received);
} }
} }
use deno_core::BufVec;
use deno_core::Op;
use deno_core::OpFn;
use deno_core::OpState;
use std::cell::RefCell;
use std::rc::Rc;
pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
Box::new(move |op_state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
// TODOs:
// * The 'bytes' metrics seem pretty useless, especially now that the
// distinction between 'control' and 'data' buffers has become blurry.
// * Tracking completion of async ops currently makes us put the boxed
// future into _another_ box. Keeping some counters may not be expensive
// in itself, but adding a heap allocation for every metric seems bad.
let mut buf_len_iter = bufs.iter().map(|buf| buf.len());
let bytes_sent_control = buf_len_iter.next().unwrap_or(0);
let bytes_sent_data = buf_len_iter.sum();
let op = (op_fn)(op_state.clone(), bufs);
let cli_state = crate::ops::cli_state2(&op_state);
let cli_state_ = cli_state.clone();
let mut metrics = cli_state.metrics.borrow_mut();
use futures::future::FutureExt;
match op {
Op::Sync(buf) => {
metrics.op_sync(bytes_sent_control, bytes_sent_data, buf.len());
Op::Sync(buf)
}
Op::Async(fut) => {
metrics.op_dispatched_async(bytes_sent_control, bytes_sent_data);
let fut = fut
.inspect(move |buf| {
let mut metrics = cli_state_.metrics.borrow_mut();
metrics.op_completed_async(buf.len());
})
.boxed_local();
Op::Async(fut)
}
Op::AsyncUnref(fut) => {
metrics.op_dispatched_async_unref(bytes_sent_control, bytes_sent_data);
let fut = fut
.inspect(move |buf| {
let mut metrics = cli_state_.metrics.borrow_mut();
metrics.op_completed_async_unref(buf.len());
})
.boxed_local();
Op::AsyncUnref(fut)
}
other => other,
}
})
}

View file

@ -1,27 +1,31 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::OpRegistry;
use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
pub fn init(s: &Rc<State>, response: Arc<Mutex<Option<String>>>) { pub fn init(
rt: &mut deno_core::JsRuntime,
response: Arc<Mutex<Option<String>>>,
) {
let custom_assets = std::collections::HashMap::new(); let custom_assets = std::collections::HashMap::new();
// TODO(ry) use None. // TODO(ry) use None.
// TODO(bartlomieju): is this op even required? // TODO(bartlomieju): is this op even required?
s.register_op( rt.register_op(
"op_fetch_asset", "op_fetch_asset",
crate::op_fetch_asset::op_fetch_asset(custom_assets), crate::op_fetch_asset::op_fetch_asset(custom_assets),
); );
s.register_op_json_sync("op_compiler_respond", move |_state, args, _bufs| { super::reg_json_sync(
let mut response_slot = response.lock().unwrap(); rt,
let replaced_value = response_slot.replace(args.to_string()); "op_compiler_respond",
assert!( move |_state, args, _bufs| {
replaced_value.is_none(), let mut response_slot = response.lock().unwrap();
"op_compiler_respond found unexpected existing compiler output", let replaced_value = response_slot.replace(args.to_string());
); assert!(
Ok(json!({})) replaced_value.is_none(),
}); "op_compiler_respond found unexpected existing compiler output",
);
Ok(json!({}))
},
);
} }

View file

@ -1,12 +1,12 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::Op; use deno_core::Op;
use deno_core::OpId; use deno_core::OpFn;
use deno_core::OpRegistry; use deno_core::OpState;
use futures::future::FutureExt; use futures::future::FutureExt;
use std::cell::RefCell;
use std::future::Future; use std::future::Future;
use std::iter::repeat; use std::iter::repeat;
use std::mem::size_of_val; use std::mem::size_of_val;
@ -132,78 +132,74 @@ fn test_parse_min_record() {
assert_eq!(parse_min_record(&buf), None); assert_eq!(parse_min_record(&buf), None);
} }
impl State { pub fn minimal_op<F>(op_fn: F) -> Box<OpFn>
pub fn register_op_minimal<F>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId where
where F: Fn(Rc<RefCell<OpState>>, bool, i32, BufVec) -> MinimalOp + 'static,
F: Fn(Rc<Self>, bool, i32, BufVec) -> MinimalOp + 'static, {
{ Box::new(move |state: Rc<RefCell<OpState>>, bufs: BufVec| {
let base_op_fn = move |state: Rc<Self>, bufs: BufVec| { let mut bufs_iter = bufs.into_iter();
let mut bufs_iter = bufs.into_iter(); let record_buf = bufs_iter.next().expect("Expected record at position 0");
let record_buf = bufs_iter.next().expect("Expected record at position 0"); let zero_copy = bufs_iter.collect::<BufVec>();
let zero_copy = bufs_iter.collect::<BufVec>();
let mut record = match parse_min_record(&record_buf) { let mut record = match parse_min_record(&record_buf) {
Some(r) => r, Some(r) => r,
None => { None => {
let error = ErrBox::type_error("Unparsable control buffer"); let error = ErrBox::type_error("Unparsable control buffer");
let error_class = state.get_error_class_name(&error); let error_class = (state.borrow().get_error_class_fn)(&error);
let error_record = ErrorRecord {
promise_id: 0,
arg: -1,
error_len: error_class.len() as i32,
error_class: error_class.as_bytes(),
error_message: error.to_string().as_bytes().to_owned(),
};
return Op::Sync(error_record.into());
}
};
let is_sync = record.promise_id == 0;
let rid = record.arg;
let min_op = op_fn(state.clone(), is_sync, rid, zero_copy);
match min_op {
MinimalOp::Sync(sync_result) => Op::Sync(match sync_result {
Ok(r) => {
record.result = r;
record.into()
}
Err(err) => {
let error_class = (state.borrow().get_error_class_fn)(&err);
let error_record = ErrorRecord { let error_record = ErrorRecord {
promise_id: 0, promise_id: record.promise_id,
arg: -1, arg: -1,
error_len: error_class.len() as i32, error_len: error_class.len() as i32,
error_class: error_class.as_bytes(), error_class: error_class.as_bytes(),
error_message: error.to_string().as_bytes().to_owned(), error_message: err.to_string().as_bytes().to_owned(),
}; };
return Op::Sync(error_record.into()); error_record.into()
} }
}; }),
let is_sync = record.promise_id == 0; MinimalOp::Async(min_fut) => {
let rid = record.arg; let fut = async move {
let min_op = op_fn(state.clone(), is_sync, rid, zero_copy); match min_fut.await {
Ok(r) => {
match min_op { record.result = r;
MinimalOp::Sync(sync_result) => Op::Sync(match sync_result { record.into()
Ok(r) => {
record.result = r;
record.into()
}
Err(err) => {
let error_class = state.get_error_class_name(&err);
let error_record = ErrorRecord {
promise_id: record.promise_id,
arg: -1,
error_len: error_class.len() as i32,
error_class: error_class.as_bytes(),
error_message: err.to_string().as_bytes().to_owned(),
};
error_record.into()
}
}),
MinimalOp::Async(min_fut) => {
let fut = async move {
match min_fut.await {
Ok(r) => {
record.result = r;
record.into()
}
Err(err) => {
let error_class = state.get_error_class_name(&err);
let error_record = ErrorRecord {
promise_id: record.promise_id,
arg: -1,
error_len: error_class.len() as i32,
error_class: error_class.as_bytes(),
error_message: err.to_string().as_bytes().to_owned(),
};
error_record.into()
}
} }
}; Err(err) => {
Op::Async(fut.boxed_local()) let error_class = (state.borrow().get_error_class_fn)(&err);
} let error_record = ErrorRecord {
promise_id: record.promise_id,
arg: -1,
error_len: error_class.len() as i32,
error_class: error_class.as_bytes(),
error_message: err.to_string().as_bytes().to_owned(),
};
error_record.into()
}
}
};
Op::Async(fut.boxed_local())
} }
}; }
})
self.register_op(name, base_op_fn)
}
} }

View file

@ -3,18 +3,16 @@
use crate::diagnostics::Diagnostic; use crate::diagnostics::Diagnostic;
use crate::source_maps::get_orig_position; use crate::source_maps::get_orig_position;
use crate::source_maps::CachedMaps; use crate::source_maps::CachedMaps;
use crate::state::State;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_apply_source_map", op_apply_source_map); super::reg_json_sync(rt, "op_apply_source_map", op_apply_source_map);
s.register_op_json_sync("op_format_diagnostic", op_format_diagnostic); super::reg_json_sync(rt, "op_format_diagnostic", op_format_diagnostic);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -26,7 +24,7 @@ struct ApplySourceMap {
} }
fn op_apply_source_map( fn op_apply_source_map(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -39,7 +37,7 @@ fn op_apply_source_map(
args.line_number.into(), args.line_number.into(),
args.column_number.into(), args.column_number.into(),
&mut mappings_map, &mut mappings_map,
&state.global_state.ts_compiler, &super::cli_state(state).global_state.ts_compiler,
); );
Ok(json!({ Ok(json!({
@ -50,7 +48,7 @@ fn op_apply_source_map(
} }
fn op_format_diagnostic( fn op_format_diagnostic(
_state: &State, _state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {

View file

@ -2,10 +2,9 @@
use super::io::{StreamResource, StreamResourceHolder}; use super::io::{StreamResource, StreamResourceHolder};
use crate::http_util::{create_http_client, HttpBody}; use crate::http_util::{create_http_client, HttpBody};
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use http::header::HeaderName; use http::header::HeaderName;
use http::header::HeaderValue; use http::header::HeaderValue;
@ -13,13 +12,14 @@ use http::Method;
use reqwest::Client; use reqwest::Client;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::convert::From; use std::convert::From;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_async("op_fetch", op_fetch); super::reg_json_async(rt, "op_fetch", op_fetch);
s.register_op_json_sync("op_create_http_client", op_create_http_client); super::reg_json_sync(rt, "op_create_http_client", op_create_http_client);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -32,7 +32,7 @@ struct FetchArgs {
} }
async fn op_fetch( async fn op_fetch(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
data: BufVec, data: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -40,13 +40,15 @@ async fn op_fetch(
let url = args.url; let url = args.url;
let client = if let Some(rid) = args.client_rid { let client = if let Some(rid) = args.client_rid {
let resource_table_ = state.resource_table.borrow(); let state = state.borrow();
let r = resource_table_ let r = state
.resource_table
.get::<HttpClientResource>(rid) .get::<HttpClientResource>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
r.client.clone() r.client.clone()
} else { } else {
let client_ref = state.http_client.borrow_mut(); let cli_state = super::cli_state2(&state);
let client_ref = cli_state.http_client.borrow();
client_ref.clone() client_ref.clone()
}; };
@ -66,7 +68,7 @@ async fn op_fetch(
))); )));
} }
state.check_net_url(&url_)?; super::cli_state2(&state).check_net_url(&url_)?;
let mut request = client.request(method, url_); let mut request = client.request(method, url_);
@ -93,7 +95,7 @@ async fn op_fetch(
} }
let body = HttpBody::from(res); let body = HttpBody::from(res);
let rid = state.resource_table.borrow_mut().add( let rid = state.borrow_mut().resource_table.add(
"httpBody", "httpBody",
Box::new(StreamResourceHolder::new(StreamResource::HttpBody( Box::new(StreamResourceHolder::new(StreamResource::HttpBody(
Box::new(body), Box::new(body),
@ -128,21 +130,20 @@ struct CreateHttpClientOptions {
} }
fn op_create_http_client( fn op_create_http_client(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: CreateHttpClientOptions = serde_json::from_value(args)?; let args: CreateHttpClientOptions = serde_json::from_value(args)?;
if let Some(ca_file) = args.ca_file.clone() { if let Some(ca_file) = args.ca_file.clone() {
state.check_read(&PathBuf::from(ca_file))?; super::cli_state(state).check_read(&PathBuf::from(ca_file))?;
} }
let client = create_http_client(args.ca_file.as_deref()).unwrap(); let client = create_http_client(args.ca_file.as_deref()).unwrap();
let rid = state let rid = state
.resource_table .resource_table
.borrow_mut()
.add("httpClient", Box::new(HttpClientResource::new(client))); .add("httpClient", Box::new(HttpClientResource::new(client)));
Ok(json!(rid)) Ok(json!(rid))
} }

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,8 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use futures::future::poll_fn; use futures::future::poll_fn;
use notify::event::Event as NotifyEvent; use notify::event::Event as NotifyEvent;
@ -15,14 +14,15 @@ use notify::Watcher;
use serde::Serialize; use serde::Serialize;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::convert::From; use std::convert::From;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use tokio::sync::mpsc; use tokio::sync::mpsc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_fs_events_open", op_fs_events_open); super::reg_json_sync(rt, "op_fs_events_open", op_fs_events_open);
s.register_op_json_async("op_fs_events_poll", op_fs_events_poll); super::reg_json_async(rt, "op_fs_events_poll", op_fs_events_poll);
} }
struct FsEventsResource { struct FsEventsResource {
@ -64,7 +64,7 @@ impl From<NotifyEvent> for FsEvent {
} }
fn op_fs_events_open( fn op_fs_events_open(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -90,19 +90,16 @@ fn op_fs_events_open(
RecursiveMode::NonRecursive RecursiveMode::NonRecursive
}; };
for path in &args.paths { for path in &args.paths {
state.check_read(&PathBuf::from(path))?; super::cli_state(state).check_read(&PathBuf::from(path))?;
watcher.watch(path, recursive_mode)?; watcher.watch(path, recursive_mode)?;
} }
let resource = FsEventsResource { watcher, receiver }; let resource = FsEventsResource { watcher, receiver };
let rid = state let rid = state.resource_table.add("fsEvents", Box::new(resource));
.resource_table
.borrow_mut()
.add("fsEvents", Box::new(resource));
Ok(json!(rid)) Ok(json!(rid))
} }
async fn op_fs_events_poll( async fn op_fs_events_poll(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -112,8 +109,9 @@ async fn op_fs_events_poll(
} }
let PollArgs { rid } = serde_json::from_value(args)?; let PollArgs { rid } = serde_json::from_value(args)?;
poll_fn(move |cx| { poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let watcher = resource_table let watcher = state
.resource_table
.get_mut::<FsEventsResource>(rid) .get_mut::<FsEventsResource>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
watcher watcher

View file

@ -2,18 +2,15 @@
//! https://url.spec.whatwg.org/#idna //! https://url.spec.whatwg.org/#idna
use crate::state::State;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use idna::domain_to_ascii; use idna::domain_to_ascii;
use idna::domain_to_ascii_strict; use idna::domain_to_ascii_strict;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::rc::Rc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_domain_to_ascii", op_domain_to_ascii); super::reg_json_sync(rt, "op_domain_to_ascii", op_domain_to_ascii);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -24,7 +21,7 @@ struct DomainToAscii {
} }
fn op_domain_to_ascii( fn op_domain_to_ascii(
_state: &State, _state: &mut deno_core::OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {

View file

@ -1,11 +1,15 @@
use super::dispatch_minimal::minimal_op;
use super::dispatch_minimal::MinimalOp; use super::dispatch_minimal::MinimalOp;
use crate::http_util::HttpBody; use crate::http_util::HttpBody;
use crate::state::State; use crate::metrics::metrics_op;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::JsRuntime;
use deno_core::OpState;
use futures::future::poll_fn; use futures::future::poll_fn;
use futures::future::FutureExt; use futures::future::FutureExt;
use futures::ready; use futures::ready;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
@ -82,9 +86,9 @@ lazy_static! {
}; };
} }
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut JsRuntime) {
s.register_op_minimal("op_read", op_read); rt.register_op("op_read", metrics_op(minimal_op(op_read)));
s.register_op_minimal("op_write", op_write); rt.register_op("op_write", metrics_op(minimal_op(op_write)));
} }
pub fn get_stdio() -> ( pub fn get_stdio() -> (
@ -233,7 +237,7 @@ impl DenoAsyncRead for StreamResource {
} }
pub fn op_read( pub fn op_read(
state: Rc<State>, state: Rc<RefCell<OpState>>,
is_sync: bool, is_sync: bool,
rid: i32, rid: i32,
mut zero_copy: BufVec, mut zero_copy: BufVec,
@ -248,7 +252,7 @@ pub fn op_read(
if is_sync { if is_sync {
MinimalOp::Sync({ MinimalOp::Sync({
// First we look up the rid in the resource table. // First we look up the rid in the resource table.
std_file_resource(&state, rid as u32, move |r| match r { std_file_resource(&mut state.borrow_mut(), rid as u32, move |r| match r {
Ok(std_file) => { Ok(std_file) => {
use std::io::Read; use std::io::Read;
std_file std_file
@ -265,8 +269,9 @@ pub fn op_read(
let mut zero_copy = zero_copy[0].clone(); let mut zero_copy = zero_copy[0].clone();
MinimalOp::Async( MinimalOp::Async(
poll_fn(move |cx| { poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let resource_holder = resource_table let resource_holder = state
.resource_table
.get_mut::<StreamResourceHolder>(rid as u32) .get_mut::<StreamResourceHolder>(rid as u32)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
@ -352,7 +357,7 @@ impl DenoAsyncWrite for StreamResource {
} }
pub fn op_write( pub fn op_write(
state: Rc<State>, state: Rc<RefCell<OpState>>,
is_sync: bool, is_sync: bool,
rid: i32, rid: i32,
zero_copy: BufVec, zero_copy: BufVec,
@ -367,7 +372,7 @@ pub fn op_write(
if is_sync { if is_sync {
MinimalOp::Sync({ MinimalOp::Sync({
// First we look up the rid in the resource table. // First we look up the rid in the resource table.
std_file_resource(&state, rid as u32, move |r| match r { std_file_resource(&mut state.borrow_mut(), rid as u32, move |r| match r {
Ok(std_file) => { Ok(std_file) => {
use std::io::Write; use std::io::Write;
std_file std_file
@ -385,8 +390,9 @@ pub fn op_write(
MinimalOp::Async( MinimalOp::Async(
async move { async move {
let nwritten = poll_fn(|cx| { let nwritten = poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let resource_holder = resource_table let resource_holder = state
.resource_table
.get_mut::<StreamResourceHolder>(rid as u32) .get_mut::<StreamResourceHolder>(rid as u32)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
resource_holder.resource.poll_write(cx, &zero_copy) resource_holder.resource.poll_write(cx, &zero_copy)
@ -398,8 +404,9 @@ pub fn op_write(
// Figure out why it's needed and preferably remove it. // Figure out why it's needed and preferably remove it.
// https://github.com/denoland/deno/issues/3565 // https://github.com/denoland/deno/issues/3565
poll_fn(|cx| { poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let resource_holder = resource_table let resource_holder = state
.resource_table
.get_mut::<StreamResourceHolder>(rid as u32) .get_mut::<StreamResourceHolder>(rid as u32)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
resource_holder.resource.poll_flush(cx) resource_holder.resource.poll_flush(cx)
@ -421,7 +428,7 @@ pub fn op_write(
/// ///
/// Returns ErrorKind::Busy if the resource is being used by another op. /// Returns ErrorKind::Busy if the resource is being used by another op.
pub fn std_file_resource<F, T>( pub fn std_file_resource<F, T>(
state: &State, state: &mut OpState,
rid: u32, rid: u32,
mut f: F, mut f: F,
) -> Result<T, ErrBox> ) -> Result<T, ErrBox>
@ -430,8 +437,7 @@ where
FnMut(Result<&mut std::fs::File, &mut StreamResource>) -> Result<T, ErrBox>, FnMut(Result<&mut std::fs::File, &mut StreamResource>) -> Result<T, ErrBox>,
{ {
// First we look up the rid in the resource table. // First we look up the rid in the resource table.
let mut resource_table = state.resource_table.borrow_mut(); let mut r = state.resource_table.get_mut::<StreamResourceHolder>(rid);
let mut r = resource_table.get_mut::<StreamResourceHolder>(rid);
if let Some(ref mut resource_holder) = r { if let Some(ref mut resource_holder) = r {
// Sync write only works for FsFile. It doesn't make sense to do this // Sync write only works for FsFile. It doesn't make sense to do this
// for non-blocking sockets. So we error out if not FsFile. // for non-blocking sockets. So we error out if not FsFile.

View file

@ -29,3 +29,43 @@ pub mod tty;
pub mod web_worker; pub mod web_worker;
pub mod websocket; pub mod websocket;
pub mod worker_host; pub mod worker_host;
use crate::metrics::metrics_op;
use deno_core::json_op_async;
use deno_core::json_op_sync;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::JsRuntime;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use serde_json::Value;
use std::cell::RefCell;
use std::future::Future;
use std::rc::Rc;
pub fn reg_json_async<F, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
where
F: Fn(Rc<RefCell<OpState>>, Value, BufVec) -> R + 'static,
R: Future<Output = Result<Value, ErrBox>> + 'static,
{
rt.register_op(name, metrics_op(json_op_async(op_fn)));
}
pub fn reg_json_sync<F>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
where
F: Fn(&mut OpState, Value, &mut [ZeroCopyBuf]) -> Result<Value, ErrBox>
+ 'static,
{
rt.register_op(name, metrics_op(json_op_sync(op_fn)));
}
/// Helper for extracting the commonly used state. Used for sync ops.
pub fn cli_state(state: &OpState) -> Rc<crate::state::State> {
state.borrow::<Rc<crate::state::State>>().clone()
}
/// Helper for extracting the commonly used state. Used for async ops.
pub fn cli_state2(state: &Rc<RefCell<OpState>>) -> Rc<crate::state::State> {
let state = state.borrow();
state.borrow::<Rc<crate::state::State>>().clone()
}

View file

@ -2,14 +2,14 @@
use crate::ops::io::{StreamResource, StreamResourceHolder}; use crate::ops::io::{StreamResource, StreamResourceHolder};
use crate::resolve_addr::resolve_addr; use crate::resolve_addr::resolve_addr;
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use futures::future::poll_fn; use futures::future::poll_fn;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::net::Shutdown; use std::net::Shutdown;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::rc::Rc; use std::rc::Rc;
@ -22,13 +22,13 @@ use tokio::net::UdpSocket;
#[cfg(unix)] #[cfg(unix)]
use super::net_unix; use super::net_unix;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_async("op_accept", op_accept); super::reg_json_async(rt, "op_accept", op_accept);
s.register_op_json_async("op_connect", op_connect); super::reg_json_async(rt, "op_connect", op_connect);
s.register_op_json_sync("op_shutdown", op_shutdown); super::reg_json_sync(rt, "op_shutdown", op_shutdown);
s.register_op_json_sync("op_listen", op_listen); super::reg_json_sync(rt, "op_listen", op_listen);
s.register_op_json_async("op_datagram_receive", op_datagram_receive); super::reg_json_async(rt, "op_datagram_receive", op_datagram_receive);
s.register_op_json_async("op_datagram_send", op_datagram_send); super::reg_json_async(rt, "op_datagram_send", op_datagram_send);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -38,15 +38,16 @@ pub(crate) struct AcceptArgs {
} }
async fn accept_tcp( async fn accept_tcp(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: AcceptArgs, args: AcceptArgs,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let rid = args.rid as u32; let rid = args.rid as u32;
let accept_fut = poll_fn(|cx| { let accept_fut = poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let listener_resource = resource_table let listener_resource = state
.resource_table
.get_mut::<TcpListenerResource>(rid) .get_mut::<TcpListenerResource>(rid)
.ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?; .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?;
let listener = &mut listener_resource.listener; let listener = &mut listener_resource.listener;
@ -68,7 +69,9 @@ async fn accept_tcp(
let (tcp_stream, _socket_addr) = accept_fut.await?; let (tcp_stream, _socket_addr) = accept_fut.await?;
let local_addr = tcp_stream.local_addr()?; let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?; let remote_addr = tcp_stream.peer_addr()?;
let rid = state.resource_table.borrow_mut().add(
let mut state = state.borrow_mut();
let rid = state.resource_table.add(
"tcpStream", "tcpStream",
Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some( Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some(
tcp_stream, tcp_stream,
@ -90,7 +93,7 @@ async fn accept_tcp(
} }
async fn op_accept( async fn op_accept(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
bufs: BufVec, bufs: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -113,7 +116,7 @@ pub(crate) struct ReceiveArgs {
} }
async fn receive_udp( async fn receive_udp(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: ReceiveArgs, args: ReceiveArgs,
zero_copy: BufVec, zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -123,8 +126,9 @@ async fn receive_udp(
let rid = args.rid as u32; let rid = args.rid as u32;
let receive_fut = poll_fn(|cx| { let receive_fut = poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let resource = resource_table let resource = state
.resource_table
.get_mut::<UdpSocketResource>(rid) .get_mut::<UdpSocketResource>(rid)
.ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?;
let socket = &mut resource.socket; let socket = &mut resource.socket;
@ -144,7 +148,7 @@ async fn receive_udp(
} }
async fn op_datagram_receive( async fn op_datagram_receive(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
zero_copy: BufVec, zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -171,12 +175,13 @@ struct SendArgs {
} }
async fn op_datagram_send( async fn op_datagram_send(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
zero_copy: BufVec, zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
assert_eq!(zero_copy.len(), 1, "Invalid number of arguments"); assert_eq!(zero_copy.len(), 1, "Invalid number of arguments");
let zero_copy = zero_copy[0].clone(); let zero_copy = zero_copy[0].clone();
let cli_state = super::cli_state2(&state);
match serde_json::from_value(args)? { match serde_json::from_value(args)? {
SendArgs { SendArgs {
@ -184,11 +189,12 @@ async fn op_datagram_send(
transport, transport,
transport_args: ArgsEnum::Ip(args), transport_args: ArgsEnum::Ip(args),
} if transport == "udp" => { } if transport == "udp" => {
state.check_net(&args.hostname, args.port)?; cli_state.check_net(&args.hostname, args.port)?;
let addr = resolve_addr(&args.hostname, args.port)?; let addr = resolve_addr(&args.hostname, args.port)?;
poll_fn(move |cx| { poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let resource = resource_table let resource = state
.resource_table
.get_mut::<UdpSocketResource>(rid as u32) .get_mut::<UdpSocketResource>(rid as u32)
.ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?;
resource resource
@ -206,9 +212,10 @@ async fn op_datagram_send(
transport_args: ArgsEnum::Unix(args), transport_args: ArgsEnum::Unix(args),
} if transport == "unixpacket" => { } if transport == "unixpacket" => {
let address_path = net_unix::Path::new(&args.path); let address_path = net_unix::Path::new(&args.path);
state.check_read(&address_path)?; cli_state.check_read(&address_path)?;
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let resource = resource_table let resource = state
.resource_table
.get_mut::<net_unix::UnixDatagramResource>(rid as u32) .get_mut::<net_unix::UnixDatagramResource>(rid as u32)
.ok_or_else(|| ErrBox::new("NotConnected", "Socket has been closed"))?; .ok_or_else(|| ErrBox::new("NotConnected", "Socket has been closed"))?;
let socket = &mut resource.socket; let socket = &mut resource.socket;
@ -230,21 +237,24 @@ struct ConnectArgs {
} }
async fn op_connect( async fn op_connect(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let cli_state = super::cli_state2(&state);
match serde_json::from_value(args)? { match serde_json::from_value(args)? {
ConnectArgs { ConnectArgs {
transport, transport,
transport_args: ArgsEnum::Ip(args), transport_args: ArgsEnum::Ip(args),
} if transport == "tcp" => { } if transport == "tcp" => {
state.check_net(&args.hostname, args.port)?; cli_state.check_net(&args.hostname, args.port)?;
let addr = resolve_addr(&args.hostname, args.port)?; let addr = resolve_addr(&args.hostname, args.port)?;
let tcp_stream = TcpStream::connect(&addr).await?; let tcp_stream = TcpStream::connect(&addr).await?;
let local_addr = tcp_stream.local_addr()?; let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?; let remote_addr = tcp_stream.peer_addr()?;
let rid = state.resource_table.borrow_mut().add(
let mut state_ = state.borrow_mut();
let rid = state_.resource_table.add(
"tcpStream", "tcpStream",
Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some( Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some(
tcp_stream, tcp_stream,
@ -270,14 +280,16 @@ async fn op_connect(
transport_args: ArgsEnum::Unix(args), transport_args: ArgsEnum::Unix(args),
} if transport == "unix" => { } if transport == "unix" => {
let address_path = net_unix::Path::new(&args.path); let address_path = net_unix::Path::new(&args.path);
state.check_unstable("Deno.connect"); cli_state.check_unstable("Deno.connect");
state.check_read(&address_path)?; cli_state.check_read(&address_path)?;
let path = args.path; let path = args.path;
let unix_stream = let unix_stream =
net_unix::UnixStream::connect(net_unix::Path::new(&path)).await?; net_unix::UnixStream::connect(net_unix::Path::new(&path)).await?;
let local_addr = unix_stream.local_addr()?; let local_addr = unix_stream.local_addr()?;
let remote_addr = unix_stream.peer_addr()?; let remote_addr = unix_stream.peer_addr()?;
let rid = state.resource_table.borrow_mut().add(
let mut state_ = state.borrow_mut();
let rid = state_.resource_table.add(
"unixStream", "unixStream",
Box::new(StreamResourceHolder::new(StreamResource::UnixStream( Box::new(StreamResourceHolder::new(StreamResource::UnixStream(
unix_stream, unix_stream,
@ -306,11 +318,11 @@ struct ShutdownArgs {
} }
fn op_shutdown( fn op_shutdown(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.shutdown"); super::cli_state(state).check_unstable("Deno.shutdown");
let args: ShutdownArgs = serde_json::from_value(args)?; let args: ShutdownArgs = serde_json::from_value(args)?;
@ -323,8 +335,8 @@ fn op_shutdown(
_ => unimplemented!(), _ => unimplemented!(),
}; };
let mut resource_table = state.resource_table.borrow_mut(); let resource_holder = state
let resource_holder = resource_table .resource_table
.get_mut::<StreamResourceHolder>(rid) .get_mut::<StreamResourceHolder>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
match resource_holder.resource { match resource_holder.resource {
@ -416,7 +428,7 @@ struct ListenArgs {
} }
fn listen_tcp( fn listen_tcp(
state: &State, state: &mut OpState,
addr: SocketAddr, addr: SocketAddr,
) -> Result<(u32, SocketAddr), ErrBox> { ) -> Result<(u32, SocketAddr), ErrBox> {
let std_listener = std::net::TcpListener::bind(&addr)?; let std_listener = std::net::TcpListener::bind(&addr)?;
@ -429,14 +441,13 @@ fn listen_tcp(
}; };
let rid = state let rid = state
.resource_table .resource_table
.borrow_mut()
.add("tcpListener", Box::new(listener_resource)); .add("tcpListener", Box::new(listener_resource));
Ok((rid, local_addr)) Ok((rid, local_addr))
} }
fn listen_udp( fn listen_udp(
state: &State, state: &mut OpState,
addr: SocketAddr, addr: SocketAddr,
) -> Result<(u32, SocketAddr), ErrBox> { ) -> Result<(u32, SocketAddr), ErrBox> {
let std_socket = std::net::UdpSocket::bind(&addr)?; let std_socket = std::net::UdpSocket::bind(&addr)?;
@ -445,26 +456,28 @@ fn listen_udp(
let socket_resource = UdpSocketResource { socket }; let socket_resource = UdpSocketResource { socket };
let rid = state let rid = state
.resource_table .resource_table
.borrow_mut()
.add("udpSocket", Box::new(socket_resource)); .add("udpSocket", Box::new(socket_resource));
Ok((rid, local_addr)) Ok((rid, local_addr))
} }
fn op_listen( fn op_listen(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let cli_state = super::cli_state(state);
match serde_json::from_value(args)? { match serde_json::from_value(args)? {
ListenArgs { ListenArgs {
transport, transport,
transport_args: ArgsEnum::Ip(args), transport_args: ArgsEnum::Ip(args),
} => { } => {
if transport == "udp" { {
state.check_unstable("Deno.listenDatagram"); if transport == "udp" {
cli_state.check_unstable("Deno.listenDatagram");
}
cli_state.check_net(&args.hostname, args.port)?;
} }
state.check_net(&args.hostname, args.port)?;
let addr = resolve_addr(&args.hostname, args.port)?; let addr = resolve_addr(&args.hostname, args.port)?;
let (rid, local_addr) = if transport == "tcp" { let (rid, local_addr) = if transport == "tcp" {
listen_tcp(state, addr)? listen_tcp(state, addr)?
@ -491,15 +504,17 @@ fn op_listen(
transport, transport,
transport_args: ArgsEnum::Unix(args), transport_args: ArgsEnum::Unix(args),
} if transport == "unix" || transport == "unixpacket" => { } if transport == "unix" || transport == "unixpacket" => {
if transport == "unix" {
state.check_unstable("Deno.listen");
}
if transport == "unixpacket" {
state.check_unstable("Deno.listenDatagram");
}
let address_path = net_unix::Path::new(&args.path); let address_path = net_unix::Path::new(&args.path);
state.check_read(&address_path)?; {
state.check_write(&address_path)?; if transport == "unix" {
cli_state.check_unstable("Deno.listen");
}
if transport == "unixpacket" {
cli_state.check_unstable("Deno.listenDatagram");
}
cli_state.check_read(&address_path)?;
cli_state.check_write(&address_path)?;
}
let (rid, local_addr) = if transport == "unix" { let (rid, local_addr) = if transport == "unix" {
net_unix::listen_unix(state, &address_path)? net_unix::listen_unix(state, &address_path)?
} else { } else {

View file

@ -2,15 +2,18 @@ use crate::ops::io::StreamResource;
use crate::ops::io::StreamResourceHolder; use crate::ops::io::StreamResourceHolder;
use crate::ops::net::AcceptArgs; use crate::ops::net::AcceptArgs;
use crate::ops::net::ReceiveArgs; use crate::ops::net::ReceiveArgs;
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpState;
use futures::future::poll_fn;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::fs::remove_file; use std::fs::remove_file;
use std::os::unix; use std::os::unix;
pub use std::path::Path; pub use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
use std::task::Poll;
use tokio::net::UnixDatagram; use tokio::net::UnixDatagram;
use tokio::net::UnixListener; use tokio::net::UnixListener;
pub use tokio::net::UnixStream; pub use tokio::net::UnixStream;
@ -30,25 +33,39 @@ pub struct UnixListenArgs {
} }
pub(crate) async fn accept_unix( pub(crate) async fn accept_unix(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: AcceptArgs, args: AcceptArgs,
_bufs: BufVec, _bufs: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let rid = args.rid as u32; let rid = args.rid as u32;
let mut resource_table_ = state.resource_table.borrow_mut(); let accept_fut = poll_fn(|cx| {
let listener_resource = { let mut state = state.borrow_mut();
resource_table_ let listener_resource = state
.resource_table
.get_mut::<UnixListenerResource>(rid) .get_mut::<UnixListenerResource>(rid)
.ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))? .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?;
}; let listener = &mut listener_resource.listener;
let (unix_stream, _socket_addr) = listener_resource.listener.accept().await?; use futures::StreamExt;
drop(resource_table_); match listener.poll_next_unpin(cx) {
Poll::Ready(Some(stream)) => {
//listener_resource.untrack_task();
Poll::Ready(stream)
}
Poll::Ready(None) => todo!(),
Poll::Pending => {
//listener_resource.track_task(cx)?;
Poll::Pending
}
}
.map_err(ErrBox::from)
});
let unix_stream = accept_fut.await?;
let local_addr = unix_stream.local_addr()?; let local_addr = unix_stream.local_addr()?;
let remote_addr = unix_stream.peer_addr()?; let remote_addr = unix_stream.peer_addr()?;
let mut resource_table_ = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let rid = resource_table_.add( let rid = state.resource_table.add(
"unixStream", "unixStream",
Box::new(StreamResourceHolder::new(StreamResource::UnixStream( Box::new(StreamResourceHolder::new(StreamResource::UnixStream(
unix_stream, unix_stream,
@ -68,7 +85,7 @@ pub(crate) async fn accept_unix(
} }
pub(crate) async fn receive_unix_packet( pub(crate) async fn receive_unix_packet(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: ReceiveArgs, args: ReceiveArgs,
bufs: BufVec, bufs: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -77,8 +94,9 @@ pub(crate) async fn receive_unix_packet(
let rid = args.rid as u32; let rid = args.rid as u32;
let mut buf = bufs.into_iter().next().unwrap(); let mut buf = bufs.into_iter().next().unwrap();
let mut resource_table_ = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let resource = resource_table_ let resource = state
.resource_table
.get_mut::<UnixDatagramResource>(rid) .get_mut::<UnixDatagramResource>(rid)
.ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?;
let (size, remote_addr) = resource.socket.recv_from(&mut buf).await?; let (size, remote_addr) = resource.socket.recv_from(&mut buf).await?;
@ -92,7 +110,7 @@ pub(crate) async fn receive_unix_packet(
} }
pub fn listen_unix( pub fn listen_unix(
state: &State, state: &mut OpState,
addr: &Path, addr: &Path,
) -> Result<(u32, unix::net::SocketAddr), ErrBox> { ) -> Result<(u32, unix::net::SocketAddr), ErrBox> {
if addr.exists() { if addr.exists() {
@ -103,14 +121,13 @@ pub fn listen_unix(
let listener_resource = UnixListenerResource { listener }; let listener_resource = UnixListenerResource { listener };
let rid = state let rid = state
.resource_table .resource_table
.borrow_mut()
.add("unixListener", Box::new(listener_resource)); .add("unixListener", Box::new(listener_resource));
Ok((rid, local_addr)) Ok((rid, local_addr))
} }
pub fn listen_unix_packet( pub fn listen_unix_packet(
state: &State, state: &mut OpState,
addr: &Path, addr: &Path,
) -> Result<(u32, unix::net::SocketAddr), ErrBox> { ) -> Result<(u32, unix::net::SocketAddr), ErrBox> {
if addr.exists() { if addr.exists() {
@ -124,7 +141,6 @@ pub fn listen_unix_packet(
}; };
let rid = state let rid = state
.resource_table .resource_table
.borrow_mut()
.add("unixDatagram", Box::new(datagram_resource)); .add("unixDatagram", Box::new(datagram_resource));
Ok((rid, local_addr)) Ok((rid, local_addr))

View file

@ -1,36 +1,35 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::rc::Rc;
use url::Url; use url::Url;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_exit", op_exit); super::reg_json_sync(rt, "op_exit", op_exit);
s.register_op_json_sync("op_env", op_env); super::reg_json_sync(rt, "op_env", op_env);
s.register_op_json_sync("op_exec_path", op_exec_path); super::reg_json_sync(rt, "op_exec_path", op_exec_path);
s.register_op_json_sync("op_set_env", op_set_env); super::reg_json_sync(rt, "op_set_env", op_set_env);
s.register_op_json_sync("op_get_env", op_get_env); super::reg_json_sync(rt, "op_get_env", op_get_env);
s.register_op_json_sync("op_delete_env", op_delete_env); super::reg_json_sync(rt, "op_delete_env", op_delete_env);
s.register_op_json_sync("op_hostname", op_hostname); super::reg_json_sync(rt, "op_hostname", op_hostname);
s.register_op_json_sync("op_loadavg", op_loadavg); super::reg_json_sync(rt, "op_loadavg", op_loadavg);
s.register_op_json_sync("op_os_release", op_os_release); super::reg_json_sync(rt, "op_os_release", op_os_release);
s.register_op_json_sync("op_system_memory_info", op_system_memory_info); super::reg_json_sync(rt, "op_system_memory_info", op_system_memory_info);
} }
fn op_exec_path( fn op_exec_path(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let current_exe = env::current_exe().unwrap(); let current_exe = env::current_exe().unwrap();
state.check_read_blind(&current_exe, "exec_path")?; let cli_state = super::cli_state(state);
cli_state.check_read_blind(&current_exe, "exec_path")?;
// Now apply URL parser to current exe to get fully resolved path, otherwise // Now apply URL parser to current exe to get fully resolved path, otherwise
// we might get `./` and `../` bits in `exec_path` // we might get `./` and `../` bits in `exec_path`
let exe_url = Url::from_file_path(current_exe).unwrap(); let exe_url = Url::from_file_path(current_exe).unwrap();
@ -45,22 +44,24 @@ struct SetEnv {
} }
fn op_set_env( fn op_set_env(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: SetEnv = serde_json::from_value(args)?; let args: SetEnv = serde_json::from_value(args)?;
state.check_env()?; let cli_state = super::cli_state(state);
cli_state.check_env()?;
env::set_var(args.key, args.value); env::set_var(args.key, args.value);
Ok(json!({})) Ok(json!({}))
} }
fn op_env( fn op_env(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_env()?; let cli_state = super::cli_state(state);
cli_state.check_env()?;
let v = env::vars().collect::<HashMap<String, String>>(); let v = env::vars().collect::<HashMap<String, String>>();
Ok(json!(v)) Ok(json!(v))
} }
@ -71,12 +72,13 @@ struct GetEnv {
} }
fn op_get_env( fn op_get_env(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: GetEnv = serde_json::from_value(args)?; let args: GetEnv = serde_json::from_value(args)?;
state.check_env()?; let cli_state = super::cli_state(state);
cli_state.check_env()?;
let r = match env::var(args.key) { let r = match env::var(args.key) {
Err(env::VarError::NotPresent) => json!([]), Err(env::VarError::NotPresent) => json!([]),
v => json!([v?]), v => json!([v?]),
@ -90,12 +92,13 @@ struct DeleteEnv {
} }
fn op_delete_env( fn op_delete_env(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: DeleteEnv = serde_json::from_value(args)?; let args: DeleteEnv = serde_json::from_value(args)?;
state.check_env()?; let cli_state = super::cli_state(state);
cli_state.check_env()?;
env::remove_var(args.key); env::remove_var(args.key);
Ok(json!({})) Ok(json!({}))
} }
@ -106,7 +109,7 @@ struct Exit {
} }
fn op_exit( fn op_exit(
_state: &State, _state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -115,12 +118,13 @@ fn op_exit(
} }
fn op_loadavg( fn op_loadavg(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.loadavg"); let cli_state = super::cli_state(state);
state.check_env()?; cli_state.check_unstable("Deno.loadavg");
cli_state.check_env()?;
match sys_info::loadavg() { match sys_info::loadavg() {
Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])), Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])),
Err(_) => Ok(json!([0f64, 0f64, 0f64])), Err(_) => Ok(json!([0f64, 0f64, 0f64])),
@ -128,34 +132,37 @@ fn op_loadavg(
} }
fn op_hostname( fn op_hostname(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.hostname"); let cli_state = super::cli_state(state);
state.check_env()?; cli_state.check_unstable("Deno.hostname");
cli_state.check_env()?;
let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string()); let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string());
Ok(json!(hostname)) Ok(json!(hostname))
} }
fn op_os_release( fn op_os_release(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.osRelease"); let cli_state = super::cli_state(state);
state.check_env()?; cli_state.check_unstable("Deno.osRelease");
cli_state.check_env()?;
let release = sys_info::os_release().unwrap_or_else(|_| "".to_string()); let release = sys_info::os_release().unwrap_or_else(|_| "".to_string());
Ok(json!(release)) Ok(json!(release))
} }
fn op_system_memory_info( fn op_system_memory_info(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.systemMemoryInfo"); let cli_state = super::cli_state(state);
state.check_env()?; cli_state.check_unstable("Deno.systemMemoryInfo");
cli_state.check_env()?;
match sys_info::mem_info() { match sys_info::mem_info() {
Ok(info) => Ok(json!({ Ok(info) => Ok(json!({
"total": info.total, "total": info.total,

View file

@ -1,18 +1,16 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::path::Path; use std::path::Path;
use std::rc::Rc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_query_permission", op_query_permission); super::reg_json_sync(rt, "op_query_permission", op_query_permission);
s.register_op_json_sync("op_revoke_permission", op_revoke_permission); super::reg_json_sync(rt, "op_revoke_permission", op_revoke_permission);
s.register_op_json_sync("op_request_permission", op_request_permission); super::reg_json_sync(rt, "op_request_permission", op_request_permission);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -23,12 +21,13 @@ struct PermissionArgs {
} }
pub fn op_query_permission( pub fn op_query_permission(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: PermissionArgs = serde_json::from_value(args)?; let args: PermissionArgs = serde_json::from_value(args)?;
let permissions = state.permissions.borrow(); let cli_state = super::cli_state(state);
let permissions = cli_state.permissions.borrow();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.query_read(&path.as_deref().map(Path::new)), "read" => permissions.query_read(&path.as_deref().map(Path::new)),
@ -49,12 +48,13 @@ pub fn op_query_permission(
} }
pub fn op_revoke_permission( pub fn op_revoke_permission(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: PermissionArgs = serde_json::from_value(args)?; let args: PermissionArgs = serde_json::from_value(args)?;
let mut permissions = state.permissions.borrow_mut(); let cli_state = super::cli_state(state);
let mut permissions = cli_state.permissions.borrow_mut();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.revoke_read(&path.as_deref().map(Path::new)), "read" => permissions.revoke_read(&path.as_deref().map(Path::new)),
@ -75,12 +75,13 @@ pub fn op_revoke_permission(
} }
pub fn op_request_permission( pub fn op_request_permission(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: PermissionArgs = serde_json::from_value(args)?; let args: PermissionArgs = serde_json::from_value(args)?;
let permissions = &mut state.permissions.borrow_mut(); let cli_state = super::cli_state(state);
let permissions = &mut cli_state.permissions.borrow_mut();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.request_read(&path.as_deref().map(Path::new)), "read" => permissions.request_read(&path.as_deref().map(Path::new)),

View file

@ -1,26 +1,28 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State; use crate::metrics::metrics_op;
use deno_core::plugin_api; use deno_core::plugin_api;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::JsRuntime;
use deno_core::Op; use deno_core::Op;
use deno_core::OpAsyncFuture; use deno_core::OpAsyncFuture;
use deno_core::OpId; use deno_core::OpId;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use dlopen::symbor::Library; use dlopen::symbor::Library;
use futures::prelude::*; use futures::prelude::*;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::path::PathBuf; use std::path::PathBuf;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::task::Context; use std::task::Context;
use std::task::Poll; use std::task::Poll;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut JsRuntime) {
s.register_op_json_sync("op_open_plugin", op_open_plugin); super::reg_json_sync(rt, "op_open_plugin", op_open_plugin);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -30,16 +32,16 @@ struct OpenPluginArgs {
} }
pub fn op_open_plugin( pub fn op_open_plugin(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.openPlugin"); let args: OpenPluginArgs = serde_json::from_value(args)?;
let args: OpenPluginArgs = serde_json::from_value(args).unwrap();
let filename = PathBuf::from(&args.filename); let filename = PathBuf::from(&args.filename);
state.check_plugin(&filename)?; let cli_state = super::cli_state(state);
cli_state.check_unstable("Deno.openPlugin");
cli_state.check_plugin(&filename)?;
debug!("Loading Plugin: {:#?}", filename); debug!("Loading Plugin: {:#?}", filename);
let plugin_lib = Library::open(filename).map(Rc::new)?; let plugin_lib = Library::open(filename).map(Rc::new)?;
@ -48,10 +50,12 @@ pub fn op_open_plugin(
let rid; let rid;
let deno_plugin_init; let deno_plugin_init;
{ {
let mut resource_table = state.resource_table.borrow_mut(); rid = state
rid = resource_table.add("plugin", Box::new(plugin_resource)); .resource_table
.add("plugin", Box::new(plugin_resource));
deno_plugin_init = *unsafe { deno_plugin_init = *unsafe {
resource_table state
.resource_table
.get::<PluginResource>(rid) .get::<PluginResource>(rid)
.unwrap() .unwrap()
.lib .lib
@ -77,12 +81,12 @@ impl PluginResource {
} }
struct PluginInterface<'a> { struct PluginInterface<'a> {
state: &'a State, state: &'a mut OpState,
plugin_lib: &'a Rc<Library>, plugin_lib: &'a Rc<Library>,
} }
impl<'a> PluginInterface<'a> { impl<'a> PluginInterface<'a> {
fn new(state: &'a State, plugin_lib: &'a Rc<Library>) -> Self { fn new(state: &'a mut OpState, plugin_lib: &'a Rc<Library>) -> Self {
Self { state, plugin_lib } Self { state, plugin_lib }
} }
} }
@ -99,23 +103,24 @@ impl<'a> plugin_api::Interface for PluginInterface<'a> {
dispatch_op_fn: plugin_api::DispatchOpFn, dispatch_op_fn: plugin_api::DispatchOpFn,
) -> OpId { ) -> OpId {
let plugin_lib = self.plugin_lib.clone(); let plugin_lib = self.plugin_lib.clone();
self.state.register_op( let plugin_op_fn = move |state_rc: Rc<RefCell<OpState>>,
name, mut zero_copy: BufVec| {
move |state: Rc<State>, mut zero_copy: BufVec| { let mut state = state_rc.borrow_mut();
let mut interface = PluginInterface::new(&state, &plugin_lib); let mut interface = PluginInterface::new(&mut state, &plugin_lib);
let op = dispatch_op_fn(&mut interface, &mut zero_copy); let op = dispatch_op_fn(&mut interface, &mut zero_copy);
match op { match op {
sync_op @ Op::Sync(..) => sync_op, sync_op @ Op::Sync(..) => sync_op,
Op::Async(fut) => { Op::Async(fut) => Op::Async(PluginOpAsyncFuture::new(&plugin_lib, fut)),
Op::Async(PluginOpAsyncFuture::new(&plugin_lib, fut)) Op::AsyncUnref(fut) => {
} Op::AsyncUnref(PluginOpAsyncFuture::new(&plugin_lib, fut))
Op::AsyncUnref(fut) => {
Op::AsyncUnref(PluginOpAsyncFuture::new(&plugin_lib, fut))
}
_ => unreachable!(),
} }
}, _ => unreachable!(),
) }
};
self
.state
.op_table
.register_op(name, metrics_op(Box::new(plugin_op_fn)))
} }
} }

View file

@ -2,28 +2,28 @@
use super::io::{std_file_resource, StreamResource, StreamResourceHolder}; use super::io::{std_file_resource, StreamResource, StreamResourceHolder};
use crate::signal::kill; use crate::signal::kill;
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use futures::future::poll_fn; use futures::future::poll_fn;
use futures::future::FutureExt; use futures::future::FutureExt;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use tokio::process::Command; use tokio::process::Command;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::process::ExitStatusExt; use std::os::unix::process::ExitStatusExt;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_run", op_run); super::reg_json_sync(rt, "op_run", op_run);
s.register_op_json_async("op_run_status", op_run_status); super::reg_json_async(rt, "op_run_status", op_run_status);
s.register_op_json_sync("op_kill", op_kill); super::reg_json_sync(rt, "op_kill", op_kill);
} }
fn clone_file(state: &State, rid: u32) -> Result<std::fs::File, ErrBox> { fn clone_file(state: &mut OpState, rid: u32) -> Result<std::fs::File, ErrBox> {
std_file_resource(state, rid, move |r| match r { std_file_resource(state, rid, move |r| match r {
Ok(std_file) => std_file.try_clone().map_err(ErrBox::from), Ok(std_file) => std_file.try_clone().map_err(ErrBox::from),
Err(_) => Err(ErrBox::bad_resource_id()), Err(_) => Err(ErrBox::bad_resource_id()),
@ -58,13 +58,12 @@ struct ChildResource {
} }
fn op_run( fn op_run(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let run_args: RunArgs = serde_json::from_value(args)?; let run_args: RunArgs = serde_json::from_value(args)?;
super::cli_state(state).check_run()?;
state.check_run()?;
let args = run_args.cmd; let args = run_args.cmd;
let env = run_args.env; let env = run_args.env;
@ -111,7 +110,7 @@ fn op_run(
let stdin_rid = match child.stdin.take() { let stdin_rid = match child.stdin.take() {
Some(child_stdin) => { Some(child_stdin) => {
let rid = state.resource_table.borrow_mut().add( let rid = state.resource_table.add(
"childStdin", "childStdin",
Box::new(StreamResourceHolder::new(StreamResource::ChildStdin( Box::new(StreamResourceHolder::new(StreamResource::ChildStdin(
child_stdin, child_stdin,
@ -124,7 +123,7 @@ fn op_run(
let stdout_rid = match child.stdout.take() { let stdout_rid = match child.stdout.take() {
Some(child_stdout) => { Some(child_stdout) => {
let rid = state.resource_table.borrow_mut().add( let rid = state.resource_table.add(
"childStdout", "childStdout",
Box::new(StreamResourceHolder::new(StreamResource::ChildStdout( Box::new(StreamResourceHolder::new(StreamResource::ChildStdout(
child_stdout, child_stdout,
@ -137,7 +136,7 @@ fn op_run(
let stderr_rid = match child.stderr.take() { let stderr_rid = match child.stderr.take() {
Some(child_stderr) => { Some(child_stderr) => {
let rid = state.resource_table.borrow_mut().add( let rid = state.resource_table.add(
"childStderr", "childStderr",
Box::new(StreamResourceHolder::new(StreamResource::ChildStderr( Box::new(StreamResourceHolder::new(StreamResource::ChildStderr(
child_stderr, child_stderr,
@ -149,10 +148,7 @@ fn op_run(
}; };
let child_resource = ChildResource { child }; let child_resource = ChildResource { child };
let child_rid = state let child_rid = state.resource_table.add("child", Box::new(child_resource));
.resource_table
.borrow_mut()
.add("child", Box::new(child_resource));
Ok(json!({ Ok(json!({
"rid": child_rid, "rid": child_rid,
@ -170,18 +166,19 @@ struct RunStatusArgs {
} }
async fn op_run_status( async fn op_run_status(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: RunStatusArgs = serde_json::from_value(args)?; let args: RunStatusArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
state.check_run()?; super::cli_state2(&state).check_run()?;
let run_status = poll_fn(|cx| { let run_status = poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let child_resource = resource_table let child_resource = state
.resource_table
.get_mut::<ChildResource>(rid) .get_mut::<ChildResource>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
let child = &mut child_resource.child; let child = &mut child_resource.child;
@ -215,12 +212,13 @@ struct KillArgs {
} }
fn op_kill( fn op_kill(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.kill"); let cli_state = super::cli_state(state);
state.check_run()?; cli_state.check_unstable("Deno.kill");
cli_state.check_run()?;
let args: KillArgs = serde_json::from_value(args)?; let args: KillArgs = serde_json::from_value(args)?;
kill(args.pid, args.signo)?; kill(args.pid, args.signo)?;

View file

@ -1,26 +1,24 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use rand::thread_rng; use rand::thread_rng;
use rand::Rng; use rand::Rng;
use serde_json::Value; use serde_json::Value;
use std::rc::Rc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_get_random_values", op_get_random_values); super::reg_json_sync(rt, "op_get_random_values", op_get_random_values);
} }
fn op_get_random_values( fn op_get_random_values(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
zero_copy: &mut [ZeroCopyBuf], zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
assert_eq!(zero_copy.len(), 1); assert_eq!(zero_copy.len(), 1);
let cli_state = super::cli_state(state);
if let Some(seeded_rng) = &state.seeded_rng { if let Some(seeded_rng) = &cli_state.seeded_rng {
seeded_rng.borrow_mut().fill(&mut *zero_copy[0]); seeded_rng.borrow_mut().fill(&mut *zero_copy[0]);
} else { } else {
let mut rng = thread_rng(); let mut rng = thread_rng();

View file

@ -2,20 +2,20 @@
use crate::repl; use crate::repl;
use crate::repl::Repl; use crate::repl::Repl;
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_repl_start", op_repl_start); super::reg_json_sync(rt, "op_repl_start", op_repl_start);
s.register_op_json_async("op_repl_readline", op_repl_readline); super::reg_json_async(rt, "op_repl_readline", op_repl_readline);
} }
struct ReplResource(Arc<Mutex<Repl>>); struct ReplResource(Arc<Mutex<Repl>>);
@ -27,20 +27,19 @@ struct ReplStartArgs {
} }
fn op_repl_start( fn op_repl_start(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: ReplStartArgs = serde_json::from_value(args)?; let args: ReplStartArgs = serde_json::from_value(args)?;
debug!("op_repl_start {}", args.history_file); debug!("op_repl_start {}", args.history_file);
let history_path = let history_path = {
repl::history_path(&state.global_state.dir, &args.history_file); let cli_state = super::cli_state(state);
repl::history_path(&cli_state.global_state.dir, &args.history_file)
};
let repl = repl::Repl::new(history_path); let repl = repl::Repl::new(history_path);
let resource = ReplResource(Arc::new(Mutex::new(repl))); let resource = ReplResource(Arc::new(Mutex::new(repl)));
let rid = state let rid = state.resource_table.add("repl", Box::new(resource));
.resource_table
.borrow_mut()
.add("repl", Box::new(resource));
Ok(json!(rid)) Ok(json!(rid))
} }
@ -51,7 +50,7 @@ struct ReplReadlineArgs {
} }
async fn op_repl_readline( async fn op_repl_readline(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -59,12 +58,14 @@ async fn op_repl_readline(
let rid = args.rid as u32; let rid = args.rid as u32;
let prompt = args.prompt; let prompt = args.prompt;
debug!("op_repl_readline {} {}", rid, prompt); debug!("op_repl_readline {} {}", rid, prompt);
let resource_table = state.resource_table.borrow(); let repl = {
let resource = resource_table let state = state.borrow();
.get::<ReplResource>(rid) let resource = state
.ok_or_else(ErrBox::bad_resource_id)?; .resource_table
let repl = resource.0.clone(); .get::<ReplResource>(rid)
drop(resource_table); .ok_or_else(ErrBox::bad_resource_id)?;
resource.0.clone()
};
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
let line = repl.lock().unwrap().readline(&prompt)?; let line = repl.lock().unwrap().readline(&prompt)?;
Ok(json!(line)) Ok(json!(line))

View file

@ -1,31 +1,28 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::rc::Rc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_resources", op_resources); super::reg_json_sync(rt, "op_resources", op_resources);
s.register_op_json_sync("op_close", op_close); super::reg_json_sync(rt, "op_close", op_close);
} }
fn op_resources( fn op_resources(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let resource_table = state.resource_table.borrow(); let serialized_resources = state.resource_table.entries();
let serialized_resources = resource_table.entries();
Ok(json!(serialized_resources)) Ok(json!(serialized_resources))
} }
/// op_close removes a resource from the resource table. /// op_close removes a resource from the resource table.
fn op_close( fn op_close(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -36,7 +33,6 @@ fn op_close(
let args: CloseArgs = serde_json::from_value(args)?; let args: CloseArgs = serde_json::from_value(args)?;
state state
.resource_table .resource_table
.borrow_mut()
.close(args.rid as u32) .close(args.rid as u32)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
Ok(json!({})) Ok(json!({}))

View file

@ -1,29 +1,27 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::colors; use crate::colors;
use crate::state::State;
use crate::version; use crate::version;
use crate::DenoSubcommand; use crate::DenoSubcommand;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use serde_json::Value; use serde_json::Value;
use std::env; use std::env;
use std::rc::Rc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_start", op_start); super::reg_json_sync(rt, "op_start", op_start);
s.register_op_json_sync("op_main_module", op_main_module); super::reg_json_sync(rt, "op_main_module", op_main_module);
s.register_op_json_sync("op_metrics", op_metrics); super::reg_json_sync(rt, "op_metrics", op_metrics);
} }
fn op_start( fn op_start(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let gs = &state.global_state; let gs = &super::cli_state(state).global_state;
Ok(json!({ Ok(json!({
// TODO(bartlomieju): `cwd` field is not used in JS, remove? // TODO(bartlomieju): `cwd` field is not used in JS, remove?
@ -44,25 +42,27 @@ fn op_start(
} }
fn op_main_module( fn op_main_module(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let main = &state.main_module.to_string(); let cli_state = super::cli_state(state);
let main = &cli_state.main_module.to_string();
let main_url = ModuleSpecifier::resolve_url_or_path(&main)?; let main_url = ModuleSpecifier::resolve_url_or_path(&main)?;
if main_url.as_url().scheme() == "file" { if main_url.as_url().scheme() == "file" {
let main_path = std::env::current_dir().unwrap().join(main_url.to_string()); let main_path = std::env::current_dir().unwrap().join(main_url.to_string());
state.check_read_blind(&main_path, "main_module")?; cli_state.check_read_blind(&main_path, "main_module")?;
} }
Ok(json!(&main)) Ok(json!(&main))
} }
fn op_metrics( fn op_metrics(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let m = &state.metrics.borrow(); let cli_state = super::cli_state(state);
let m = &cli_state.metrics.borrow();
Ok(json!({ Ok(json!({
"opsDispatched": m.ops_dispatched, "opsDispatched": m.ops_dispatched,

View file

@ -1,21 +1,21 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::futures::FutureExt; use crate::futures::FutureExt;
use crate::state::State;
use crate::tsc::runtime_bundle; use crate::tsc::runtime_bundle;
use crate::tsc::runtime_compile; use crate::tsc::runtime_compile;
use crate::tsc::runtime_transpile; use crate::tsc::runtime_transpile;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_async("op_compile", op_compile); super::reg_json_async(rt, "op_compile", op_compile);
s.register_op_json_async("op_transpile", op_transpile); super::reg_json_async(rt, "op_transpile", op_transpile);
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -28,14 +28,15 @@ struct CompileArgs {
} }
async fn op_compile( async fn op_compile(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_data: BufVec, _data: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.compile"); let cli_state = super::cli_state2(&state);
cli_state.check_unstable("Deno.compile");
let args: CompileArgs = serde_json::from_value(args)?; let args: CompileArgs = serde_json::from_value(args)?;
let global_state = state.global_state.clone(); let global_state = cli_state.global_state.clone();
let permissions = state.permissions.borrow().clone(); let permissions = cli_state.permissions.borrow().clone();
let fut = if args.bundle { let fut = if args.bundle {
runtime_bundle( runtime_bundle(
&global_state, &global_state,
@ -66,14 +67,15 @@ struct TranspileArgs {
} }
async fn op_transpile( async fn op_transpile(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_data: BufVec, _data: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.transpile"); let cli_state = super::cli_state2(&state);
cli_state.check_unstable("Deno.transpile");
let args: TranspileArgs = serde_json::from_value(args)?; let args: TranspileArgs = serde_json::from_value(args)?;
let global_state = state.global_state.clone(); let global_state = cli_state.global_state.clone();
let permissions = state.permissions.borrow().clone(); let permissions = cli_state.permissions.borrow().clone();
let result = let result =
runtime_transpile(&global_state, permissions, &args.sources, &args.options) runtime_transpile(&global_state, permissions, &args.sources, &args.options)
.await?; .await?;

View file

@ -1,11 +1,11 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
#[cfg(unix)] #[cfg(unix)]
@ -17,10 +17,10 @@ use std::task::Waker;
#[cfg(unix)] #[cfg(unix)]
use tokio::signal::unix::{signal, Signal, SignalKind}; use tokio::signal::unix::{signal, Signal, SignalKind};
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_signal_bind", op_signal_bind); super::reg_json_sync(rt, "op_signal_bind", op_signal_bind);
s.register_op_json_sync("op_signal_unbind", op_signal_unbind); super::reg_json_sync(rt, "op_signal_unbind", op_signal_unbind);
s.register_op_json_async("op_signal_poll", op_signal_poll); super::reg_json_async(rt, "op_signal_poll", op_signal_poll);
} }
#[cfg(unix)] #[cfg(unix)]
@ -42,13 +42,13 @@ struct SignalArgs {
#[cfg(unix)] #[cfg(unix)]
fn op_signal_bind( fn op_signal_bind(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.signal"); super::cli_state(state).check_unstable("Deno.signal");
let args: BindSignalArgs = serde_json::from_value(args)?; let args: BindSignalArgs = serde_json::from_value(args)?;
let rid = state.resource_table.borrow_mut().add( let rid = state.resource_table.add(
"signal", "signal",
Box::new(SignalStreamResource( Box::new(SignalStreamResource(
signal(SignalKind::from_raw(args.signo)).expect(""), signal(SignalKind::from_raw(args.signo)).expect(""),
@ -62,18 +62,18 @@ fn op_signal_bind(
#[cfg(unix)] #[cfg(unix)]
async fn op_signal_poll( async fn op_signal_poll(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.signal"); super::cli_state2(&state).check_unstable("Deno.signal");
let args: SignalArgs = serde_json::from_value(args)?; let args: SignalArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
let future = poll_fn(move |cx| { let future = poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
if let Some(mut signal) = if let Some(mut signal) =
resource_table.get_mut::<SignalStreamResource>(rid) state.resource_table.get_mut::<SignalStreamResource>(rid)
{ {
signal.1 = Some(cx.waker().clone()); signal.1 = Some(cx.waker().clone());
return signal.0.poll_recv(cx); return signal.0.poll_recv(cx);
@ -86,15 +86,14 @@ async fn op_signal_poll(
#[cfg(unix)] #[cfg(unix)]
pub fn op_signal_unbind( pub fn op_signal_unbind(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.signal"); super::cli_state(state).check_unstable("Deno.signal");
let mut resource_table = state.resource_table.borrow_mut();
let args: SignalArgs = serde_json::from_value(args)?; let args: SignalArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
let resource = resource_table.get_mut::<SignalStreamResource>(rid); let resource = state.resource_table.get_mut::<SignalStreamResource>(rid);
if let Some(signal) = resource { if let Some(signal) = resource {
if let Some(waker) = &signal.1 { if let Some(waker) = &signal.1 {
// Wakes up the pending poll if exists. // Wakes up the pending poll if exists.
@ -102,7 +101,8 @@ pub fn op_signal_unbind(
waker.clone().wake(); waker.clone().wake();
} }
} }
resource_table state
.resource_table
.close(rid) .close(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
Ok(json!({})) Ok(json!({}))
@ -110,7 +110,7 @@ pub fn op_signal_unbind(
#[cfg(not(unix))] #[cfg(not(unix))]
pub fn op_signal_bind( pub fn op_signal_bind(
_state: &State, _state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -119,7 +119,7 @@ pub fn op_signal_bind(
#[cfg(not(unix))] #[cfg(not(unix))]
fn op_signal_unbind( fn op_signal_unbind(
_state: &State, _state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -128,7 +128,7 @@ fn op_signal_unbind(
#[cfg(not(unix))] #[cfg(not(unix))]
async fn op_signal_poll( async fn op_signal_poll(
_state: Rc<State>, _state: Rc<RefCell<OpState>>,
_args: Value, _args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {

View file

@ -1,29 +1,30 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use futures::future::FutureExt; use futures::future::FutureExt;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::time::Duration; use std::time::Duration;
use std::time::Instant; use std::time::Instant;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_global_timer_stop", op_global_timer_stop); super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop);
s.register_op_json_async("op_global_timer", op_global_timer); super::reg_json_async(rt, "op_global_timer", op_global_timer);
s.register_op_json_sync("op_now", op_now); super::reg_json_sync(rt, "op_now", op_now);
} }
fn op_global_timer_stop( fn op_global_timer_stop(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.global_timer.borrow_mut().cancel(); let cli_state = super::cli_state(state);
cli_state.global_timer.borrow_mut().cancel();
Ok(json!({})) Ok(json!({}))
} }
@ -33,7 +34,7 @@ struct GlobalTimerArgs {
} }
async fn op_global_timer( async fn op_global_timer(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -41,11 +42,13 @@ async fn op_global_timer(
let val = args.timeout; let val = args.timeout;
let deadline = Instant::now() + Duration::from_millis(val); let deadline = Instant::now() + Duration::from_millis(val);
let timer_fut = state let timer_fut = {
.global_timer super::cli_state2(&state)
.borrow_mut() .global_timer
.new_timeout(deadline) .borrow_mut()
.boxed_local(); .new_timeout(deadline)
.boxed_local()
};
let _ = timer_fut.await; let _ = timer_fut.await;
Ok(json!({})) Ok(json!({}))
} }
@ -55,18 +58,19 @@ async fn op_global_timer(
// If the High precision flag is not set, the // If the High precision flag is not set, the
// nanoseconds are rounded on 2ms. // nanoseconds are rounded on 2ms.
fn op_now( fn op_now(
state: &State, state: &mut OpState,
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let seconds = state.start_time.elapsed().as_secs(); let cli_state = super::cli_state(state);
let mut subsec_nanos = state.start_time.elapsed().subsec_nanos(); let seconds = cli_state.start_time.elapsed().as_secs();
let mut subsec_nanos = cli_state.start_time.elapsed().subsec_nanos();
let reduced_time_precision = 2_000_000; // 2ms in nanoseconds let reduced_time_precision = 2_000_000; // 2ms in nanoseconds
// If the permission is not enabled // If the permission is not enabled
// Round the nano result on 2 milliseconds // Round the nano result on 2 milliseconds
// see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision // see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision
if state.check_hrtime().is_err() { if cli_state.check_hrtime().is_err() {
subsec_nanos -= subsec_nanos % reduced_time_precision; subsec_nanos -= subsec_nanos % reduced_time_precision;
} }

View file

@ -2,14 +2,14 @@
use super::io::{StreamResource, StreamResourceHolder}; use super::io::{StreamResource, StreamResourceHolder};
use crate::resolve_addr::resolve_addr; use crate::resolve_addr::resolve_addr;
use crate::state::State;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use futures::future::poll_fn; use futures::future::poll_fn;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::convert::From; use std::convert::From;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
@ -31,11 +31,11 @@ use tokio_rustls::{
}; };
use webpki::DNSNameRef; use webpki::DNSNameRef;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_async("op_start_tls", op_start_tls); super::reg_json_async(rt, "op_start_tls", op_start_tls);
s.register_op_json_async("op_connect_tls", op_connect_tls); super::reg_json_async(rt, "op_connect_tls", op_connect_tls);
s.register_op_json_sync("op_listen_tls", op_listen_tls); super::reg_json_sync(rt, "op_listen_tls", op_listen_tls);
s.register_op_json_async("op_accept_tls", op_accept_tls); super::reg_json_async(rt, "op_accept_tls", op_accept_tls);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -56,11 +56,10 @@ struct StartTLSArgs {
} }
async fn op_start_tls( async fn op_start_tls(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.startTls");
let args: StartTLSArgs = serde_json::from_value(args)?; let args: StartTLSArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
let cert_file = args.cert_file.clone(); let cert_file = args.cert_file.clone();
@ -69,15 +68,17 @@ async fn op_start_tls(
if domain.is_empty() { if domain.is_empty() {
domain.push_str("localhost"); domain.push_str("localhost");
} }
{
state.check_net(&domain, 0)?; let cli_state = super::cli_state2(&state);
if let Some(path) = cert_file.clone() { cli_state.check_unstable("Deno.startTls");
state.check_read(Path::new(&path))?; cli_state.check_net(&domain, 0)?;
if let Some(path) = cert_file.clone() {
cli_state.check_read(Path::new(&path))?;
}
} }
let mut resource_holder = { let mut resource_holder = {
let mut resource_table = state.resource_table.borrow_mut(); let mut state_ = state.borrow_mut();
match resource_table.remove::<StreamResourceHolder>(rid) { match state_.resource_table.remove::<StreamResourceHolder>(rid) {
Some(resource) => *resource, Some(resource) => *resource,
None => return Err(ErrBox::bad_resource_id()), None => return Err(ErrBox::bad_resource_id()),
} }
@ -104,13 +105,15 @@ async fn op_start_tls(
DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup"); DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup");
let tls_stream = tls_connector.connect(dnsname, tcp_stream).await?; let tls_stream = tls_connector.connect(dnsname, tcp_stream).await?;
let mut resource_table = state.resource_table.borrow_mut(); let rid = {
let rid = resource_table.add( let mut state_ = state.borrow_mut();
"clientTlsStream", state_.resource_table.add(
Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream( "clientTlsStream",
Box::new(tls_stream), Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream(
))), Box::new(tls_stream),
); ))),
)
};
Ok(json!({ Ok(json!({
"rid": rid, "rid": rid,
"localAddr": { "localAddr": {
@ -130,17 +133,19 @@ async fn op_start_tls(
} }
async fn op_connect_tls( async fn op_connect_tls(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: ConnectTLSArgs = serde_json::from_value(args)?; let args: ConnectTLSArgs = serde_json::from_value(args)?;
let cert_file = args.cert_file.clone(); let cert_file = args.cert_file.clone();
state.check_net(&args.hostname, args.port)?; {
if let Some(path) = cert_file.clone() { let cli_state = super::cli_state2(&state);
state.check_read(Path::new(&path))?; cli_state.check_net(&args.hostname, args.port)?;
if let Some(path) = cert_file.clone() {
cli_state.check_read(Path::new(&path))?;
}
} }
let mut domain = args.hostname.clone(); let mut domain = args.hostname.clone();
if domain.is_empty() { if domain.is_empty() {
domain.push_str("localhost"); domain.push_str("localhost");
@ -163,13 +168,15 @@ async fn op_connect_tls(
let dnsname = let dnsname =
DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup"); DNSNameRef::try_from_ascii_str(&domain).expect("Invalid DNS lookup");
let tls_stream = tls_connector.connect(dnsname, tcp_stream).await?; let tls_stream = tls_connector.connect(dnsname, tcp_stream).await?;
let mut resource_table = state.resource_table.borrow_mut(); let rid = {
let rid = resource_table.add( let mut state_ = state.borrow_mut();
"clientTlsStream", state_.resource_table.add(
Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream( "clientTlsStream",
Box::new(tls_stream), Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream(
))), Box::new(tls_stream),
); ))),
)
};
Ok(json!({ Ok(json!({
"rid": rid, "rid": rid,
"localAddr": { "localAddr": {
@ -298,7 +305,7 @@ struct ListenTlsArgs {
} }
fn op_listen_tls( fn op_listen_tls(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -307,11 +314,12 @@ fn op_listen_tls(
let cert_file = args.cert_file; let cert_file = args.cert_file;
let key_file = args.key_file; let key_file = args.key_file;
{
state.check_net(&args.hostname, args.port)?; let cli_state = super::cli_state(state);
state.check_read(Path::new(&cert_file))?; cli_state.check_net(&args.hostname, args.port)?;
state.check_read(Path::new(&key_file))?; cli_state.check_read(Path::new(&cert_file))?;
cli_state.check_read(Path::new(&key_file))?;
}
let mut config = ServerConfig::new(NoClientAuth::new()); let mut config = ServerConfig::new(NoClientAuth::new());
config config
.set_single_cert(load_certs(&cert_file)?, load_keys(&key_file)?.remove(0)) .set_single_cert(load_certs(&cert_file)?, load_keys(&key_file)?.remove(0))
@ -330,7 +338,6 @@ fn op_listen_tls(
let rid = state let rid = state
.resource_table .resource_table
.borrow_mut()
.add("tlsListener", Box::new(tls_listener_resource)); .add("tlsListener", Box::new(tls_listener_resource));
Ok(json!({ Ok(json!({
@ -349,15 +356,16 @@ struct AcceptTlsArgs {
} }
async fn op_accept_tls( async fn op_accept_tls(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: AcceptTlsArgs = serde_json::from_value(args)?; let args: AcceptTlsArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
let accept_fut = poll_fn(|cx| { let accept_fut = poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let listener_resource = resource_table let listener_resource = state
.resource_table
.get_mut::<TlsListenerResource>(rid) .get_mut::<TlsListenerResource>(rid)
.ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?; .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?;
let listener = &mut listener_resource.listener; let listener = &mut listener_resource.listener;
@ -380,8 +388,9 @@ async fn op_accept_tls(
let local_addr = tcp_stream.local_addr()?; let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?; let remote_addr = tcp_stream.peer_addr()?;
let tls_acceptor = { let tls_acceptor = {
let resource_table = state.resource_table.borrow(); let state_ = state.borrow();
let resource = resource_table let resource = state_
.resource_table
.get::<TlsListenerResource>(rid) .get::<TlsListenerResource>(rid)
.ok_or_else(ErrBox::bad_resource_id) .ok_or_else(ErrBox::bad_resource_id)
.expect("Can't find tls listener"); .expect("Can't find tls listener");
@ -389,8 +398,8 @@ async fn op_accept_tls(
}; };
let tls_stream = tls_acceptor.accept(tcp_stream).await?; let tls_stream = tls_acceptor.accept(tcp_stream).await?;
let rid = { let rid = {
let mut resource_table = state.resource_table.borrow_mut(); let mut state_ = state.borrow_mut();
resource_table.add( state_.resource_table.add(
"serverTlsStream", "serverTlsStream",
Box::new(StreamResourceHolder::new(StreamResource::ServerTlsStream( Box::new(StreamResourceHolder::new(StreamResource::ServerTlsStream(
Box::new(tls_stream), Box::new(tls_stream),

View file

@ -2,15 +2,13 @@
use super::io::std_file_resource; use super::io::std_file_resource;
use super::io::{StreamResource, StreamResourceHolder}; use super::io::{StreamResource, StreamResourceHolder};
use crate::state::State;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
#[cfg(unix)] #[cfg(unix)]
use nix::sys::termios; use nix::sys::termios;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use std::rc::Rc;
#[cfg(windows)] #[cfg(windows)]
use winapi::shared::minwindef::DWORD; use winapi::shared::minwindef::DWORD;
@ -20,6 +18,7 @@ use winapi::um::wincon;
const RAW_MODE_MASK: DWORD = wincon::ENABLE_LINE_INPUT const RAW_MODE_MASK: DWORD = wincon::ENABLE_LINE_INPUT
| wincon::ENABLE_ECHO_INPUT | wincon::ENABLE_ECHO_INPUT
| wincon::ENABLE_PROCESSED_INPUT; | wincon::ENABLE_PROCESSED_INPUT;
#[cfg(windows)] #[cfg(windows)]
fn get_windows_handle( fn get_windows_handle(
f: &std::fs::File, f: &std::fs::File,
@ -36,10 +35,10 @@ fn get_windows_handle(
Ok(handle) Ok(handle)
} }
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_set_raw", op_set_raw); super::reg_json_sync(rt, "op_set_raw", op_set_raw);
s.register_op_json_sync("op_isatty", op_isatty); super::reg_json_sync(rt, "op_isatty", op_isatty);
s.register_op_json_sync("op_console_size", op_console_size); super::reg_json_sync(rt, "op_console_size", op_console_size);
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -49,11 +48,12 @@ struct SetRawArgs {
} }
fn op_set_raw( fn op_set_raw(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.setRaw"); super::cli_state(state).check_unstable("Deno.setRaw");
let args: SetRawArgs = serde_json::from_value(args)?; let args: SetRawArgs = serde_json::from_value(args)?;
let rid = args.rid; let rid = args.rid;
let is_raw = args.mode; let is_raw = args.mode;
@ -69,8 +69,8 @@ fn op_set_raw(
use winapi::shared::minwindef::FALSE; use winapi::shared::minwindef::FALSE;
use winapi::um::{consoleapi, handleapi}; use winapi::um::{consoleapi, handleapi};
let mut resource_table = state.resource_table.borrow_mut(); let resource_holder =
let resource_holder = resource_table.get_mut::<StreamResourceHolder>(rid); state.resource_table.get_mut::<StreamResourceHolder>(rid);
if resource_holder.is_none() { if resource_holder.is_none() {
return Err(ErrBox::bad_resource_id()); return Err(ErrBox::bad_resource_id());
} }
@ -135,8 +135,8 @@ fn op_set_raw(
{ {
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
let mut resource_table = state.resource_table.borrow_mut(); let resource_holder =
let resource_holder = resource_table.get_mut::<StreamResourceHolder>(rid); state.resource_table.get_mut::<StreamResourceHolder>(rid);
if resource_holder.is_none() { if resource_holder.is_none() {
return Err(ErrBox::bad_resource_id()); return Err(ErrBox::bad_resource_id());
} }
@ -217,7 +217,7 @@ struct IsattyArgs {
} }
fn op_isatty( fn op_isatty(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -261,11 +261,12 @@ struct ConsoleSize {
} }
fn op_console_size( fn op_console_size(
state: &State, state: &mut OpState,
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
state.check_unstable("Deno.consoleSize"); super::cli_state(state).check_unstable("Deno.consoleSize");
let args: ConsoleSizeArgs = serde_json::from_value(args)?; let args: ConsoleSizeArgs = serde_json::from_value(args)?;
let rid = args.rid; let rid = args.rid;

View file

@ -1,20 +1,18 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use crate::web_worker::WebWorkerHandle; use crate::web_worker::WebWorkerHandle;
use crate::worker::WorkerEvent; use crate::worker::WorkerEvent;
use deno_core::OpRegistry;
use futures::channel::mpsc; use futures::channel::mpsc;
use std::rc::Rc;
pub fn init( pub fn init(
s: &Rc<State>, rt: &mut deno_core::JsRuntime,
sender: &mpsc::Sender<WorkerEvent>, sender: mpsc::Sender<WorkerEvent>,
handle: WebWorkerHandle, handle: WebWorkerHandle,
) { ) {
// Post message to host as guest worker. // Post message to host as guest worker.
let sender_ = sender.clone(); let sender_ = sender.clone();
s.register_op_json_sync( super::reg_json_sync(
rt,
"op_worker_post_message", "op_worker_post_message",
move |_state, _args, bufs| { move |_state, _args, bufs| {
assert_eq!(bufs.len(), 1, "Invalid number of arguments"); assert_eq!(bufs.len(), 1, "Invalid number of arguments");
@ -28,10 +26,9 @@ pub fn init(
); );
// Notify host that guest worker closes. // Notify host that guest worker closes.
let sender_ = sender.clone(); super::reg_json_sync(rt, "op_worker_close", move |_state, _args, _bufs| {
s.register_op_json_sync("op_worker_close", move |_state, _args, _bufs| {
// Notify parent that we're finished // Notify parent that we're finished
sender_.clone().close_channel(); sender.clone().close_channel();
// Terminate execution of current worker // Terminate execution of current worker
handle.terminate(); handle.terminate();
Ok(json!({})) Ok(json!({}))

View file

@ -1,10 +1,9 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use core::task::Poll; use core::task::Poll;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::OpRegistry; use deno_core::OpState;
use futures::future::poll_fn; use futures::future::poll_fn;
use futures::StreamExt; use futures::StreamExt;
use futures::{ready, SinkExt}; use futures::{ready, SinkExt};
@ -12,6 +11,7 @@ use http::{Method, Request, Uri};
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::RefCell;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use std::rc::Rc; use std::rc::Rc;
@ -26,11 +26,11 @@ use tokio_tungstenite::tungstenite::{
use tokio_tungstenite::{client_async, WebSocketStream}; use tokio_tungstenite::{client_async, WebSocketStream};
use webpki::DNSNameRef; use webpki::DNSNameRef;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_async("op_ws_create", op_ws_create); super::reg_json_async(rt, "op_ws_create", op_ws_create);
s.register_op_json_async("op_ws_send", op_ws_send); super::reg_json_async(rt, "op_ws_send", op_ws_send);
s.register_op_json_async("op_ws_close", op_ws_close); super::reg_json_async(rt, "op_ws_close", op_ws_close);
s.register_op_json_async("op_ws_next_event", op_ws_next_event); super::reg_json_async(rt, "op_ws_next_event", op_ws_next_event);
} }
type MaybeTlsStream = type MaybeTlsStream =
@ -46,13 +46,16 @@ struct CreateArgs {
} }
pub async fn op_ws_create( pub async fn op_ws_create(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_bufs: BufVec, _bufs: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: CreateArgs = serde_json::from_value(args)?; let args: CreateArgs = serde_json::from_value(args)?;
state.check_net_url(&url::Url::parse(&args.url)?)?; let ca_file = {
let ca_file = state.global_state.flags.ca_file.clone(); let cli_state = super::cli_state2(&state);
cli_state.check_net_url(&url::Url::parse(&args.url)?)?;
cli_state.global_state.flags.ca_file.clone()
};
let uri: Uri = args.url.parse().unwrap(); let uri: Uri = args.url.parse().unwrap();
let request = Request::builder() let request = Request::builder()
.method(Method::GET) .method(Method::GET)
@ -99,9 +102,9 @@ pub async fn op_ws_create(
let (stream, response): (WsStream, Response) = let (stream, response): (WsStream, Response) =
client_async(request, socket).await.unwrap(); client_async(request, socket).await.unwrap();
let mut state = state.borrow_mut();
let rid = state let rid = state
.resource_table .resource_table
.borrow_mut()
.add("webSocketStream", Box::new(stream)); .add("webSocketStream", Box::new(stream));
let protocol = match response.headers().get("Sec-WebSocket-Protocol") { let protocol = match response.headers().get("Sec-WebSocket-Protocol") {
@ -130,7 +133,7 @@ struct SendArgs {
} }
pub async fn op_ws_send( pub async fn op_ws_send(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
bufs: BufVec, bufs: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -143,8 +146,9 @@ pub async fn op_ws_send(
let rid = args.rid; let rid = args.rid;
poll_fn(move |cx| { poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let stream = resource_table let stream = state
.resource_table
.get_mut::<WsStream>(rid) .get_mut::<WsStream>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
@ -171,7 +175,7 @@ struct CloseArgs {
} }
pub async fn op_ws_close( pub async fn op_ws_close(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_bufs: BufVec, _bufs: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -186,8 +190,9 @@ pub async fn op_ws_close(
}))); })));
poll_fn(move |cx| { poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let stream = resource_table let stream = state
.resource_table
.get_mut::<WsStream>(rid) .get_mut::<WsStream>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
@ -213,14 +218,15 @@ struct NextEventArgs {
} }
pub async fn op_ws_next_event( pub async fn op_ws_next_event(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_bufs: BufVec, _bufs: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: NextEventArgs = serde_json::from_value(args)?; let args: NextEventArgs = serde_json::from_value(args)?;
poll_fn(move |cx| { poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut(); let mut state = state.borrow_mut();
let stream = resource_table let stream = state
.resource_table
.get_mut::<WsStream>(args.rid) .get_mut::<WsStream>(args.rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
stream stream
@ -248,7 +254,7 @@ pub async fn op_ws_next_event(
Some(Ok(Message::Pong(_))) => json!({"type": "pong"}), Some(Ok(Message::Pong(_))) => json!({"type": "pong"}),
Some(Err(_)) => json!({"type": "error"}), Some(Err(_)) => json!({"type": "error"}),
None => { None => {
resource_table.close(args.rid).unwrap(); state.resource_table.close(args.rid).unwrap();
json!({"type": "closed"}) json!({"type": "closed"})
} }
} }

View file

@ -5,7 +5,6 @@ use crate::global_state::GlobalState;
use crate::ops::io::get_stdio; use crate::ops::io::get_stdio;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::startup_data; use crate::startup_data;
use crate::state::State;
use crate::tokio_util::create_basic_runtime; use crate::tokio_util::create_basic_runtime;
use crate::web_worker::WebWorker; use crate::web_worker::WebWorker;
use crate::web_worker::WebWorkerHandle; use crate::web_worker::WebWorkerHandle;
@ -13,21 +12,26 @@ use crate::worker::WorkerEvent;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use futures::future::FutureExt; use futures::future::FutureExt;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::convert::From; use std::convert::From;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::thread::JoinHandle; use std::thread::JoinHandle;
pub fn init(s: &Rc<State>) { pub fn init(rt: &mut deno_core::JsRuntime) {
s.register_op_json_sync("op_create_worker", op_create_worker); super::reg_json_sync(rt, "op_create_worker", op_create_worker);
s.register_op_json_sync("op_host_terminate_worker", op_host_terminate_worker); super::reg_json_sync(
s.register_op_json_sync("op_host_post_message", op_host_post_message); rt,
s.register_op_json_async("op_host_get_message", op_host_get_message); "op_host_terminate_worker",
op_host_terminate_worker,
);
super::reg_json_sync(rt, "op_host_post_message", op_host_post_message);
super::reg_json_async(rt, "op_host_get_message", op_host_get_message);
} }
fn create_web_worker( fn create_web_worker(
@ -38,27 +42,31 @@ fn create_web_worker(
specifier: ModuleSpecifier, specifier: ModuleSpecifier,
has_deno_namespace: bool, has_deno_namespace: bool,
) -> Result<WebWorker, ErrBox> { ) -> Result<WebWorker, ErrBox> {
let state = let cli_state = crate::state::State::new_for_worker(
State::new_for_worker(global_state, Some(permissions), specifier)?; global_state,
Some(permissions),
specifier,
)?;
let mut worker = WebWorker::new( let mut worker = WebWorker::new(
name.clone(), name.clone(),
startup_data::deno_isolate_init(), startup_data::deno_isolate_init(),
&state, &cli_state,
has_deno_namespace, has_deno_namespace,
); );
if has_deno_namespace { if has_deno_namespace {
let mut resource_table = state.resource_table.borrow_mut(); let state = worker.isolate.op_state();
let mut state = state.borrow_mut();
let (stdin, stdout, stderr) = get_stdio(); let (stdin, stdout, stderr) = get_stdio();
if let Some(stream) = stdin { if let Some(stream) = stdin {
resource_table.add("stdin", Box::new(stream)); state.resource_table.add("stdin", Box::new(stream));
} }
if let Some(stream) = stdout { if let Some(stream) = stdout {
resource_table.add("stdout", Box::new(stream)); state.resource_table.add("stdout", Box::new(stream));
} }
if let Some(stream) = stderr { if let Some(stream) = stderr {
resource_table.add("stderr", Box::new(stream)); state.resource_table.add("stderr", Box::new(stream));
} }
} }
@ -172,10 +180,11 @@ struct CreateWorkerArgs {
/// Create worker as the host /// Create worker as the host
fn op_create_worker( fn op_create_worker(
state: &State, state: &mut OpState,
args: Value, args: Value,
_data: &mut [ZeroCopyBuf], _data: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let cli_state = super::cli_state(state);
let args: CreateWorkerArgs = serde_json::from_value(args)?; let args: CreateWorkerArgs = serde_json::from_value(args)?;
let specifier = args.specifier.clone(); let specifier = args.specifier.clone();
@ -187,12 +196,12 @@ fn op_create_worker(
let args_name = args.name; let args_name = args.name;
let use_deno_namespace = args.use_deno_namespace; let use_deno_namespace = args.use_deno_namespace;
if use_deno_namespace { if use_deno_namespace {
state.check_unstable("Worker.deno"); cli_state.check_unstable("Worker.deno");
} }
let global_state = state.global_state.clone(); let global_state = cli_state.global_state.clone();
let permissions = state.permissions.borrow().clone(); let permissions = cli_state.permissions.borrow().clone();
let worker_id = state.next_worker_id.get(); let worker_id = cli_state.next_worker_id.get();
state.next_worker_id.set(worker_id + 1); cli_state.next_worker_id.set(worker_id + 1);
let module_specifier = ModuleSpecifier::resolve_url(&specifier)?; let module_specifier = ModuleSpecifier::resolve_url(&specifier)?;
let worker_name = args_name.unwrap_or_else(|| "".to_string()); let worker_name = args_name.unwrap_or_else(|| "".to_string());
@ -208,7 +217,8 @@ fn op_create_worker(
)?; )?;
// At this point all interactions with worker happen using thread // At this point all interactions with worker happen using thread
// safe handler returned from previous function call // safe handler returned from previous function call
state let cli_state = super::cli_state(state);
cli_state
.workers .workers
.borrow_mut() .borrow_mut()
.insert(worker_id, (join_handle, worker_handle)); .insert(worker_id, (join_handle, worker_handle));
@ -222,13 +232,14 @@ struct WorkerArgs {
} }
fn op_host_terminate_worker( fn op_host_terminate_worker(
state: &State, state: &mut OpState,
args: Value, args: Value,
_data: &mut [ZeroCopyBuf], _data: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: WorkerArgs = serde_json::from_value(args)?; let args: WorkerArgs = serde_json::from_value(args)?;
let id = args.id as u32; let id = args.id as u32;
let (join_handle, worker_handle) = state let cli_state = super::cli_state(state);
let (join_handle, worker_handle) = cli_state
.workers .workers
.borrow_mut() .borrow_mut()
.remove(&id) .remove(&id)
@ -290,40 +301,41 @@ fn serialize_worker_event(event: WorkerEvent) -> Value {
/// Get message from guest worker as host /// Get message from guest worker as host
async fn op_host_get_message( async fn op_host_get_message(
state: Rc<State>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
let args: WorkerArgs = serde_json::from_value(args)?; let args: WorkerArgs = serde_json::from_value(args)?;
let id = args.id as u32; let id = args.id as u32;
let state = state.clone(); let cli_state = super::cli_state2(&state);
let workers_table = state.workers.borrow(); let worker_handle = {
let maybe_handle = workers_table.get(&id); let workers_table = cli_state.workers.borrow();
let worker_handle = if let Some(handle) = maybe_handle { let maybe_handle = workers_table.get(&id);
handle.1.clone() if let Some(handle) = maybe_handle {
} else { handle.1.clone()
// If handle was not found it means worker has already shutdown } else {
return Ok(json!({ "type": "close" })); // If handle was not found it means worker has already shutdown
return Ok(json!({ "type": "close" }));
}
}; };
drop(workers_table);
let response = match worker_handle.get_event().await? { let response = match worker_handle.get_event().await? {
Some(event) => { Some(event) => {
// Terminal error means that worker should be removed from worker table. // Terminal error means that worker should be removed from worker table.
if let WorkerEvent::TerminalError(_) = &event { if let WorkerEvent::TerminalError(_) = &event {
if let Some((join_handle, mut worker_handle)) = if let Some((join_handle, mut worker_handle)) =
state.workers.borrow_mut().remove(&id) cli_state.workers.borrow_mut().remove(&id)
{ {
worker_handle.sender.close_channel(); worker_handle.sender.close_channel();
join_handle.join().expect("Worker thread panicked"); join_handle.join().expect("Worker thread panicked");
} };
} }
serialize_worker_event(event) serialize_worker_event(event)
} }
None => { None => {
// Worker shuts down // Worker shuts down
let mut workers = state.workers.borrow_mut(); let mut workers = cli_state.workers.borrow_mut();
// Try to remove worker from workers table - NOTE: `Worker.terminate()` might have been called // Try to remove worker from workers table - NOTE: `Worker.terminate()` might have been called
// already meaning that we won't find worker in table - in that case ignore. // already meaning that we won't find worker in table - in that case ignore.
if let Some((join_handle, mut worker_handle)) = workers.remove(&id) { if let Some((join_handle, mut worker_handle)) = workers.remove(&id) {
@ -338,7 +350,7 @@ async fn op_host_get_message(
/// Post message to guest worker as host /// Post message to guest worker as host
fn op_host_post_message( fn op_host_post_message(
state: &State, state: &mut OpState,
args: Value, args: Value,
data: &mut [ZeroCopyBuf], data: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -348,7 +360,8 @@ fn op_host_post_message(
let msg = Vec::from(&*data[0]).into_boxed_slice(); let msg = Vec::from(&*data[0]).into_boxed_slice();
debug!("post message to worker {}", id); debug!("post message to worker {}", id);
let workers = state.workers.borrow(); let cli_state = super::cli_state(state);
let workers = cli_state.workers.borrow();
let worker_handle = workers[&id].1.clone(); let worker_handle = workers[&id].1.clone();
worker_handle.post_message(msg)?; worker_handle.post_message(msg)?;
Ok(json!({})) Ok(json!({}))

View file

@ -1,6 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::errors::get_error_class_name;
use crate::file_fetcher::SourceFileFetcher; use crate::file_fetcher::SourceFileFetcher;
use crate::global_state::GlobalState; use crate::global_state::GlobalState;
use crate::global_timer::GlobalTimer; use crate::global_timer::GlobalTimer;
@ -10,17 +9,10 @@ use crate::metrics::Metrics;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::tsc::TargetLib; use crate::tsc::TargetLib;
use crate::web_worker::WebWorkerHandle; use crate::web_worker::WebWorkerHandle;
use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::ModuleLoadId; use deno_core::ModuleLoadId;
use deno_core::ModuleLoader; use deno_core::ModuleLoader;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_core::Op;
use deno_core::OpId;
use deno_core::OpRegistry;
use deno_core::OpRouter;
use deno_core::OpTable;
use deno_core::ResourceTable;
use futures::future::FutureExt; use futures::future::FutureExt;
use futures::Future; use futures::Future;
use rand::rngs::StdRng; use rand::rngs::StdRng;
@ -36,6 +28,7 @@ use std::sync::Arc;
use std::thread::JoinHandle; use std::thread::JoinHandle;
use std::time::Instant; use std::time::Instant;
// TODO(ry) Rename to CliState to avoid confusion with other states.
#[cfg_attr(feature = "cargo-clippy", allow(stutter))] #[cfg_attr(feature = "cargo-clippy", allow(stutter))]
pub struct State { pub struct State {
pub global_state: Arc<GlobalState>, pub global_state: Arc<GlobalState>,
@ -54,8 +47,6 @@ pub struct State {
pub is_main: bool, pub is_main: bool,
pub is_internal: bool, pub is_internal: bool,
pub http_client: RefCell<reqwest::Client>, pub http_client: RefCell<reqwest::Client>,
pub resource_table: RefCell<ResourceTable>,
pub op_table: RefCell<OpTable<Self>>,
} }
impl State { impl State {
@ -202,8 +193,6 @@ impl State {
is_main: true, is_main: true,
is_internal, is_internal,
http_client: create_http_client(fl.ca_file.as_deref())?.into(), http_client: create_http_client(fl.ca_file.as_deref())?.into(),
resource_table: Default::default(),
op_table: Default::default(),
}; };
Ok(Rc::new(state)) Ok(Rc::new(state))
} }
@ -232,8 +221,6 @@ impl State {
is_main: false, is_main: false,
is_internal: false, is_internal: false,
http_client: create_http_client(fl.ca_file.as_deref())?.into(), http_client: create_http_client(fl.ca_file.as_deref())?.into(),
resource_table: Default::default(),
op_table: Default::default(),
}; };
Ok(Rc::new(state)) Ok(Rc::new(state))
} }
@ -331,78 +318,3 @@ impl State {
.unwrap() .unwrap()
} }
} }
impl OpRouter for State {
fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op {
// TODOs:
// * The 'bytes' metrics seem pretty useless, especially now that the
// distinction between 'control' and 'data' buffers has become blurry.
// * Tracking completion of async ops currently makes us put the boxed
// future into _another_ box. Keeping some counters may not be expensive
// in itself, but adding a heap allocation for every metric seems bad.
let mut buf_len_iter = bufs.iter().map(|buf| buf.len());
let bytes_sent_control = buf_len_iter.next().unwrap_or(0);
let bytes_sent_data = buf_len_iter.sum();
let op_fn = self
.op_table
.borrow()
.get_index(op_id)
.map(|(_, op_fn)| op_fn.clone())
.unwrap();
let self_ = self.clone();
let op = (op_fn)(self_, bufs);
let self_ = self.clone();
let mut metrics = self_.metrics.borrow_mut();
match op {
Op::Sync(buf) => {
metrics.op_sync(bytes_sent_control, bytes_sent_data, buf.len());
Op::Sync(buf)
}
Op::Async(fut) => {
metrics.op_dispatched_async(bytes_sent_control, bytes_sent_data);
let fut = fut
.inspect(move |buf| {
self.metrics.borrow_mut().op_completed_async(buf.len());
})
.boxed_local();
Op::Async(fut)
}
Op::AsyncUnref(fut) => {
metrics.op_dispatched_async_unref(bytes_sent_control, bytes_sent_data);
let fut = fut
.inspect(move |buf| {
self
.metrics
.borrow_mut()
.op_completed_async_unref(buf.len());
})
.boxed_local();
Op::AsyncUnref(fut)
}
other => other,
}
}
}
impl OpRegistry for State {
fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId> {
self.op_table.borrow().get_op_catalog()
}
fn register_op<F>(&self, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<Self>, BufVec) -> Op + 'static,
{
let mut op_table = self.op_table.borrow_mut();
let (op_id, prev) = op_table.insert_full(name.to_owned(), Rc::new(op_fn));
assert!(prev.is_none());
op_id
}
fn get_error_class_name(&self, err: &ErrBox) -> &'static str {
get_error_class_name(err)
}
}

View file

@ -139,15 +139,12 @@ impl CompilerWorker {
startup_data: StartupData, startup_data: StartupData,
state: &Rc<State>, state: &Rc<State>,
) -> Self { ) -> Self {
let worker = Worker::new(name, startup_data, state); let mut worker = Worker::new(name, startup_data, state);
let response = Arc::new(Mutex::new(None)); let response = Arc::new(Mutex::new(None));
{ ops::runtime::init(&mut worker);
ops::runtime::init(&state); ops::errors::init(&mut worker);
ops::errors::init(&state); ops::timers::init(&mut worker);
ops::timers::init(&state); ops::compiler::init(&mut worker, response.clone());
ops::compiler::init(&state, response.clone());
}
Self { worker, response } Self { worker, response }
} }

View file

@ -102,7 +102,7 @@ impl WebWorker {
terminate_tx, terminate_tx,
}; };
let web_worker = Self { let mut web_worker = Self {
worker, worker,
event_loop_idle: false, event_loop_idle: false,
terminate_rx, terminate_rx,
@ -110,37 +110,33 @@ impl WebWorker {
has_deno_namespace, has_deno_namespace,
}; };
let handle = web_worker.thread_safe_handle();
{ {
ops::runtime::init(&state); ops::runtime::init(&mut web_worker.worker);
ops::web_worker::init( let sender = web_worker.worker.internal_channels.sender.clone();
&state, let handle = web_worker.thread_safe_handle();
&web_worker.worker.internal_channels.sender, ops::web_worker::init(&mut web_worker.worker, sender, handle);
handle, ops::worker_host::init(&mut web_worker.worker);
); ops::idna::init(&mut web_worker.worker);
ops::worker_host::init(&state); ops::io::init(&mut web_worker.worker);
ops::idna::init(&state); ops::resources::init(&mut web_worker.worker);
ops::io::init(&state); ops::errors::init(&mut web_worker.worker);
ops::resources::init(&state); ops::timers::init(&mut web_worker.worker);
ops::errors::init(&state); ops::fetch::init(&mut web_worker.worker);
ops::timers::init(&state); ops::websocket::init(&mut web_worker.worker);
ops::fetch::init(&state);
ops::websocket::init(&state);
if has_deno_namespace { if has_deno_namespace {
ops::runtime_compiler::init(&state); ops::runtime_compiler::init(&mut web_worker.worker);
ops::fs::init(&state); ops::fs::init(&mut web_worker.worker);
ops::fs_events::init(&state); ops::fs_events::init(&mut web_worker.worker);
ops::plugin::init(&state); ops::plugin::init(&mut web_worker.worker);
ops::net::init(&state); ops::net::init(&mut web_worker.worker);
ops::tls::init(&state); ops::tls::init(&mut web_worker.worker);
ops::os::init(&state); ops::os::init(&mut web_worker.worker);
ops::permissions::init(&state); ops::permissions::init(&mut web_worker.worker);
ops::process::init(&state); ops::process::init(&mut web_worker.worker);
ops::random::init(&state); ops::random::init(&mut web_worker.worker);
ops::signal::init(&state); ops::signal::init(&mut web_worker.worker);
ops::tty::init(&state); ops::tty::init(&mut web_worker.worker);
} }
} }

View file

@ -91,7 +91,7 @@ fn create_channels() -> (WorkerChannelsInternal, WorkerHandle) {
/// - `WebWorker` /// - `WebWorker`
pub struct Worker { pub struct Worker {
pub name: String, pub name: String,
pub isolate: deno_core::JsRuntime, pub isolate: JsRuntime,
pub inspector: Option<Box<DenoInspector>>, pub inspector: Option<Box<DenoInspector>>,
pub state: Rc<State>, pub state: Rc<State>,
pub waker: AtomicWaker, pub waker: AtomicWaker,
@ -105,22 +105,22 @@ impl Worker {
startup_data: StartupData, startup_data: StartupData,
state: &Rc<State>, state: &Rc<State>,
) -> Self { ) -> Self {
let mut isolate = deno_core::JsRuntime::new_with_loader( let mut isolate =
state.clone(), JsRuntime::new_with_loader(state.clone(), startup_data, false);
state.clone(),
startup_data,
false,
);
{ {
let global_state = state.global_state.clone(); let global_state = state.global_state.clone();
let core_state_rc = JsRuntime::state(&isolate); let js_runtime_state = JsRuntime::state(&isolate);
let mut core_state = core_state_rc.borrow_mut(); let mut js_runtime_state = js_runtime_state.borrow_mut();
core_state.set_js_error_create_fn(move |core_js_error| { js_runtime_state.set_js_error_create_fn(move |core_js_error| {
JsError::create(core_js_error, &global_state.ts_compiler) JsError::create(core_js_error, &global_state.ts_compiler)
}); });
} }
{
let op_state = isolate.op_state();
let mut op_state = op_state.borrow_mut();
op_state.get_error_class_fn = &crate::errors::get_error_class_name;
op_state.put(state.clone());
}
let inspector = { let inspector = {
let global_state = &state.global_state; let global_state = &state.global_state;
global_state global_state
@ -235,7 +235,7 @@ impl Future for Worker {
} }
impl Deref for Worker { impl Deref for Worker {
type Target = deno_core::JsRuntime; type Target = JsRuntime;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.isolate &self.isolate
} }
@ -258,30 +258,30 @@ pub struct MainWorker(Worker);
impl MainWorker { impl MainWorker {
// TODO(ry) combine MainWorker::new and MainWorker::create. // TODO(ry) combine MainWorker::new and MainWorker::create.
fn new(name: String, startup_data: StartupData, state: &Rc<State>) -> Self { fn new(name: String, startup_data: StartupData, state: &Rc<State>) -> Self {
let worker = Worker::new(name, startup_data, state); let mut worker = Worker::new(name, startup_data, state);
{ {
ops::runtime::init(&state); ops::runtime::init(&mut worker);
ops::runtime_compiler::init(&state); ops::runtime_compiler::init(&mut worker);
ops::errors::init(&state); ops::errors::init(&mut worker);
ops::fetch::init(&state); ops::fetch::init(&mut worker);
ops::websocket::init(&state); ops::websocket::init(&mut worker);
ops::fs::init(&state); ops::fs::init(&mut worker);
ops::fs_events::init(&state); ops::fs_events::init(&mut worker);
ops::idna::init(&state); ops::idna::init(&mut worker);
ops::io::init(&state); ops::io::init(&mut worker);
ops::plugin::init(&state); ops::plugin::init(&mut worker);
ops::net::init(&state); ops::net::init(&mut worker);
ops::tls::init(&state); ops::tls::init(&mut worker);
ops::os::init(&state); ops::os::init(&mut worker);
ops::permissions::init(&state); ops::permissions::init(&mut worker);
ops::process::init(&state); ops::process::init(&mut worker);
ops::random::init(&state); ops::random::init(&mut worker);
ops::repl::init(&state); ops::repl::init(&mut worker);
ops::resources::init(&state); ops::resources::init(&mut worker);
ops::signal::init(&state); ops::signal::init(&mut worker);
ops::timers::init(&state); ops::timers::init(&mut worker);
ops::tty::init(&state); ops::tty::init(&mut worker);
ops::worker_host::init(&state); ops::worker_host::init(&mut worker);
} }
Self(worker) Self(worker)
} }
@ -303,7 +303,9 @@ impl MainWorker {
&state, &state,
); );
{ {
let mut t = state.resource_table.borrow_mut(); let op_state = worker.op_state();
let mut op_state = op_state.borrow_mut();
let t = &mut op_state.resource_table;
let (stdin, stdout, stderr) = get_stdio(); let (stdin, stdout, stderr) = get_stdio();
if let Some(stream) = stdin { if let Some(stream) = stdin {
t.add("stdin", Box::new(stream)); t.add("stdin", Box::new(stream));

View file

@ -1,91 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::BufVec;
use crate::Op;
use crate::OpId;
use crate::OpRegistry;
use crate::OpRouter;
use crate::OpTable;
use crate::ResourceTable;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
/// A minimal state struct for use by tests, examples etc. It contains
/// an OpTable and ResourceTable, and implements the relevant traits
/// for working with ops in the most straightforward way possible.
#[derive(Default)]
pub struct BasicState {
pub op_table: RefCell<OpTable<Self>>,
pub resource_table: RefCell<ResourceTable>,
}
impl BasicState {
pub fn new() -> Rc<Self> {
Default::default()
}
}
impl OpRegistry for BasicState {
fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId> {
self.op_table.borrow().get_op_catalog()
}
fn register_op<F>(&self, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<Self>, BufVec) -> Op + 'static,
{
let mut op_table = self.op_table.borrow_mut();
let (op_id, prev) = op_table.insert_full(name.to_owned(), Rc::new(op_fn));
assert!(prev.is_none());
op_id
}
}
impl OpRouter for BasicState {
fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op {
let op_fn = self
.op_table
.borrow()
.get_index(op_id)
.map(|(_, op_fn)| op_fn.clone())
.unwrap();
(op_fn)(self, bufs)
}
}
#[test]
fn test_basic_state_ops() {
let state = BasicState::new();
let foo_id = state.register_op("foo", |_, _| Op::Sync(b"oof!"[..].into()));
assert_eq!(foo_id, 1);
let bar_id = state.register_op("bar", |_, _| Op::Sync(b"rab!"[..].into()));
assert_eq!(bar_id, 2);
let state_ = state.clone();
let foo_res = state_.route_op(foo_id, Default::default());
assert!(matches!(foo_res, Op::Sync(buf) if &*buf == b"oof!"));
let state_ = state.clone();
let bar_res = state_.route_op(bar_id, Default::default());
assert!(matches!(bar_res, Op::Sync(buf) if &*buf == b"rab!"));
let catalog_res = state.route_op(0, Default::default());
let mut catalog_entries = match catalog_res {
Op::Sync(buf) => serde_json::from_slice::<HashMap<String, OpId>>(&buf)
.map(|map| map.into_iter().collect::<Vec<_>>())
.unwrap(),
_ => panic!("unexpected `Op` variant"),
};
catalog_entries.sort_by(|(_, id1), (_, id2)| id1.partial_cmp(id2).unwrap());
assert_eq!(
catalog_entries,
vec![
("ops".to_owned(), 0),
("foo".to_owned(), 1),
("bar".to_owned(), 2)
]
)
}

View file

@ -6,6 +6,7 @@ use crate::JsRuntime;
use crate::JsRuntimeState; use crate::JsRuntimeState;
use crate::Op; use crate::Op;
use crate::OpId; use crate::OpId;
use crate::OpTable;
use crate::ZeroCopyBuf; use crate::ZeroCopyBuf;
use futures::future::FutureExt; use futures::future::FutureExt;
use rusty_v8 as v8; use rusty_v8 as v8;
@ -426,8 +427,7 @@ fn send<'s>(
} }
}; };
let op_router = state.op_router.clone(); let op = OpTable::route_op(op_id, state.op_state.clone(), bufs);
let op = op_router.route_op(op_id, bufs);
assert_eq!(state.shared.size(), 0); assert_eq!(state.shared.size(), 0);
match op { match op {
Op::Sync(buf) if !buf.is_empty() => { Op::Sync(buf) if !buf.is_empty() => {

View file

@ -2,11 +2,10 @@
extern crate log; extern crate log;
use deno_core::js_check; use deno_core::js_check;
use deno_core::BasicState;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::JsRuntime; use deno_core::JsRuntime;
use deno_core::Op; use deno_core::Op;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::Script; use deno_core::Script;
use deno_core::StartupData; use deno_core::StartupData;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
@ -14,6 +13,7 @@ use futures::future::poll_fn;
use futures::future::FutureExt; use futures::future::FutureExt;
use futures::future::TryFuture; use futures::future::TryFuture;
use futures::future::TryFutureExt; use futures::future::TryFutureExt;
use std::cell::RefCell;
use std::convert::TryInto; use std::convert::TryInto;
use std::env; use std::env;
use std::fmt::Debug; use std::fmt::Debug;
@ -78,23 +78,22 @@ impl From<Record> for RecordBuf {
} }
fn create_isolate() -> JsRuntime { fn create_isolate() -> JsRuntime {
let state = BasicState::new();
register_op_bin_sync(&state, "listen", op_listen);
register_op_bin_sync(&state, "close", op_close);
register_op_bin_async(&state, "accept", op_accept);
register_op_bin_async(&state, "read", op_read);
register_op_bin_async(&state, "write", op_write);
let startup_data = StartupData::Script(Script { let startup_data = StartupData::Script(Script {
source: include_str!("http_bench_bin_ops.js"), source: include_str!("http_bench_bin_ops.js"),
filename: "http_bench_bin_ops.js", filename: "http_bench_bin_ops.js",
}); });
JsRuntime::new(state, startup_data, false) let mut isolate = JsRuntime::new(startup_data, false);
register_op_bin_sync(&mut isolate, "listen", op_listen);
register_op_bin_sync(&mut isolate, "close", op_close);
register_op_bin_async(&mut isolate, "accept", op_accept);
register_op_bin_async(&mut isolate, "read", op_read);
register_op_bin_async(&mut isolate, "write", op_write);
isolate
} }
fn op_listen( fn op_listen(
state: &BasicState, state: &mut OpState,
_rid: u32, _rid: u32,
_bufs: &mut [ZeroCopyBuf], _bufs: &mut [ZeroCopyBuf],
) -> Result<u32, Error> { ) -> Result<u32, Error> {
@ -102,36 +101,33 @@ fn op_listen(
let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap(); let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap();
let std_listener = std::net::TcpListener::bind(&addr)?; let std_listener = std::net::TcpListener::bind(&addr)?;
let listener = TcpListener::from_std(std_listener)?; let listener = TcpListener::from_std(std_listener)?;
let rid = state let rid = state.resource_table.add("tcpListener", Box::new(listener));
.resource_table
.borrow_mut()
.add("tcpListener", Box::new(listener));
Ok(rid) Ok(rid)
} }
fn op_close( fn op_close(
state: &BasicState, state: &mut OpState,
rid: u32, rid: u32,
_bufs: &mut [ZeroCopyBuf], _bufs: &mut [ZeroCopyBuf],
) -> Result<u32, Error> { ) -> Result<u32, Error> {
debug!("close rid={}", rid); debug!("close rid={}", rid);
state state
.resource_table .resource_table
.borrow_mut()
.close(rid) .close(rid)
.map(|_| 0) .map(|_| 0)
.ok_or_else(bad_resource_id) .ok_or_else(bad_resource_id)
} }
fn op_accept( async fn op_accept(
state: Rc<BasicState>, state: Rc<RefCell<OpState>>,
rid: u32, rid: u32,
_bufs: BufVec, _bufs: BufVec,
) -> impl TryFuture<Ok = u32, Error = Error> { ) -> Result<u32, Error> {
debug!("accept rid={}", rid); debug!("accept rid={}", rid);
poll_fn(move |cx| { poll_fn(move |cx| {
let resource_table = &mut state.resource_table.borrow_mut(); let resource_table = &mut state.borrow_mut().resource_table;
let listener = resource_table let listener = resource_table
.get_mut::<TcpListener>(rid) .get_mut::<TcpListener>(rid)
.ok_or_else(bad_resource_id)?; .ok_or_else(bad_resource_id)?;
@ -139,10 +135,11 @@ fn op_accept(
resource_table.add("tcpStream", Box::new(stream)) resource_table.add("tcpStream", Box::new(stream))
}) })
}) })
.await
} }
fn op_read( fn op_read(
state: Rc<BasicState>, state: Rc<RefCell<OpState>>,
rid: u32, rid: u32,
bufs: BufVec, bufs: BufVec,
) -> impl TryFuture<Ok = usize, Error = Error> { ) -> impl TryFuture<Ok = usize, Error = Error> {
@ -152,7 +149,8 @@ fn op_read(
debug!("read rid={}", rid); debug!("read rid={}", rid);
poll_fn(move |cx| { poll_fn(move |cx| {
let resource_table = &mut state.resource_table.borrow_mut(); let resource_table = &mut state.borrow_mut().resource_table;
let stream = resource_table let stream = resource_table
.get_mut::<TcpStream>(rid) .get_mut::<TcpStream>(rid)
.ok_or_else(bad_resource_id)?; .ok_or_else(bad_resource_id)?;
@ -161,7 +159,7 @@ fn op_read(
} }
fn op_write( fn op_write(
state: Rc<BasicState>, state: Rc<RefCell<OpState>>,
rid: u32, rid: u32,
bufs: BufVec, bufs: BufVec,
) -> impl TryFuture<Ok = usize, Error = Error> { ) -> impl TryFuture<Ok = usize, Error = Error> {
@ -170,7 +168,8 @@ fn op_write(
debug!("write rid={}", rid); debug!("write rid={}", rid);
poll_fn(move |cx| { poll_fn(move |cx| {
let resource_table = &mut state.resource_table.borrow_mut(); let resource_table = &mut state.borrow_mut().resource_table;
let stream = resource_table let stream = resource_table
.get_mut::<TcpStream>(rid) .get_mut::<TcpStream>(rid)
.ok_or_else(bad_resource_id)?; .ok_or_else(bad_resource_id)?;
@ -178,35 +177,42 @@ fn op_write(
}) })
} }
fn register_op_bin_sync<F>(state: &BasicState, name: &'static str, op_fn: F) fn register_op_bin_sync<F>(
where isolate: &mut JsRuntime,
F: Fn(&BasicState, u32, &mut [ZeroCopyBuf]) -> Result<u32, Error> + 'static, name: &'static str,
op_fn: F,
) where
F: Fn(&mut OpState, u32, &mut [ZeroCopyBuf]) -> Result<u32, Error> + 'static,
{ {
let base_op_fn = move |state: Rc<BasicState>, mut bufs: BufVec| -> Op { let base_op_fn = move |state: Rc<RefCell<OpState>>, mut bufs: BufVec| -> Op {
let record = Record::from(bufs[0].as_ref()); let record = Record::from(bufs[0].as_ref());
let is_sync = record.promise_id == 0; let is_sync = record.promise_id == 0;
assert!(is_sync); assert!(is_sync);
let zero_copy_bufs = &mut bufs[1..]; let zero_copy_bufs = &mut bufs[1..];
let result: i32 = match op_fn(&state, record.rid, zero_copy_bufs) { let result: i32 =
Ok(r) => r as i32, match op_fn(&mut state.borrow_mut(), record.rid, zero_copy_bufs) {
Err(_) => -1, Ok(r) => r as i32,
}; Err(_) => -1,
};
let buf = RecordBuf::from(Record { result, ..record })[..].into(); let buf = RecordBuf::from(Record { result, ..record })[..].into();
Op::Sync(buf) Op::Sync(buf)
}; };
state.register_op(name, base_op_fn); isolate.register_op(name, base_op_fn);
} }
fn register_op_bin_async<F, R>(state: &BasicState, name: &'static str, op_fn: F) fn register_op_bin_async<F, R>(
where isolate: &mut JsRuntime,
F: Fn(Rc<BasicState>, u32, BufVec) -> R + Copy + 'static, name: &'static str,
op_fn: F,
) where
F: Fn(Rc<RefCell<OpState>>, u32, BufVec) -> R + Copy + 'static,
R: TryFuture, R: TryFuture,
R::Ok: TryInto<i32>, R::Ok: TryInto<i32>,
<R::Ok as TryInto<i32>>::Error: Debug, <R::Ok as TryInto<i32>>::Error: Debug,
{ {
let base_op_fn = move |state: Rc<BasicState>, bufs: BufVec| -> Op { let base_op_fn = move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
let mut bufs_iter = bufs.into_iter(); let mut bufs_iter = bufs.into_iter();
let record_buf = bufs_iter.next().unwrap(); let record_buf = bufs_iter.next().unwrap();
let zero_copy_bufs = bufs_iter.collect::<BufVec>(); let zero_copy_bufs = bufs_iter.collect::<BufVec>();
@ -227,7 +233,7 @@ where
Op::Async(fut.boxed_local()) Op::Async(fut.boxed_local())
}; };
state.register_op(name, base_op_fn); isolate.register_op(name, base_op_fn);
} }
fn bad_resource_id() -> Error { fn bad_resource_id() -> Error {

View file

@ -2,17 +2,17 @@
extern crate log; extern crate log;
use deno_core::js_check; use deno_core::js_check;
use deno_core::BasicState;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::ErrBox; use deno_core::ErrBox;
use deno_core::JsRuntime; use deno_core::JsRuntime;
use deno_core::OpRegistry; use deno_core::OpState;
use deno_core::Script; use deno_core::Script;
use deno_core::StartupData; use deno_core::StartupData;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use futures::future::poll_fn; use futures::future::poll_fn;
use futures::future::Future; use futures::future::Future;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::convert::TryInto; use std::convert::TryInto;
use std::env; use std::env;
use std::net::SocketAddr; use std::net::SocketAddr;
@ -42,23 +42,21 @@ impl log::Log for Logger {
} }
fn create_isolate() -> JsRuntime { fn create_isolate() -> JsRuntime {
let state = BasicState::new();
state.register_op_json_sync("listen", op_listen);
state.register_op_json_sync("close", op_close);
state.register_op_json_async("accept", op_accept);
state.register_op_json_async("read", op_read);
state.register_op_json_async("write", op_write);
let startup_data = StartupData::Script(Script { let startup_data = StartupData::Script(Script {
source: include_str!("http_bench_json_ops.js"), source: include_str!("http_bench_json_ops.js"),
filename: "http_bench_json_ops.js", filename: "http_bench_json_ops.js",
}); });
let mut runtime = JsRuntime::new(startup_data, false);
JsRuntime::new(state, startup_data, false) runtime.register_op("listen", deno_core::json_op_sync(op_listen));
runtime.register_op("close", deno_core::json_op_sync(op_close));
runtime.register_op("accept", deno_core::json_op_async(op_accept));
runtime.register_op("read", deno_core::json_op_async(op_read));
runtime.register_op("write", deno_core::json_op_async(op_write));
runtime
} }
fn op_listen( fn op_listen(
state: &BasicState, state: &mut OpState,
_args: Value, _args: Value,
_bufs: &mut [ZeroCopyBuf], _bufs: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -66,15 +64,12 @@ fn op_listen(
let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap(); let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap();
let std_listener = std::net::TcpListener::bind(&addr)?; let std_listener = std::net::TcpListener::bind(&addr)?;
let listener = TcpListener::from_std(std_listener)?; let listener = TcpListener::from_std(std_listener)?;
let rid = state let rid = state.resource_table.add("tcpListener", Box::new(listener));
.resource_table
.borrow_mut()
.add("tcpListener", Box::new(listener));
Ok(serde_json::json!({ "rid": rid })) Ok(serde_json::json!({ "rid": rid }))
} }
fn op_close( fn op_close(
state: &BasicState, state: &mut OpState,
args: Value, args: Value,
_buf: &mut [ZeroCopyBuf], _buf: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> { ) -> Result<Value, ErrBox> {
@ -86,17 +81,15 @@ fn op_close(
.try_into() .try_into()
.unwrap(); .unwrap();
debug!("close rid={}", rid); debug!("close rid={}", rid);
state state
.resource_table .resource_table
.borrow_mut()
.close(rid) .close(rid)
.map(|_| serde_json::json!(())) .map(|_| serde_json::json!(()))
.ok_or_else(ErrBox::bad_resource_id) .ok_or_else(ErrBox::bad_resource_id)
} }
fn op_accept( fn op_accept(
state: Rc<BasicState>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
_bufs: BufVec, _bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> { ) -> impl Future<Output = Result<Value, ErrBox>> {
@ -110,7 +103,8 @@ fn op_accept(
debug!("accept rid={}", rid); debug!("accept rid={}", rid);
poll_fn(move |cx| { poll_fn(move |cx| {
let resource_table = &mut state.resource_table.borrow_mut(); let resource_table = &mut state.borrow_mut().resource_table;
let listener = resource_table let listener = resource_table
.get_mut::<TcpListener>(rid) .get_mut::<TcpListener>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
@ -122,7 +116,7 @@ fn op_accept(
} }
fn op_read( fn op_read(
state: Rc<BasicState>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
mut bufs: BufVec, mut bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> { ) -> impl Future<Output = Result<Value, ErrBox>> {
@ -138,7 +132,8 @@ fn op_read(
debug!("read rid={}", rid); debug!("read rid={}", rid);
poll_fn(move |cx| -> Poll<Result<Value, ErrBox>> { poll_fn(move |cx| -> Poll<Result<Value, ErrBox>> {
let resource_table = &mut state.resource_table.borrow_mut(); let resource_table = &mut state.borrow_mut().resource_table;
let stream = resource_table let stream = resource_table
.get_mut::<TcpStream>(rid) .get_mut::<TcpStream>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;
@ -149,7 +144,7 @@ fn op_read(
} }
fn op_write( fn op_write(
state: Rc<BasicState>, state: Rc<RefCell<OpState>>,
args: Value, args: Value,
bufs: BufVec, bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> { ) -> impl Future<Output = Result<Value, ErrBox>> {
@ -165,7 +160,8 @@ fn op_write(
debug!("write rid={}", rid); debug!("write rid={}", rid);
poll_fn(move |cx| { poll_fn(move |cx| {
let resource_table = &mut state.resource_table.borrow_mut(); let resource_table = &mut state.borrow_mut().resource_table;
let stream = resource_table let stream = resource_table
.get_mut::<TcpStream>(rid) .get_mut::<TcpStream>(rid)
.ok_or_else(ErrBox::bad_resource_id)?; .ok_or_else(ErrBox::bad_resource_id)?;

167
core/gotham_state.rs Normal file
View file

@ -0,0 +1,167 @@
// Forked from Gotham:
// https://github.com/gotham-rs/gotham/blob/bcbbf8923789e341b7a0e62c59909428ca4e22e2/gotham/src/state/mod.rs
// Copyright 2017 Gotham Project Developers. MIT license.
use std::any::Any;
use std::any::TypeId;
use std::collections::HashMap;
#[derive(Default)]
pub struct GothamState {
data: HashMap<TypeId, Box<dyn Any>>,
}
impl GothamState {
/// Puts a value into the `GothamState` storage. One value of each type is retained.
/// Successive calls to `put` will overwrite the existing value of the same
/// type.
pub fn put<T: 'static>(&mut self, t: T) {
let type_id = TypeId::of::<T>();
trace!(" inserting record to state for type_id `{:?}`", type_id);
self.data.insert(type_id, Box::new(t));
}
/// Determines if the current value exists in `GothamState` storage.
pub fn has<T: 'static>(&self) -> bool {
let type_id = TypeId::of::<T>();
self.data.get(&type_id).is_some()
}
/// Tries to borrow a value from the `GothamState` storage.
pub fn try_borrow<T: 'static>(&self) -> Option<&T> {
let type_id = TypeId::of::<T>();
trace!(" borrowing state data for type_id `{:?}`", type_id);
self.data.get(&type_id).and_then(|b| b.downcast_ref())
}
/// Borrows a value from the `GothamState` storage.
pub fn borrow<T: 'static>(&self) -> &T {
self
.try_borrow()
.expect("required type is not present in GothamState container")
}
/// Tries to mutably borrow a value from the `GothamState` storage.
pub fn try_borrow_mut<T: 'static>(&mut self) -> Option<&mut T> {
let type_id = TypeId::of::<T>();
trace!(" mutably borrowing state data for type_id `{:?}`", type_id);
self.data.get_mut(&type_id).and_then(|b| b.downcast_mut())
}
/// Mutably borrows a value from the `GothamState` storage.
pub fn borrow_mut<T: 'static>(&mut self) -> &mut T {
self
.try_borrow_mut()
.expect("required type is not present in GothamState container")
}
/// Tries to move a value out of the `GothamState` storage and return ownership.
pub fn try_take<T: 'static>(&mut self) -> Option<T> {
let type_id = TypeId::of::<T>();
trace!(
" taking ownership from state data for type_id `{:?}`",
type_id
);
self
.data
.remove(&type_id)
.and_then(|b| b.downcast().ok())
.map(|b| *b)
}
/// Moves a value out of the `GothamState` storage and returns ownership.
///
/// # Panics
///
/// If a value of type `T` is not present in `GothamState`.
pub fn take<T: 'static>(&mut self) -> T {
self
.try_take()
.expect("required type is not present in GothamState container")
}
}
#[cfg(test)]
mod tests {
use super::GothamState;
struct MyStruct {
value: i32,
}
struct AnotherStruct {
value: &'static str,
}
#[test]
fn put_borrow1() {
let mut state = GothamState::default();
state.put(MyStruct { value: 1 });
assert_eq!(state.borrow::<MyStruct>().value, 1);
}
#[test]
fn put_borrow2() {
let mut state = GothamState::default();
assert!(!state.has::<AnotherStruct>());
state.put(AnotherStruct { value: "a string" });
assert!(state.has::<AnotherStruct>());
assert!(!state.has::<MyStruct>());
state.put(MyStruct { value: 100 });
assert!(state.has::<MyStruct>());
assert_eq!(state.borrow::<MyStruct>().value, 100);
assert_eq!(state.borrow::<AnotherStruct>().value, "a string");
}
#[test]
fn try_borrow() {
let mut state = GothamState::default();
state.put(MyStruct { value: 100 });
assert!(state.try_borrow::<MyStruct>().is_some());
assert_eq!(state.try_borrow::<MyStruct>().unwrap().value, 100);
assert!(state.try_borrow::<AnotherStruct>().is_none());
}
#[test]
fn try_borrow_mut() {
let mut state = GothamState::default();
state.put(MyStruct { value: 100 });
if let Some(a) = state.try_borrow_mut::<MyStruct>() {
a.value += 10;
}
assert_eq!(state.borrow::<MyStruct>().value, 110);
}
#[test]
fn borrow_mut() {
let mut state = GothamState::default();
state.put(MyStruct { value: 100 });
{
let a = state.borrow_mut::<MyStruct>();
a.value += 10;
}
assert_eq!(state.borrow::<MyStruct>().value, 110);
assert!(state.try_borrow_mut::<AnotherStruct>().is_none());
}
#[test]
fn try_take() {
let mut state = GothamState::default();
state.put(MyStruct { value: 100 });
assert_eq!(state.try_take::<MyStruct>().unwrap().value, 100);
assert!(state.try_take::<MyStruct>().is_none());
assert!(state.try_borrow_mut::<MyStruct>().is_none());
assert!(state.try_borrow::<MyStruct>().is_none());
assert!(state.try_take::<AnotherStruct>().is_none());
}
#[test]
fn take() {
let mut state = GothamState::default();
state.put(MyStruct { value: 110 });
assert_eq!(state.take::<MyStruct>().value, 110);
assert!(state.try_take::<MyStruct>().is_none());
assert!(state.try_borrow_mut::<MyStruct>().is_none());
assert!(state.try_borrow::<MyStruct>().is_none());
}
}

View file

@ -8,10 +8,10 @@ extern crate lazy_static;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
mod basic_state;
mod bindings; mod bindings;
mod errors; mod errors;
mod flags; mod flags;
mod gotham_state;
mod module_specifier; mod module_specifier;
mod modules; mod modules;
mod normalize_path; mod normalize_path;
@ -24,7 +24,6 @@ mod zero_copy_buf;
pub use rusty_v8 as v8; pub use rusty_v8 as v8;
pub use crate::basic_state::BasicState;
pub use crate::errors::AnyError; pub use crate::errors::AnyError;
pub use crate::errors::ErrBox; pub use crate::errors::ErrBox;
pub use crate::errors::JsError; pub use crate::errors::JsError;
@ -38,12 +37,13 @@ pub use crate::modules::ModuleSource;
pub use crate::modules::ModuleSourceFuture; pub use crate::modules::ModuleSourceFuture;
pub use crate::modules::RecursiveModuleLoad; pub use crate::modules::RecursiveModuleLoad;
pub use crate::normalize_path::normalize_path; pub use crate::normalize_path::normalize_path;
pub use crate::ops::json_op_async;
pub use crate::ops::json_op_sync;
pub use crate::ops::Op; pub use crate::ops::Op;
pub use crate::ops::OpAsyncFuture; pub use crate::ops::OpAsyncFuture;
pub use crate::ops::OpFn; pub use crate::ops::OpFn;
pub use crate::ops::OpId; pub use crate::ops::OpId;
pub use crate::ops::OpRegistry; pub use crate::ops::OpState;
pub use crate::ops::OpRouter;
pub use crate::ops::OpTable; pub use crate::ops::OpTable;
pub use crate::resources::ResourceTable; pub use crate::resources::ResourceTable;
pub use crate::runtime::js_check; pub use crate::runtime::js_check;

View file

@ -441,7 +441,6 @@ impl Modules {
mod tests { mod tests {
use super::*; use super::*;
use crate::js_check; use crate::js_check;
use crate::BasicState;
use crate::JsRuntime; use crate::JsRuntime;
use crate::StartupData; use crate::StartupData;
use futures::future::FutureExt; use futures::future::FutureExt;
@ -620,12 +619,8 @@ mod tests {
fn test_recursive_load() { fn test_recursive_load() {
let loader = MockLoader::new(); let loader = MockLoader::new();
let loads = loader.loads.clone(); let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
let spec = ModuleSpecifier::resolve_url("file:///a.js").unwrap(); let spec = ModuleSpecifier::resolve_url("file:///a.js").unwrap();
let a_id_fut = runtime.load_module(&spec, None); let a_id_fut = runtime.load_module(&spec, None);
let a_id = futures::executor::block_on(a_id_fut).expect("Failed to load"); let a_id = futures::executor::block_on(a_id_fut).expect("Failed to load");
@ -687,12 +682,8 @@ mod tests {
fn test_circular_load() { fn test_circular_load() {
let loader = MockLoader::new(); let loader = MockLoader::new();
let loads = loader.loads.clone(); let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
let fut = async move { let fut = async move {
let spec = ModuleSpecifier::resolve_url("file:///circular1.js").unwrap(); let spec = ModuleSpecifier::resolve_url("file:///circular1.js").unwrap();
@ -765,12 +756,8 @@ mod tests {
fn test_redirect_load() { fn test_redirect_load() {
let loader = MockLoader::new(); let loader = MockLoader::new();
let loads = loader.loads.clone(); let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
let fut = async move { let fut = async move {
let spec = ModuleSpecifier::resolve_url("file:///redirect1.js").unwrap(); let spec = ModuleSpecifier::resolve_url("file:///redirect1.js").unwrap();
@ -834,12 +821,8 @@ mod tests {
run_in_task(|mut cx| { run_in_task(|mut cx| {
let loader = MockLoader::new(); let loader = MockLoader::new();
let loads = loader.loads.clone(); let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
let spec = ModuleSpecifier::resolve_url("file:///main.js").unwrap(); let spec = ModuleSpecifier::resolve_url("file:///main.js").unwrap();
let mut recursive_load = runtime.load_module(&spec, None).boxed_local(); let mut recursive_load = runtime.load_module(&spec, None).boxed_local();
@ -884,12 +867,8 @@ mod tests {
fn loader_disappears_after_error() { fn loader_disappears_after_error() {
run_in_task(|mut cx| { run_in_task(|mut cx| {
let loader = MockLoader::new(); let loader = MockLoader::new();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
let spec = ModuleSpecifier::resolve_url("file:///bad_import.js").unwrap(); let spec = ModuleSpecifier::resolve_url("file:///bad_import.js").unwrap();
let mut load_fut = runtime.load_module(&spec, None).boxed_local(); let mut load_fut = runtime.load_module(&spec, None).boxed_local();
let result = load_fut.poll_unpin(&mut cx); let result = load_fut.poll_unpin(&mut cx);
@ -917,12 +896,8 @@ mod tests {
fn recursive_load_main_with_code() { fn recursive_load_main_with_code() {
let loader = MockLoader::new(); let loader = MockLoader::new();
let loads = loader.loads.clone(); let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
// In default resolution code should be empty. // In default resolution code should be empty.
// Instead we explicitly pass in our own code. // Instead we explicitly pass in our own code.
// The behavior should be very similar to /a.js. // The behavior should be very similar to /a.js.

View file

@ -1,13 +1,13 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::gotham_state::GothamState;
use crate::BufVec; use crate::BufVec;
use crate::ErrBox; use crate::ErrBox;
use crate::ZeroCopyBuf; use crate::ZeroCopyBuf;
use futures::Future; use futures::Future;
use futures::FutureExt;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde_json::json;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::iter::once; use std::iter::once;
use std::ops::Deref; use std::ops::Deref;
@ -16,7 +16,7 @@ use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
pub type OpAsyncFuture = Pin<Box<dyn Future<Output = Box<[u8]>>>>; pub type OpAsyncFuture = Pin<Box<dyn Future<Output = Box<[u8]>>>>;
pub type OpFn<S> = dyn Fn(Rc<S>, BufVec) -> Op + 'static; pub type OpFn = dyn Fn(Rc<RefCell<OpState>>, BufVec) -> Op + 'static;
pub type OpId = usize; pub type OpId = usize;
pub enum Op { pub enum Op {
@ -28,119 +28,191 @@ pub enum Op {
NotFound, NotFound,
} }
pub trait OpRouter { pub struct OpState {
fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op; pub resource_table: crate::ResourceTable,
pub op_table: OpTable,
pub get_error_class_fn: crate::runtime::GetErrorClassFn,
gotham_state: GothamState,
} }
pub trait OpRegistry: OpRouter + 'static { impl Default for OpState {
fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId>; // TODO(ry) Only deno_core should be able to construct an OpState. But I don't
// know how to make default private. Maybe rename to
// pub(crate) fn new() -> OpState
fn default() -> OpState {
OpState {
resource_table: crate::ResourceTable::default(),
op_table: OpTable::default(),
get_error_class_fn: &|_| "Error",
gotham_state: GothamState::default(),
}
}
}
fn register_op<F>(&self, name: &str, op_fn: F) -> OpId impl Deref for OpState {
where type Target = GothamState;
F: Fn(Rc<Self>, BufVec) -> Op + 'static;
fn register_op_json_sync<F>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId fn deref(&self) -> &Self::Target {
&self.gotham_state
}
}
impl DerefMut for OpState {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.gotham_state
}
}
/// Collection for storing registered ops. The special 'get_op_catalog'
/// op with OpId `0` is automatically added when the OpTable is created.
pub struct OpTable(IndexMap<String, Rc<OpFn>>);
impl OpTable {
pub fn register_op<F>(&mut self, name: &str, op_fn: F) -> OpId
where where
F: Fn(&Self, Value, &mut [ZeroCopyBuf]) -> Result<Value, ErrBox> + 'static, F: Fn(Rc<RefCell<OpState>>, BufVec) -> Op + 'static,
{ {
let base_op_fn = move |state: Rc<Self>, mut bufs: BufVec| -> Op { let (op_id, prev) = self.0.insert_full(name.to_owned(), Rc::new(op_fn));
let result = serde_json::from_slice(&bufs[0]) assert!(prev.is_none());
.map_err(ErrBox::from) op_id
.and_then(|args| op_fn(&state, args, &mut bufs[1..]));
let buf = state.json_serialize_op_result(None, result);
Op::Sync(buf)
};
self.register_op(name, base_op_fn)
} }
fn register_op_json_async<F, R>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId pub fn route_op(
where op_id: OpId,
F: Fn(Rc<Self>, Value, BufVec) -> R + 'static, state: Rc<RefCell<OpState>>,
R: Future<Output = Result<Value, ErrBox>> + 'static, bufs: BufVec,
) -> Op {
if op_id == 0 {
let ops: HashMap<String, OpId> =
state.borrow().op_table.0.keys().cloned().zip(0..).collect();
let buf = serde_json::to_vec(&ops).map(Into::into).unwrap();
Op::Sync(buf)
} else {
let op_fn = state
.borrow()
.op_table
.0
.get_index(op_id)
.map(|(_, op_fn)| op_fn.clone());
match op_fn {
Some(f) => (f)(state, bufs),
None => Op::NotFound,
}
}
}
}
impl Default for OpTable {
fn default() -> Self {
fn dummy(_state: Rc<RefCell<OpState>>, _bufs: BufVec) -> Op {
unreachable!()
}
Self(once(("ops".to_owned(), Rc::new(dummy) as _)).collect())
}
}
#[test]
fn op_table() {
let state = Rc::new(RefCell::new(OpState::default()));
let foo_id;
let bar_id;
{ {
let try_dispatch_op = move |state: Rc<Self>, let op_table = &mut state.borrow_mut().op_table;
bufs: BufVec| foo_id = op_table.register_op("foo", |_, _| Op::Sync(b"oof!"[..].into()));
-> Result<Op, ErrBox> { assert_eq!(foo_id, 1);
bar_id = op_table.register_op("bar", |_, _| Op::Sync(b"rab!"[..].into()));
assert_eq!(bar_id, 2);
}
let foo_res = OpTable::route_op(foo_id, state.clone(), Default::default());
assert!(matches!(foo_res, Op::Sync(buf) if &*buf == b"oof!"));
let bar_res = OpTable::route_op(bar_id, state.clone(), Default::default());
assert!(matches!(bar_res, Op::Sync(buf) if &*buf == b"rab!"));
let catalog_res = OpTable::route_op(0, state, Default::default());
let mut catalog_entries = match catalog_res {
Op::Sync(buf) => serde_json::from_slice::<HashMap<String, OpId>>(&buf)
.map(|map| map.into_iter().collect::<Vec<_>>())
.unwrap(),
_ => panic!("unexpected `Op` variant"),
};
catalog_entries.sort_by(|(_, id1), (_, id2)| id1.partial_cmp(id2).unwrap());
assert_eq!(
catalog_entries,
vec![
("ops".to_owned(), 0),
("foo".to_owned(), 1),
("bar".to_owned(), 2)
]
)
}
pub fn json_op_sync<F>(op_fn: F) -> Box<OpFn>
where
F: Fn(&mut OpState, Value, &mut [ZeroCopyBuf]) -> Result<Value, ErrBox>
+ 'static,
{
Box::new(move |state: Rc<RefCell<OpState>>, mut bufs: BufVec| -> Op {
let result = serde_json::from_slice(&bufs[0])
.map_err(crate::ErrBox::from)
.and_then(|args| op_fn(&mut state.borrow_mut(), args, &mut bufs[1..]));
let buf =
json_serialize_op_result(None, result, state.borrow().get_error_class_fn);
Op::Sync(buf)
})
}
pub fn json_op_async<F, R>(op_fn: F) -> Box<OpFn>
where
F: Fn(Rc<RefCell<OpState>>, Value, BufVec) -> R + 'static,
R: Future<Output = Result<Value, ErrBox>> + 'static,
{
let try_dispatch_op =
move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Result<Op, ErrBox> {
let args: Value = serde_json::from_slice(&bufs[0])?; let args: Value = serde_json::from_slice(&bufs[0])?;
let promise_id = args let promise_id = args
.get("promiseId") .get("promiseId")
.and_then(Value::as_u64) .and_then(Value::as_u64)
.ok_or_else(|| ErrBox::type_error("missing or invalid `promiseId`"))?; .ok_or_else(|| ErrBox::type_error("missing or invalid `promiseId`"))?;
let bufs = bufs[1..].into(); let bufs = bufs[1..].into();
use crate::futures::FutureExt;
let fut = op_fn(state.clone(), args, bufs).map(move |result| { let fut = op_fn(state.clone(), args, bufs).map(move |result| {
state.json_serialize_op_result(Some(promise_id), result) json_serialize_op_result(
Some(promise_id),
result,
state.borrow().get_error_class_fn,
)
}); });
Ok(Op::Async(Box::pin(fut))) Ok(Op::Async(Box::pin(fut)))
}; };
let base_op_fn = move |state: Rc<Self>, bufs: BufVec| -> Op { Box::new(move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
match try_dispatch_op(state.clone(), bufs) { match try_dispatch_op(state.clone(), bufs) {
Ok(op) => op, Ok(op) => op,
Err(err) => Op::Sync(state.json_serialize_op_result(None, Err(err))), Err(err) => Op::Sync(json_serialize_op_result(
None,
Err(err),
state.borrow().get_error_class_fn,
)),
}
})
}
fn json_serialize_op_result(
promise_id: Option<u64>,
result: Result<serde_json::Value, crate::ErrBox>,
get_error_class_fn: crate::runtime::GetErrorClassFn,
) -> Box<[u8]> {
let value = match result {
Ok(v) => serde_json::json!({ "ok": v, "promiseId": promise_id }),
Err(err) => serde_json::json!({
"promiseId": promise_id ,
"err": {
"className": (get_error_class_fn)(&err),
"message": err.to_string(),
} }
}; }),
};
self.register_op(name, base_op_fn) serde_json::to_vec(&value).unwrap().into_boxed_slice()
}
fn json_serialize_op_result(
&self,
promise_id: Option<u64>,
result: Result<Value, ErrBox>,
) -> Box<[u8]> {
let value = match result {
Ok(v) => json!({ "ok": v, "promiseId": promise_id }),
Err(err) => json!({
"promiseId": promise_id ,
"err": {
"className": self.get_error_class_name(&err),
"message": err.to_string(),
}
}),
};
serde_json::to_vec(&value).unwrap().into_boxed_slice()
}
fn get_error_class_name(&self, _err: &ErrBox) -> &'static str {
"Error"
}
}
/// Collection for storing registered ops. The special 'get_op_catalog'
/// op with OpId `0` is automatically added when the OpTable is created.
pub struct OpTable<S>(IndexMap<String, Rc<OpFn<S>>>);
impl<S: OpRegistry> OpTable<S> {
pub fn get_op_catalog(&self) -> HashMap<String, OpId> {
self.keys().cloned().zip(0..).collect()
}
fn op_get_op_catalog(state: Rc<S>, _bufs: BufVec) -> Op {
let ops = state.get_op_catalog();
let buf = serde_json::to_vec(&ops).map(Into::into).unwrap();
Op::Sync(buf)
}
}
impl<S: OpRegistry> Default for OpTable<S> {
fn default() -> Self {
Self(
once(("ops".to_owned(), Rc::new(Self::op_get_op_catalog) as _)).collect(),
)
}
}
impl<S> Deref for OpTable<S> {
type Target = IndexMap<String, Rc<OpFn<S>>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<S> DerefMut for OpTable<S> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
} }

View file

@ -19,9 +19,10 @@ use crate::modules::RecursiveModuleLoad;
use crate::ops::*; use crate::ops::*;
use crate::shared_queue::SharedQueue; use crate::shared_queue::SharedQueue;
use crate::shared_queue::RECOMMENDED_SIZE; use crate::shared_queue::RECOMMENDED_SIZE;
use crate::BufVec;
use crate::ErrBox; use crate::ErrBox;
use crate::JsError; use crate::JsError;
use crate::OpRouter; use crate::OpState;
use futures::stream::FuturesUnordered; use futures::stream::FuturesUnordered;
use futures::stream::StreamExt; use futures::stream::StreamExt;
use futures::stream::StreamFuture; use futures::stream::StreamFuture;
@ -94,7 +95,7 @@ impl StartupData<'_> {
type JsErrorCreateFn = dyn Fn(JsError) -> ErrBox; type JsErrorCreateFn = dyn Fn(JsError) -> ErrBox;
pub type GetErrorClassFn = dyn for<'e> Fn(&'e ErrBox) -> &'static str; pub type GetErrorClassFn = &'static dyn for<'e> Fn(&'e ErrBox) -> &'static str;
/// Objects that need to live as long as the isolate /// Objects that need to live as long as the isolate
#[derive(Default)] #[derive(Default)]
@ -137,7 +138,8 @@ pub struct JsRuntimeState {
pub(crate) pending_ops: FuturesUnordered<PendingOpFuture>, pub(crate) pending_ops: FuturesUnordered<PendingOpFuture>,
pub(crate) pending_unref_ops: FuturesUnordered<PendingOpFuture>, pub(crate) pending_unref_ops: FuturesUnordered<PendingOpFuture>,
pub(crate) have_unpolled_ops: Cell<bool>, pub(crate) have_unpolled_ops: Cell<bool>,
pub(crate) op_router: Rc<dyn OpRouter>, //pub(crate) op_table: OpTable,
pub(crate) op_state: Rc<RefCell<OpState>>,
loader: Rc<dyn ModuleLoader>, loader: Rc<dyn ModuleLoader>,
pub modules: Modules, pub modules: Modules,
pub(crate) dyn_import_map: pub(crate) dyn_import_map:
@ -219,7 +221,6 @@ pub struct HeapLimits {
pub(crate) struct IsolateOptions { pub(crate) struct IsolateOptions {
loader: Rc<dyn ModuleLoader>, loader: Rc<dyn ModuleLoader>,
op_router: Rc<dyn OpRouter>,
startup_script: Option<OwnedScript>, startup_script: Option<OwnedScript>,
startup_snapshot: Option<Snapshot>, startup_snapshot: Option<Snapshot>,
will_snapshot: bool, will_snapshot: bool,
@ -229,15 +230,10 @@ pub(crate) struct IsolateOptions {
impl JsRuntime { impl JsRuntime {
/// startup_data defines the snapshot or script used at startup to initialize /// startup_data defines the snapshot or script used at startup to initialize
/// the isolate. /// the isolate.
pub fn new( pub fn new(startup_data: StartupData, will_snapshot: bool) -> Self {
op_router: Rc<dyn OpRouter>,
startup_data: StartupData,
will_snapshot: bool,
) -> Self {
let (startup_script, startup_snapshot) = startup_data.into_options(); let (startup_script, startup_snapshot) = startup_data.into_options();
let options = IsolateOptions { let options = IsolateOptions {
loader: Rc::new(NoopModuleLoader), loader: Rc::new(NoopModuleLoader),
op_router,
startup_script, startup_script,
startup_snapshot, startup_snapshot,
will_snapshot, will_snapshot,
@ -251,14 +247,12 @@ impl JsRuntime {
/// Create new isolate that can load and execute ESModules. /// Create new isolate that can load and execute ESModules.
pub fn new_with_loader( pub fn new_with_loader(
loader: Rc<dyn ModuleLoader>, loader: Rc<dyn ModuleLoader>,
op_router: Rc<dyn OpRouter>,
startup_data: StartupData, startup_data: StartupData,
will_snapshot: bool, will_snapshot: bool,
) -> Self { ) -> Self {
let (startup_script, startup_snapshot) = startup_data.into_options(); let (startup_script, startup_snapshot) = startup_data.into_options();
let options = IsolateOptions { let options = IsolateOptions {
loader, loader,
op_router,
startup_script, startup_script,
startup_snapshot, startup_snapshot,
will_snapshot, will_snapshot,
@ -275,14 +269,12 @@ impl JsRuntime {
/// Make sure to use [`add_near_heap_limit_callback`](#method.add_near_heap_limit_callback) /// Make sure to use [`add_near_heap_limit_callback`](#method.add_near_heap_limit_callback)
/// to prevent v8 from crashing when reaching the upper limit. /// to prevent v8 from crashing when reaching the upper limit.
pub fn with_heap_limits( pub fn with_heap_limits(
op_router: Rc<dyn OpRouter>,
startup_data: StartupData, startup_data: StartupData,
heap_limits: HeapLimits, heap_limits: HeapLimits,
) -> Self { ) -> Self {
let (startup_script, startup_snapshot) = startup_data.into_options(); let (startup_script, startup_snapshot) = startup_data.into_options();
let options = IsolateOptions { let options = IsolateOptions {
loader: Rc::new(NoopModuleLoader), loader: Rc::new(NoopModuleLoader),
op_router,
startup_script, startup_script,
startup_snapshot, startup_snapshot,
will_snapshot: false, will_snapshot: false,
@ -347,6 +339,8 @@ impl JsRuntime {
(isolate, None) (isolate, None)
}; };
let op_state = OpState::default();
isolate.set_slot(Rc::new(RefCell::new(JsRuntimeState { isolate.set_slot(Rc::new(RefCell::new(JsRuntimeState {
global_context: Some(global_context), global_context: Some(global_context),
pending_promise_exceptions: HashMap::new(), pending_promise_exceptions: HashMap::new(),
@ -357,8 +351,8 @@ impl JsRuntime {
shared: SharedQueue::new(RECOMMENDED_SIZE), shared: SharedQueue::new(RECOMMENDED_SIZE),
pending_ops: FuturesUnordered::new(), pending_ops: FuturesUnordered::new(),
pending_unref_ops: FuturesUnordered::new(), pending_unref_ops: FuturesUnordered::new(),
op_state: Rc::new(RefCell::new(op_state)),
have_unpolled_ops: Cell::new(false), have_unpolled_ops: Cell::new(false),
op_router: options.op_router,
modules: Modules::new(), modules: Modules::new(),
loader: options.loader, loader: options.loader,
dyn_import_map: HashMap::new(), dyn_import_map: HashMap::new(),
@ -406,6 +400,12 @@ impl JsRuntime {
} }
} }
pub fn op_state(&mut self) -> Rc<RefCell<OpState>> {
let state_rc = Self::state(self);
let state = state_rc.borrow();
state.op_state.clone()
}
/// Executes traditional JavaScript code (traditional = not ES modules) /// Executes traditional JavaScript code (traditional = not ES modules)
/// ///
/// ErrBox can be downcast to a type that exposes additional information about /// ErrBox can be downcast to a type that exposes additional information about
@ -477,6 +477,18 @@ impl JsRuntime {
snapshot snapshot
} }
pub fn register_op<F>(&mut self, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<RefCell<OpState>>, BufVec) -> Op + 'static,
{
Self::state(self)
.borrow_mut()
.op_state
.borrow_mut()
.op_table
.register_op(name, op_fn)
}
/// Registers a callback on the isolate when the memory limits are approached. /// Registers a callback on the isolate when the memory limits are approached.
/// Use this to prevent V8 from crashing the process when reaching the limit. /// Use this to prevent V8 from crashing the process when reaching the limit.
/// ///
@ -1283,8 +1295,6 @@ impl JsRuntime {
pub mod tests { pub mod tests {
use super::*; use super::*;
use crate::modules::ModuleSourceFuture; use crate::modules::ModuleSourceFuture;
use crate::ops::*;
use crate::BasicState;
use crate::BufVec; use crate::BufVec;
use futures::future::lazy; use futures::future::lazy;
use futures::FutureExt; use futures::FutureExt;
@ -1328,89 +1338,89 @@ pub mod tests {
OverflowResAsync, OverflowResAsync,
} }
struct TestOpRouter { struct TestState {
mode: Mode, mode: Mode,
dispatch_count: Arc<AtomicUsize>, dispatch_count: Arc<AtomicUsize>,
} }
impl OpRouter for TestOpRouter { fn dispatch(op_state: Rc<RefCell<OpState>>, bufs: BufVec) -> Op {
fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op { let op_state_ = op_state.borrow();
if op_id != 1 { let test_state = op_state_.borrow::<TestState>();
return Op::NotFound; test_state.dispatch_count.fetch_add(1, Ordering::Relaxed);
match test_state.mode {
Mode::Async => {
assert_eq!(bufs.len(), 1);
assert_eq!(bufs[0].len(), 1);
assert_eq!(bufs[0][0], 42);
let buf = vec![43u8].into_boxed_slice();
Op::Async(futures::future::ready(buf).boxed())
} }
self.dispatch_count.fetch_add(1, Ordering::Relaxed); Mode::AsyncUnref => {
match self.mode { assert_eq!(bufs.len(), 1);
Mode::Async => { assert_eq!(bufs[0].len(), 1);
assert_eq!(bufs.len(), 1); assert_eq!(bufs[0][0], 42);
assert_eq!(bufs[0].len(), 1); let fut = async {
assert_eq!(bufs[0][0], 42); // This future never finish.
let buf = vec![43u8].into_boxed_slice(); futures::future::pending::<()>().await;
Op::Async(futures::future::ready(buf).boxed()) vec![43u8].into_boxed_slice()
} };
Mode::AsyncUnref => { Op::AsyncUnref(fut.boxed())
assert_eq!(bufs.len(), 1); }
assert_eq!(bufs[0].len(), 1); Mode::AsyncZeroCopy(count) => {
assert_eq!(bufs[0][0], 42); assert_eq!(bufs.len(), count as usize);
let fut = async { bufs.iter().enumerate().for_each(|(idx, buf)| {
// This future never finish. assert_eq!(buf.len(), 1);
futures::future::pending::<()>().await; assert_eq!(idx, buf[0] as usize);
vec![43u8].into_boxed_slice() });
};
Op::AsyncUnref(fut.boxed())
}
Mode::AsyncZeroCopy(count) => {
assert_eq!(bufs.len(), count as usize);
bufs.iter().enumerate().for_each(|(idx, buf)| {
assert_eq!(buf.len(), 1);
assert_eq!(idx, buf[0] as usize);
});
let buf = vec![43u8].into_boxed_slice(); let buf = vec![43u8].into_boxed_slice();
Op::Async(futures::future::ready(buf).boxed()) Op::Async(futures::future::ready(buf).boxed())
} }
Mode::OverflowReqSync => { Mode::OverflowReqSync => {
assert_eq!(bufs.len(), 1); assert_eq!(bufs.len(), 1);
assert_eq!(bufs[0].len(), 100 * 1024 * 1024); assert_eq!(bufs[0].len(), 100 * 1024 * 1024);
let buf = vec![43u8].into_boxed_slice(); let buf = vec![43u8].into_boxed_slice();
Op::Sync(buf) Op::Sync(buf)
} }
Mode::OverflowResSync => { Mode::OverflowResSync => {
assert_eq!(bufs.len(), 1); assert_eq!(bufs.len(), 1);
assert_eq!(bufs[0].len(), 1); assert_eq!(bufs[0].len(), 1);
assert_eq!(bufs[0][0], 42); assert_eq!(bufs[0][0], 42);
let mut vec = Vec::<u8>::new(); let mut vec = Vec::<u8>::new();
vec.resize(100 * 1024 * 1024, 0); vec.resize(100 * 1024 * 1024, 0);
vec[0] = 99; vec[0] = 99;
let buf = vec.into_boxed_slice(); let buf = vec.into_boxed_slice();
Op::Sync(buf) Op::Sync(buf)
} }
Mode::OverflowReqAsync => { Mode::OverflowReqAsync => {
assert_eq!(bufs.len(), 1); assert_eq!(bufs.len(), 1);
assert_eq!(bufs[0].len(), 100 * 1024 * 1024); assert_eq!(bufs[0].len(), 100 * 1024 * 1024);
let buf = vec![43u8].into_boxed_slice(); let buf = vec![43u8].into_boxed_slice();
Op::Async(futures::future::ready(buf).boxed()) Op::Async(futures::future::ready(buf).boxed())
} }
Mode::OverflowResAsync => { Mode::OverflowResAsync => {
assert_eq!(bufs.len(), 1); assert_eq!(bufs.len(), 1);
assert_eq!(bufs[0].len(), 1); assert_eq!(bufs[0].len(), 1);
assert_eq!(bufs[0][0], 42); assert_eq!(bufs[0][0], 42);
let mut vec = Vec::<u8>::new(); let mut vec = Vec::<u8>::new();
vec.resize(100 * 1024 * 1024, 0); vec.resize(100 * 1024 * 1024, 0);
vec[0] = 4; vec[0] = 4;
let buf = vec.into_boxed_slice(); let buf = vec.into_boxed_slice();
Op::Async(futures::future::ready(buf).boxed()) Op::Async(futures::future::ready(buf).boxed())
}
} }
} }
} }
fn setup(mode: Mode) -> (JsRuntime, Arc<AtomicUsize>) { fn setup(mode: Mode) -> (JsRuntime, Arc<AtomicUsize>) {
let dispatch_count = Arc::new(AtomicUsize::new(0)); let dispatch_count = Arc::new(AtomicUsize::new(0));
let test_state = Rc::new(TestOpRouter { let mut runtime = JsRuntime::new(StartupData::None, false);
let op_state = runtime.op_state();
op_state.borrow_mut().put(TestState {
mode, mode,
dispatch_count: dispatch_count.clone(), dispatch_count: dispatch_count.clone(),
}); });
let mut runtime = JsRuntime::new(test_state, StartupData::None, false);
runtime.register_op("test", dispatch);
js_check(runtime.execute( js_check(runtime.execute(
"setup.js", "setup.js",
@ -1774,8 +1784,7 @@ pub mod tests {
#[test] #[test]
fn syntax_error() { fn syntax_error() {
let mut runtime = let mut runtime = JsRuntime::new(StartupData::None, false);
JsRuntime::new(BasicState::new(), StartupData::None, false);
let src = "hocuspocus("; let src = "hocuspocus(";
let r = runtime.execute("i.js", src); let r = runtime.execute("i.js", src);
let e = r.unwrap_err(); let e = r.unwrap_err();
@ -1800,29 +1809,27 @@ pub mod tests {
#[test] #[test]
fn will_snapshot() { fn will_snapshot() {
let snapshot = { let snapshot = {
let mut runtime = let mut runtime = JsRuntime::new(StartupData::None, true);
JsRuntime::new(BasicState::new(), StartupData::None, true);
js_check(runtime.execute("a.js", "a = 1 + 2")); js_check(runtime.execute("a.js", "a = 1 + 2"));
runtime.snapshot() runtime.snapshot()
}; };
let startup_data = StartupData::Snapshot(Snapshot::JustCreated(snapshot)); let startup_data = StartupData::Snapshot(Snapshot::JustCreated(snapshot));
let mut runtime2 = JsRuntime::new(BasicState::new(), startup_data, false); let mut runtime2 = JsRuntime::new(startup_data, false);
js_check(runtime2.execute("check.js", "if (a != 3) throw Error('x')")); js_check(runtime2.execute("check.js", "if (a != 3) throw Error('x')"));
} }
#[test] #[test]
fn test_from_boxed_snapshot() { fn test_from_boxed_snapshot() {
let snapshot = { let snapshot = {
let mut runtime = let mut runtime = JsRuntime::new(StartupData::None, true);
JsRuntime::new(BasicState::new(), StartupData::None, true);
js_check(runtime.execute("a.js", "a = 1 + 2")); js_check(runtime.execute("a.js", "a = 1 + 2"));
let snap: &[u8] = &*runtime.snapshot(); let snap: &[u8] = &*runtime.snapshot();
Vec::from(snap).into_boxed_slice() Vec::from(snap).into_boxed_slice()
}; };
let startup_data = StartupData::Snapshot(Snapshot::Boxed(snapshot)); let startup_data = StartupData::Snapshot(Snapshot::Boxed(snapshot));
let mut runtime2 = JsRuntime::new(BasicState::new(), startup_data, false); let mut runtime2 = JsRuntime::new(startup_data, false);
js_check(runtime2.execute("check.js", "if (a != 3) throw Error('x')")); js_check(runtime2.execute("check.js", "if (a != 3) throw Error('x')"));
} }
@ -1832,11 +1839,8 @@ pub mod tests {
initial: 0, initial: 0,
max: 20 * 1024, // 20 kB max: 20 * 1024, // 20 kB
}; };
let mut runtime = JsRuntime::with_heap_limits( let mut runtime =
BasicState::new(), JsRuntime::with_heap_limits(StartupData::None, heap_limits);
StartupData::None,
heap_limits,
);
let cb_handle = runtime.thread_safe_handle(); let cb_handle = runtime.thread_safe_handle();
let callback_invoke_count = Rc::new(AtomicUsize::default()); let callback_invoke_count = Rc::new(AtomicUsize::default());
@ -1864,8 +1868,7 @@ pub mod tests {
#[test] #[test]
fn test_heap_limit_cb_remove() { fn test_heap_limit_cb_remove() {
let mut runtime = let mut runtime = JsRuntime::new(StartupData::None, false);
JsRuntime::new(BasicState::new(), StartupData::None, false);
runtime.add_near_heap_limit_callback(|current_limit, _initial_limit| { runtime.add_near_heap_limit_callback(|current_limit, _initial_limit| {
current_limit * 2 current_limit * 2
@ -1880,11 +1883,8 @@ pub mod tests {
initial: 0, initial: 0,
max: 20 * 1024, // 20 kB max: 20 * 1024, // 20 kB
}; };
let mut runtime = JsRuntime::with_heap_limits( let mut runtime =
BasicState::new(), JsRuntime::with_heap_limits(StartupData::None, heap_limits);
StartupData::None,
heap_limits,
);
let cb_handle = runtime.thread_safe_handle(); let cb_handle = runtime.thread_safe_handle();
let callback_invoke_count_first = Rc::new(AtomicUsize::default()); let callback_invoke_count_first = Rc::new(AtomicUsize::default());
@ -1952,13 +1952,12 @@ pub mod tests {
} }
let loader = Rc::new(ModsLoader::default()); let loader = Rc::new(ModsLoader::default());
let state = BasicState::new();
let resolve_count = loader.count.clone(); let resolve_count = loader.count.clone();
let dispatch_count = Arc::new(AtomicUsize::new(0)); let dispatch_count = Arc::new(AtomicUsize::new(0));
let dispatch_count_ = dispatch_count.clone(); let dispatch_count_ = dispatch_count.clone();
let dispatcher = move |_state: Rc<BasicState>, bufs: BufVec| -> Op { let dispatcher = move |_state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
dispatch_count_.fetch_add(1, Ordering::Relaxed); dispatch_count_.fetch_add(1, Ordering::Relaxed);
assert_eq!(bufs.len(), 1); assert_eq!(bufs.len(), 1);
assert_eq!(bufs[0].len(), 1); assert_eq!(bufs[0].len(), 1);
@ -1966,10 +1965,10 @@ pub mod tests {
let buf = [43u8, 0, 0, 0][..].into(); let buf = [43u8, 0, 0, 0][..].into();
Op::Async(futures::future::ready(buf).boxed()) Op::Async(futures::future::ready(buf).boxed())
}; };
state.register_op("test", dispatcher);
let mut runtime = let mut runtime =
JsRuntime::new_with_loader(loader, state, StartupData::None, false); JsRuntime::new_with_loader(loader, StartupData::None, false);
runtime.register_op("test", dispatcher);
js_check(runtime.execute( js_check(runtime.execute(
"setup.js", "setup.js",
@ -2063,12 +2062,8 @@ pub mod tests {
run_in_task(|cx| { run_in_task(|cx| {
let loader = Rc::new(DynImportErrLoader::default()); let loader = Rc::new(DynImportErrLoader::default());
let count = loader.count.clone(); let count = loader.count.clone();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
js_check(runtime.execute( js_check(runtime.execute(
"file:///dyn_import2.js", "file:///dyn_import2.js",
@ -2145,12 +2140,8 @@ pub mod tests {
let prepare_load_count = loader.prepare_load_count.clone(); let prepare_load_count = loader.prepare_load_count.clone();
let resolve_count = loader.resolve_count.clone(); let resolve_count = loader.resolve_count.clone();
let load_count = loader.load_count.clone(); let load_count = loader.load_count.clone();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
// Dynamically import mod_b // Dynamically import mod_b
js_check(runtime.execute( js_check(runtime.execute(
@ -2190,12 +2181,8 @@ pub mod tests {
run_in_task(|cx| { run_in_task(|cx| {
let loader = Rc::new(DynImportOkLoader::default()); let loader = Rc::new(DynImportOkLoader::default());
let prepare_load_count = loader.prepare_load_count.clone(); let prepare_load_count = loader.prepare_load_count.clone();
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, false);
BasicState::new(),
StartupData::None,
false,
);
js_check(runtime.execute( js_check(runtime.execute(
"file:///dyn_import3.js", "file:///dyn_import3.js",
r#" r#"
@ -2246,12 +2233,8 @@ pub mod tests {
} }
let loader = std::rc::Rc::new(ModsLoader::default()); let loader = std::rc::Rc::new(ModsLoader::default());
let mut runtime = JsRuntime::new_with_loader( let mut runtime =
loader, JsRuntime::new_with_loader(loader, StartupData::None, true);
BasicState::new(),
StartupData::None,
true,
);
let specifier = ModuleSpecifier::resolve_url("file:///main.js").unwrap(); let specifier = ModuleSpecifier::resolve_url("file:///main.js").unwrap();
let source_code = "Deno.core.print('hello\\n')".to_string(); let source_code = "Deno.core.print('hello\\n')".to_string();

View file

@ -33,7 +33,6 @@ pub fn get_declaration() -> PathBuf {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use deno_core::js_check; use deno_core::js_check;
use deno_core::BasicState;
use deno_core::JsRuntime; use deno_core::JsRuntime;
use deno_core::StartupData; use deno_core::StartupData;
use futures::future::lazy; use futures::future::lazy;
@ -49,8 +48,7 @@ mod tests {
} }
fn setup() -> JsRuntime { fn setup() -> JsRuntime {
let mut isolate = let mut isolate = JsRuntime::new(StartupData::None, false);
JsRuntime::new(BasicState::new(), StartupData::None, false);
crate::init(&mut isolate); crate::init(&mut isolate);
isolate isolate
} }