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;
use deno_core::js_check;
use deno_core::BasicState;
use deno_core::JsRuntime;
use deno_core::OpRegistry;
use deno_core::StartupData;
use std::collections::HashMap;
use std::env;
@ -39,8 +37,7 @@ fn create_snapshot(
}
fn create_runtime_snapshot(snapshot_path: &Path, files: Vec<PathBuf>) {
let state = BasicState::new();
let isolate = JsRuntime::new(state, StartupData::None, true);
let isolate = JsRuntime::new(StartupData::None, true);
create_snapshot(isolate, snapshot_path, files);
}
@ -73,13 +70,11 @@ fn create_compiler_snapshot(
cwd.join("dts/lib.deno.unstable.d.ts"),
);
let state = BasicState::new();
state.register_op(
let mut isolate = JsRuntime::new(StartupData::None, true);
isolate.register_op(
"op_fetch_asset",
op_fetch_asset::op_fetch_asset(custom_libs),
);
let isolate = JsRuntime::new(state, StartupData::None, true);
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]
fn cli_snapshot() {
let mut isolate = deno_core::JsRuntime::new(
deno_core::BasicState::new(),
deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(CLI_SNAPSHOT)),
false,
);
@ -32,7 +31,6 @@ fn cli_snapshot() {
#[test]
fn compiler_snapshot() {
let mut isolate = deno_core::JsRuntime::new(
deno_core::BasicState::new(),
deno_core::StartupData::Snapshot(deno_core::Snapshot::Static(
COMPILER_SNAPSHOT,
)),

View file

@ -71,3 +71,60 @@ impl Metrics {
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.
use crate::state::State;
use deno_core::OpRegistry;
use std::rc::Rc;
use std::sync::Arc;
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();
// TODO(ry) use None.
// TODO(bartlomieju): is this op even required?
s.register_op(
rt.register_op(
"op_fetch_asset",
crate::op_fetch_asset::op_fetch_asset(custom_assets),
);
s.register_op_json_sync("op_compiler_respond", move |_state, args, _bufs| {
let mut response_slot = response.lock().unwrap();
let replaced_value = response_slot.replace(args.to_string());
assert!(
replaced_value.is_none(),
"op_compiler_respond found unexpected existing compiler output",
);
Ok(json!({}))
});
super::reg_json_sync(
rt,
"op_compiler_respond",
move |_state, args, _bufs| {
let mut response_slot = response.lock().unwrap();
let replaced_value = response_slot.replace(args.to_string());
assert!(
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.
use crate::state::State;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::Op;
use deno_core::OpId;
use deno_core::OpRegistry;
use deno_core::OpFn;
use deno_core::OpState;
use futures::future::FutureExt;
use std::cell::RefCell;
use std::future::Future;
use std::iter::repeat;
use std::mem::size_of_val;
@ -132,78 +132,74 @@ fn test_parse_min_record() {
assert_eq!(parse_min_record(&buf), None);
}
impl State {
pub fn register_op_minimal<F>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<Self>, bool, i32, BufVec) -> MinimalOp + 'static,
{
let base_op_fn = move |state: Rc<Self>, bufs: BufVec| {
let mut bufs_iter = bufs.into_iter();
let record_buf = bufs_iter.next().expect("Expected record at position 0");
let zero_copy = bufs_iter.collect::<BufVec>();
pub fn minimal_op<F>(op_fn: F) -> Box<OpFn>
where
F: Fn(Rc<RefCell<OpState>>, bool, i32, BufVec) -> MinimalOp + 'static,
{
Box::new(move |state: Rc<RefCell<OpState>>, bufs: BufVec| {
let mut bufs_iter = bufs.into_iter();
let record_buf = bufs_iter.next().expect("Expected record at position 0");
let zero_copy = bufs_iter.collect::<BufVec>();
let mut record = match parse_min_record(&record_buf) {
Some(r) => r,
None => {
let error = ErrBox::type_error("Unparsable control buffer");
let error_class = state.get_error_class_name(&error);
let mut record = match parse_min_record(&record_buf) {
Some(r) => r,
None => {
let error = ErrBox::type_error("Unparsable control buffer");
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 {
promise_id: 0,
promise_id: record.promise_id,
arg: -1,
error_len: error_class.len() as i32,
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;
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.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()
}
}),
MinimalOp::Async(min_fut) => {
let fut = async move {
match min_fut.await {
Ok(r) => {
record.result = r;
record.into()
}
};
Op::Async(fut.boxed_local())
}
Err(err) => {
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::source_maps::get_orig_position;
use crate::source_maps::CachedMaps;
use crate::state::State;
use deno_core::ErrBox;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use serde_derive::Deserialize;
use serde_json::Value;
use std::collections::HashMap;
use std::rc::Rc;
pub fn init(s: &Rc<State>) {
s.register_op_json_sync("op_apply_source_map", op_apply_source_map);
s.register_op_json_sync("op_format_diagnostic", op_format_diagnostic);
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_apply_source_map", op_apply_source_map);
super::reg_json_sync(rt, "op_format_diagnostic", op_format_diagnostic);
}
#[derive(Deserialize)]
@ -26,7 +24,7 @@ struct ApplySourceMap {
}
fn op_apply_source_map(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
@ -39,7 +37,7 @@ fn op_apply_source_map(
args.line_number.into(),
args.column_number.into(),
&mut mappings_map,
&state.global_state.ts_compiler,
&super::cli_state(state).global_state.ts_compiler,
);
Ok(json!({
@ -50,7 +48,7 @@ fn op_apply_source_map(
}
fn op_format_diagnostic(
_state: &State,
_state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {

View file

@ -2,10 +2,9 @@
use super::io::{StreamResource, StreamResourceHolder};
use crate::http_util::{create_http_client, HttpBody};
use crate::state::State;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use http::header::HeaderName;
use http::header::HeaderValue;
@ -13,13 +12,14 @@ use http::Method;
use reqwest::Client;
use serde_derive::Deserialize;
use serde_json::Value;
use std::cell::RefCell;
use std::convert::From;
use std::path::PathBuf;
use std::rc::Rc;
pub fn init(s: &Rc<State>) {
s.register_op_json_async("op_fetch", op_fetch);
s.register_op_json_sync("op_create_http_client", op_create_http_client);
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_async(rt, "op_fetch", op_fetch);
super::reg_json_sync(rt, "op_create_http_client", op_create_http_client);
}
#[derive(Deserialize)]
@ -32,7 +32,7 @@ struct FetchArgs {
}
async fn op_fetch(
state: Rc<State>,
state: Rc<RefCell<OpState>>,
args: Value,
data: BufVec,
) -> Result<Value, ErrBox> {
@ -40,13 +40,15 @@ async fn op_fetch(
let url = args.url;
let client = if let Some(rid) = args.client_rid {
let resource_table_ = state.resource_table.borrow();
let r = resource_table_
let state = state.borrow();
let r = state
.resource_table
.get::<HttpClientResource>(rid)
.ok_or_else(ErrBox::bad_resource_id)?;
r.client.clone()
} 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()
};
@ -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_);
@ -93,7 +95,7 @@ async fn op_fetch(
}
let body = HttpBody::from(res);
let rid = state.resource_table.borrow_mut().add(
let rid = state.borrow_mut().resource_table.add(
"httpBody",
Box::new(StreamResourceHolder::new(StreamResource::HttpBody(
Box::new(body),
@ -128,21 +130,20 @@ struct CreateHttpClientOptions {
}
fn op_create_http_client(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
let args: CreateHttpClientOptions = serde_json::from_value(args)?;
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 rid = state
.resource_table
.borrow_mut()
.add("httpClient", Box::new(HttpClientResource::new(client)));
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.
use crate::state::State;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use futures::future::poll_fn;
use notify::event::Event as NotifyEvent;
@ -15,14 +14,15 @@ use notify::Watcher;
use serde::Serialize;
use serde_derive::Deserialize;
use serde_json::Value;
use std::cell::RefCell;
use std::convert::From;
use std::path::PathBuf;
use std::rc::Rc;
use tokio::sync::mpsc;
pub fn init(s: &Rc<State>) {
s.register_op_json_sync("op_fs_events_open", op_fs_events_open);
s.register_op_json_async("op_fs_events_poll", op_fs_events_poll);
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_fs_events_open", op_fs_events_open);
super::reg_json_async(rt, "op_fs_events_poll", op_fs_events_poll);
}
struct FsEventsResource {
@ -64,7 +64,7 @@ impl From<NotifyEvent> for FsEvent {
}
fn op_fs_events_open(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
@ -90,19 +90,16 @@ fn op_fs_events_open(
RecursiveMode::NonRecursive
};
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)?;
}
let resource = FsEventsResource { watcher, receiver };
let rid = state
.resource_table
.borrow_mut()
.add("fsEvents", Box::new(resource));
let rid = state.resource_table.add("fsEvents", Box::new(resource));
Ok(json!(rid))
}
async fn op_fs_events_poll(
state: Rc<State>,
state: Rc<RefCell<OpState>>,
args: Value,
_zero_copy: BufVec,
) -> Result<Value, ErrBox> {
@ -112,8 +109,9 @@ async fn op_fs_events_poll(
}
let PollArgs { rid } = serde_json::from_value(args)?;
poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut();
let watcher = resource_table
let mut state = state.borrow_mut();
let watcher = state
.resource_table
.get_mut::<FsEventsResource>(rid)
.ok_or_else(ErrBox::bad_resource_id)?;
watcher

View file

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

View file

@ -1,11 +1,15 @@
use super::dispatch_minimal::minimal_op;
use super::dispatch_minimal::MinimalOp;
use crate::http_util::HttpBody;
use crate::state::State;
use crate::metrics::metrics_op;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::JsRuntime;
use deno_core::OpState;
use futures::future::poll_fn;
use futures::future::FutureExt;
use futures::ready;
use std::cell::RefCell;
use std::collections::HashMap;
use std::pin::Pin;
use std::rc::Rc;
@ -82,9 +86,9 @@ lazy_static! {
};
}
pub fn init(s: &Rc<State>) {
s.register_op_minimal("op_read", op_read);
s.register_op_minimal("op_write", op_write);
pub fn init(rt: &mut JsRuntime) {
rt.register_op("op_read", metrics_op(minimal_op(op_read)));
rt.register_op("op_write", metrics_op(minimal_op(op_write)));
}
pub fn get_stdio() -> (
@ -233,7 +237,7 @@ impl DenoAsyncRead for StreamResource {
}
pub fn op_read(
state: Rc<State>,
state: Rc<RefCell<OpState>>,
is_sync: bool,
rid: i32,
mut zero_copy: BufVec,
@ -248,7 +252,7 @@ pub fn op_read(
if is_sync {
MinimalOp::Sync({
// 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) => {
use std::io::Read;
std_file
@ -265,8 +269,9 @@ pub fn op_read(
let mut zero_copy = zero_copy[0].clone();
MinimalOp::Async(
poll_fn(move |cx| {
let mut resource_table = state.resource_table.borrow_mut();
let resource_holder = resource_table
let mut state = state.borrow_mut();
let resource_holder = state
.resource_table
.get_mut::<StreamResourceHolder>(rid as u32)
.ok_or_else(ErrBox::bad_resource_id)?;
@ -352,7 +357,7 @@ impl DenoAsyncWrite for StreamResource {
}
pub fn op_write(
state: Rc<State>,
state: Rc<RefCell<OpState>>,
is_sync: bool,
rid: i32,
zero_copy: BufVec,
@ -367,7 +372,7 @@ pub fn op_write(
if is_sync {
MinimalOp::Sync({
// 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) => {
use std::io::Write;
std_file
@ -385,8 +390,9 @@ pub fn op_write(
MinimalOp::Async(
async move {
let nwritten = poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut();
let resource_holder = resource_table
let mut state = state.borrow_mut();
let resource_holder = state
.resource_table
.get_mut::<StreamResourceHolder>(rid as u32)
.ok_or_else(ErrBox::bad_resource_id)?;
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.
// https://github.com/denoland/deno/issues/3565
poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut();
let resource_holder = resource_table
let mut state = state.borrow_mut();
let resource_holder = state
.resource_table
.get_mut::<StreamResourceHolder>(rid as u32)
.ok_or_else(ErrBox::bad_resource_id)?;
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.
pub fn std_file_resource<F, T>(
state: &State,
state: &mut OpState,
rid: u32,
mut f: F,
) -> Result<T, ErrBox>
@ -430,8 +437,7 @@ where
FnMut(Result<&mut std::fs::File, &mut StreamResource>) -> Result<T, ErrBox>,
{
// First we look up the rid in the resource table.
let mut resource_table = state.resource_table.borrow_mut();
let mut r = resource_table.get_mut::<StreamResourceHolder>(rid);
let mut r = state.resource_table.get_mut::<StreamResourceHolder>(rid);
if let Some(ref mut resource_holder) = r {
// 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.

View file

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

View file

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

View file

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

View file

@ -1,18 +1,16 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::State;
use deno_core::ErrBox;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use serde_derive::Deserialize;
use serde_json::Value;
use std::path::Path;
use std::rc::Rc;
pub fn init(s: &Rc<State>) {
s.register_op_json_sync("op_query_permission", op_query_permission);
s.register_op_json_sync("op_revoke_permission", op_revoke_permission);
s.register_op_json_sync("op_request_permission", op_request_permission);
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_query_permission", op_query_permission);
super::reg_json_sync(rt, "op_revoke_permission", op_revoke_permission);
super::reg_json_sync(rt, "op_request_permission", op_request_permission);
}
#[derive(Deserialize)]
@ -23,12 +21,13 @@ struct PermissionArgs {
}
pub fn op_query_permission(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
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 perm = match args.name.as_ref() {
"read" => permissions.query_read(&path.as_deref().map(Path::new)),
@ -49,12 +48,13 @@ pub fn op_query_permission(
}
pub fn op_revoke_permission(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
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 perm = match args.name.as_ref() {
"read" => permissions.revoke_read(&path.as_deref().map(Path::new)),
@ -75,12 +75,13 @@ pub fn op_revoke_permission(
}
pub fn op_request_permission(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
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 perm = match args.name.as_ref() {
"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.
use crate::state::State;
use crate::metrics::metrics_op;
use deno_core::plugin_api;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::JsRuntime;
use deno_core::Op;
use deno_core::OpAsyncFuture;
use deno_core::OpId;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use dlopen::symbor::Library;
use futures::prelude::*;
use serde_derive::Deserialize;
use serde_json::Value;
use std::cell::RefCell;
use std::path::PathBuf;
use std::pin::Pin;
use std::rc::Rc;
use std::task::Context;
use std::task::Poll;
pub fn init(s: &Rc<State>) {
s.register_op_json_sync("op_open_plugin", op_open_plugin);
pub fn init(rt: &mut JsRuntime) {
super::reg_json_sync(rt, "op_open_plugin", op_open_plugin);
}
#[derive(Deserialize)]
@ -30,16 +32,16 @@ struct OpenPluginArgs {
}
pub fn op_open_plugin(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
state.check_unstable("Deno.openPlugin");
let args: OpenPluginArgs = serde_json::from_value(args).unwrap();
let args: OpenPluginArgs = serde_json::from_value(args)?;
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);
let plugin_lib = Library::open(filename).map(Rc::new)?;
@ -48,10 +50,12 @@ pub fn op_open_plugin(
let rid;
let deno_plugin_init;
{
let mut resource_table = state.resource_table.borrow_mut();
rid = resource_table.add("plugin", Box::new(plugin_resource));
rid = state
.resource_table
.add("plugin", Box::new(plugin_resource));
deno_plugin_init = *unsafe {
resource_table
state
.resource_table
.get::<PluginResource>(rid)
.unwrap()
.lib
@ -77,12 +81,12 @@ impl PluginResource {
}
struct PluginInterface<'a> {
state: &'a State,
state: &'a mut OpState,
plugin_lib: &'a Rc<Library>,
}
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 }
}
}
@ -99,23 +103,24 @@ impl<'a> plugin_api::Interface for PluginInterface<'a> {
dispatch_op_fn: plugin_api::DispatchOpFn,
) -> OpId {
let plugin_lib = self.plugin_lib.clone();
self.state.register_op(
name,
move |state: Rc<State>, mut zero_copy: BufVec| {
let mut interface = PluginInterface::new(&state, &plugin_lib);
let op = dispatch_op_fn(&mut interface, &mut zero_copy);
match op {
sync_op @ Op::Sync(..) => sync_op,
Op::Async(fut) => {
Op::Async(PluginOpAsyncFuture::new(&plugin_lib, fut))
}
Op::AsyncUnref(fut) => {
Op::AsyncUnref(PluginOpAsyncFuture::new(&plugin_lib, fut))
}
_ => unreachable!(),
let plugin_op_fn = move |state_rc: Rc<RefCell<OpState>>,
mut zero_copy: BufVec| {
let mut state = state_rc.borrow_mut();
let mut interface = PluginInterface::new(&mut state, &plugin_lib);
let op = dispatch_op_fn(&mut interface, &mut zero_copy);
match op {
sync_op @ Op::Sync(..) => sync_op,
Op::Async(fut) => Op::Async(PluginOpAsyncFuture::new(&plugin_lib, fut)),
Op::AsyncUnref(fut) => {
Op::AsyncUnref(PluginOpAsyncFuture::new(&plugin_lib, fut))
}
},
)
_ => 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 crate::signal::kill;
use crate::state::State;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use futures::future::poll_fn;
use futures::future::FutureExt;
use serde_derive::Deserialize;
use serde_json::Value;
use std::cell::RefCell;
use std::rc::Rc;
use tokio::process::Command;
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
pub fn init(s: &Rc<State>) {
s.register_op_json_sync("op_run", op_run);
s.register_op_json_async("op_run_status", op_run_status);
s.register_op_json_sync("op_kill", op_kill);
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_run", op_run);
super::reg_json_async(rt, "op_run_status", op_run_status);
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 {
Ok(std_file) => std_file.try_clone().map_err(ErrBox::from),
Err(_) => Err(ErrBox::bad_resource_id()),
@ -58,13 +58,12 @@ struct ChildResource {
}
fn op_run(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
let run_args: RunArgs = serde_json::from_value(args)?;
state.check_run()?;
super::cli_state(state).check_run()?;
let args = run_args.cmd;
let env = run_args.env;
@ -111,7 +110,7 @@ fn op_run(
let stdin_rid = match child.stdin.take() {
Some(child_stdin) => {
let rid = state.resource_table.borrow_mut().add(
let rid = state.resource_table.add(
"childStdin",
Box::new(StreamResourceHolder::new(StreamResource::ChildStdin(
child_stdin,
@ -124,7 +123,7 @@ fn op_run(
let stdout_rid = match child.stdout.take() {
Some(child_stdout) => {
let rid = state.resource_table.borrow_mut().add(
let rid = state.resource_table.add(
"childStdout",
Box::new(StreamResourceHolder::new(StreamResource::ChildStdout(
child_stdout,
@ -137,7 +136,7 @@ fn op_run(
let stderr_rid = match child.stderr.take() {
Some(child_stderr) => {
let rid = state.resource_table.borrow_mut().add(
let rid = state.resource_table.add(
"childStderr",
Box::new(StreamResourceHolder::new(StreamResource::ChildStderr(
child_stderr,
@ -149,10 +148,7 @@ fn op_run(
};
let child_resource = ChildResource { child };
let child_rid = state
.resource_table
.borrow_mut()
.add("child", Box::new(child_resource));
let child_rid = state.resource_table.add("child", Box::new(child_resource));
Ok(json!({
"rid": child_rid,
@ -170,18 +166,19 @@ struct RunStatusArgs {
}
async fn op_run_status(
state: Rc<State>,
state: Rc<RefCell<OpState>>,
args: Value,
_zero_copy: BufVec,
) -> Result<Value, ErrBox> {
let args: RunStatusArgs = serde_json::from_value(args)?;
let rid = args.rid as u32;
state.check_run()?;
super::cli_state2(&state).check_run()?;
let run_status = poll_fn(|cx| {
let mut resource_table = state.resource_table.borrow_mut();
let child_resource = resource_table
let mut state = state.borrow_mut();
let child_resource = state
.resource_table
.get_mut::<ChildResource>(rid)
.ok_or_else(ErrBox::bad_resource_id)?;
let child = &mut child_resource.child;
@ -215,12 +212,13 @@ struct KillArgs {
}
fn op_kill(
state: &State,
state: &mut OpState,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
state.check_unstable("Deno.kill");
state.check_run()?;
let cli_state = super::cli_state(state);
cli_state.check_unstable("Deno.kill");
cli_state.check_run()?;
let args: KillArgs = serde_json::from_value(args)?;
kill(args.pid, args.signo)?;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,6 @@ use crate::global_state::GlobalState;
use crate::ops::io::get_stdio;
use crate::permissions::Permissions;
use crate::startup_data;
use crate::state::State;
use crate::tokio_util::create_basic_runtime;
use crate::web_worker::WebWorker;
use crate::web_worker::WebWorkerHandle;
@ -13,21 +12,26 @@ use crate::worker::WorkerEvent;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::ModuleSpecifier;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use futures::future::FutureExt;
use serde_derive::Deserialize;
use serde_json::Value;
use std::cell::RefCell;
use std::convert::From;
use std::rc::Rc;
use std::sync::Arc;
use std::thread::JoinHandle;
pub fn init(s: &Rc<State>) {
s.register_op_json_sync("op_create_worker", op_create_worker);
s.register_op_json_sync("op_host_terminate_worker", op_host_terminate_worker);
s.register_op_json_sync("op_host_post_message", op_host_post_message);
s.register_op_json_async("op_host_get_message", op_host_get_message);
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_create_worker", op_create_worker);
super::reg_json_sync(
rt,
"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(
@ -38,27 +42,31 @@ fn create_web_worker(
specifier: ModuleSpecifier,
has_deno_namespace: bool,
) -> Result<WebWorker, ErrBox> {
let state =
State::new_for_worker(global_state, Some(permissions), specifier)?;
let cli_state = crate::state::State::new_for_worker(
global_state,
Some(permissions),
specifier,
)?;
let mut worker = WebWorker::new(
name.clone(),
startup_data::deno_isolate_init(),
&state,
&cli_state,
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();
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 {
resource_table.add("stdout", Box::new(stream));
state.resource_table.add("stdout", Box::new(stream));
}
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
fn op_create_worker(
state: &State,
state: &mut OpState,
args: Value,
_data: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
let cli_state = super::cli_state(state);
let args: CreateWorkerArgs = serde_json::from_value(args)?;
let specifier = args.specifier.clone();
@ -187,12 +196,12 @@ fn op_create_worker(
let args_name = args.name;
let use_deno_namespace = args.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 permissions = state.permissions.borrow().clone();
let worker_id = state.next_worker_id.get();
state.next_worker_id.set(worker_id + 1);
let global_state = cli_state.global_state.clone();
let permissions = cli_state.permissions.borrow().clone();
let worker_id = cli_state.next_worker_id.get();
cli_state.next_worker_id.set(worker_id + 1);
let module_specifier = ModuleSpecifier::resolve_url(&specifier)?;
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
// safe handler returned from previous function call
state
let cli_state = super::cli_state(state);
cli_state
.workers
.borrow_mut()
.insert(worker_id, (join_handle, worker_handle));
@ -222,13 +232,14 @@ struct WorkerArgs {
}
fn op_host_terminate_worker(
state: &State,
state: &mut OpState,
args: Value,
_data: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
let args: WorkerArgs = serde_json::from_value(args)?;
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
.borrow_mut()
.remove(&id)
@ -290,40 +301,41 @@ fn serialize_worker_event(event: WorkerEvent) -> Value {
/// Get message from guest worker as host
async fn op_host_get_message(
state: Rc<State>,
state: Rc<RefCell<OpState>>,
args: Value,
_zero_copy: BufVec,
) -> Result<Value, ErrBox> {
let args: WorkerArgs = serde_json::from_value(args)?;
let id = args.id as u32;
let state = state.clone();
let cli_state = super::cli_state2(&state);
let workers_table = state.workers.borrow();
let maybe_handle = workers_table.get(&id);
let worker_handle = if let Some(handle) = maybe_handle {
handle.1.clone()
} else {
// If handle was not found it means worker has already shutdown
return Ok(json!({ "type": "close" }));
let worker_handle = {
let workers_table = cli_state.workers.borrow();
let maybe_handle = workers_table.get(&id);
if let Some(handle) = maybe_handle {
handle.1.clone()
} else {
// 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? {
Some(event) => {
// Terminal error means that worker should be removed from worker table.
if let WorkerEvent::TerminalError(_) = &event {
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();
join_handle.join().expect("Worker thread panicked");
}
};
}
serialize_worker_event(event)
}
None => {
// 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
// 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) {
@ -338,7 +350,7 @@ async fn op_host_get_message(
/// Post message to guest worker as host
fn op_host_post_message(
state: &State,
state: &mut OpState,
args: Value,
data: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
@ -348,7 +360,8 @@ fn op_host_post_message(
let msg = Vec::from(&*data[0]).into_boxed_slice();
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();
worker_handle.post_message(msg)?;
Ok(json!({}))

View file

@ -1,6 +1,5 @@
// 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::global_state::GlobalState;
use crate::global_timer::GlobalTimer;
@ -10,17 +9,10 @@ use crate::metrics::Metrics;
use crate::permissions::Permissions;
use crate::tsc::TargetLib;
use crate::web_worker::WebWorkerHandle;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::ModuleLoadId;
use deno_core::ModuleLoader;
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;
use rand::rngs::StdRng;
@ -36,6 +28,7 @@ use std::sync::Arc;
use std::thread::JoinHandle;
use std::time::Instant;
// TODO(ry) Rename to CliState to avoid confusion with other states.
#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
pub struct State {
pub global_state: Arc<GlobalState>,
@ -54,8 +47,6 @@ pub struct State {
pub is_main: bool,
pub is_internal: bool,
pub http_client: RefCell<reqwest::Client>,
pub resource_table: RefCell<ResourceTable>,
pub op_table: RefCell<OpTable<Self>>,
}
impl State {
@ -202,8 +193,6 @@ impl State {
is_main: true,
is_internal,
http_client: create_http_client(fl.ca_file.as_deref())?.into(),
resource_table: Default::default(),
op_table: Default::default(),
};
Ok(Rc::new(state))
}
@ -232,8 +221,6 @@ impl State {
is_main: false,
is_internal: false,
http_client: create_http_client(fl.ca_file.as_deref())?.into(),
resource_table: Default::default(),
op_table: Default::default(),
};
Ok(Rc::new(state))
}
@ -331,78 +318,3 @@ impl State {
.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,
state: &Rc<State>,
) -> 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));
{
ops::runtime::init(&state);
ops::errors::init(&state);
ops::timers::init(&state);
ops::compiler::init(&state, response.clone());
}
ops::runtime::init(&mut worker);
ops::errors::init(&mut worker);
ops::timers::init(&mut worker);
ops::compiler::init(&mut worker, response.clone());
Self { worker, response }
}

View file

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

View file

@ -91,7 +91,7 @@ fn create_channels() -> (WorkerChannelsInternal, WorkerHandle) {
/// - `WebWorker`
pub struct Worker {
pub name: String,
pub isolate: deno_core::JsRuntime,
pub isolate: JsRuntime,
pub inspector: Option<Box<DenoInspector>>,
pub state: Rc<State>,
pub waker: AtomicWaker,
@ -105,22 +105,22 @@ impl Worker {
startup_data: StartupData,
state: &Rc<State>,
) -> Self {
let mut isolate = deno_core::JsRuntime::new_with_loader(
state.clone(),
state.clone(),
startup_data,
false,
);
let mut isolate =
JsRuntime::new_with_loader(state.clone(), startup_data, false);
{
let global_state = state.global_state.clone();
let core_state_rc = JsRuntime::state(&isolate);
let mut core_state = core_state_rc.borrow_mut();
core_state.set_js_error_create_fn(move |core_js_error| {
let js_runtime_state = JsRuntime::state(&isolate);
let mut js_runtime_state = js_runtime_state.borrow_mut();
js_runtime_state.set_js_error_create_fn(move |core_js_error| {
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 global_state = &state.global_state;
global_state
@ -235,7 +235,7 @@ impl Future for Worker {
}
impl Deref for Worker {
type Target = deno_core::JsRuntime;
type Target = JsRuntime;
fn deref(&self) -> &Self::Target {
&self.isolate
}
@ -258,30 +258,30 @@ pub struct MainWorker(Worker);
impl MainWorker {
// TODO(ry) combine MainWorker::new and MainWorker::create.
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_compiler::init(&state);
ops::errors::init(&state);
ops::fetch::init(&state);
ops::websocket::init(&state);
ops::fs::init(&state);
ops::fs_events::init(&state);
ops::idna::init(&state);
ops::io::init(&state);
ops::plugin::init(&state);
ops::net::init(&state);
ops::tls::init(&state);
ops::os::init(&state);
ops::permissions::init(&state);
ops::process::init(&state);
ops::random::init(&state);
ops::repl::init(&state);
ops::resources::init(&state);
ops::signal::init(&state);
ops::timers::init(&state);
ops::tty::init(&state);
ops::worker_host::init(&state);
ops::runtime::init(&mut worker);
ops::runtime_compiler::init(&mut worker);
ops::errors::init(&mut worker);
ops::fetch::init(&mut worker);
ops::websocket::init(&mut worker);
ops::fs::init(&mut worker);
ops::fs_events::init(&mut worker);
ops::idna::init(&mut worker);
ops::io::init(&mut worker);
ops::plugin::init(&mut worker);
ops::net::init(&mut worker);
ops::tls::init(&mut worker);
ops::os::init(&mut worker);
ops::permissions::init(&mut worker);
ops::process::init(&mut worker);
ops::random::init(&mut worker);
ops::repl::init(&mut worker);
ops::resources::init(&mut worker);
ops::signal::init(&mut worker);
ops::timers::init(&mut worker);
ops::tty::init(&mut worker);
ops::worker_host::init(&mut worker);
}
Self(worker)
}
@ -303,7 +303,9 @@ impl MainWorker {
&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();
if let Some(stream) = stdin {
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::Op;
use crate::OpId;
use crate::OpTable;
use crate::ZeroCopyBuf;
use futures::future::FutureExt;
use rusty_v8 as v8;
@ -426,8 +427,7 @@ fn send<'s>(
}
};
let op_router = state.op_router.clone();
let op = op_router.route_op(op_id, bufs);
let op = OpTable::route_op(op_id, state.op_state.clone(), bufs);
assert_eq!(state.shared.size(), 0);
match op {
Op::Sync(buf) if !buf.is_empty() => {

View file

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

View file

@ -2,17 +2,17 @@
extern crate log;
use deno_core::js_check;
use deno_core::BasicState;
use deno_core::BufVec;
use deno_core::ErrBox;
use deno_core::JsRuntime;
use deno_core::OpRegistry;
use deno_core::OpState;
use deno_core::Script;
use deno_core::StartupData;
use deno_core::ZeroCopyBuf;
use futures::future::poll_fn;
use futures::future::Future;
use serde_json::Value;
use std::cell::RefCell;
use std::convert::TryInto;
use std::env;
use std::net::SocketAddr;
@ -42,23 +42,21 @@ impl log::Log for Logger {
}
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 {
source: include_str!("http_bench_json_ops.js"),
filename: "http_bench_json_ops.js",
});
JsRuntime::new(state, startup_data, false)
let mut runtime = JsRuntime::new(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(
state: &BasicState,
state: &mut OpState,
_args: Value,
_bufs: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
@ -66,15 +64,12 @@ fn op_listen(
let addr = "127.0.0.1:4544".parse::<SocketAddr>().unwrap();
let std_listener = std::net::TcpListener::bind(&addr)?;
let listener = TcpListener::from_std(std_listener)?;
let rid = state
.resource_table
.borrow_mut()
.add("tcpListener", Box::new(listener));
let rid = state.resource_table.add("tcpListener", Box::new(listener));
Ok(serde_json::json!({ "rid": rid }))
}
fn op_close(
state: &BasicState,
state: &mut OpState,
args: Value,
_buf: &mut [ZeroCopyBuf],
) -> Result<Value, ErrBox> {
@ -86,17 +81,15 @@ fn op_close(
.try_into()
.unwrap();
debug!("close rid={}", rid);
state
.resource_table
.borrow_mut()
.close(rid)
.map(|_| serde_json::json!(()))
.ok_or_else(ErrBox::bad_resource_id)
}
fn op_accept(
state: Rc<BasicState>,
state: Rc<RefCell<OpState>>,
args: Value,
_bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> {
@ -110,7 +103,8 @@ fn op_accept(
debug!("accept rid={}", rid);
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
.get_mut::<TcpListener>(rid)
.ok_or_else(ErrBox::bad_resource_id)?;
@ -122,7 +116,7 @@ fn op_accept(
}
fn op_read(
state: Rc<BasicState>,
state: Rc<RefCell<OpState>>,
args: Value,
mut bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> {
@ -138,7 +132,8 @@ fn op_read(
debug!("read rid={}", rid);
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
.get_mut::<TcpStream>(rid)
.ok_or_else(ErrBox::bad_resource_id)?;
@ -149,7 +144,7 @@ fn op_read(
}
fn op_write(
state: Rc<BasicState>,
state: Rc<RefCell<OpState>>,
args: Value,
bufs: BufVec,
) -> impl Future<Output = Result<Value, ErrBox>> {
@ -165,7 +160,8 @@ fn op_write(
debug!("write rid={}", rid);
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
.get_mut::<TcpStream>(rid)
.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]
extern crate log;
mod basic_state;
mod bindings;
mod errors;
mod flags;
mod gotham_state;
mod module_specifier;
mod modules;
mod normalize_path;
@ -24,7 +24,6 @@ mod zero_copy_buf;
pub use rusty_v8 as v8;
pub use crate::basic_state::BasicState;
pub use crate::errors::AnyError;
pub use crate::errors::ErrBox;
pub use crate::errors::JsError;
@ -38,12 +37,13 @@ pub use crate::modules::ModuleSource;
pub use crate::modules::ModuleSourceFuture;
pub use crate::modules::RecursiveModuleLoad;
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::OpAsyncFuture;
pub use crate::ops::OpFn;
pub use crate::ops::OpId;
pub use crate::ops::OpRegistry;
pub use crate::ops::OpRouter;
pub use crate::ops::OpState;
pub use crate::ops::OpTable;
pub use crate::resources::ResourceTable;
pub use crate::runtime::js_check;

View file

@ -441,7 +441,6 @@ impl Modules {
mod tests {
use super::*;
use crate::js_check;
use crate::BasicState;
use crate::JsRuntime;
use crate::StartupData;
use futures::future::FutureExt;
@ -620,12 +619,8 @@ mod tests {
fn test_recursive_load() {
let loader = MockLoader::new();
let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader(
loader,
BasicState::new(),
StartupData::None,
false,
);
let mut runtime =
JsRuntime::new_with_loader(loader, StartupData::None, false);
let spec = ModuleSpecifier::resolve_url("file:///a.js").unwrap();
let a_id_fut = runtime.load_module(&spec, None);
let a_id = futures::executor::block_on(a_id_fut).expect("Failed to load");
@ -687,12 +682,8 @@ mod tests {
fn test_circular_load() {
let loader = MockLoader::new();
let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader(
loader,
BasicState::new(),
StartupData::None,
false,
);
let mut runtime =
JsRuntime::new_with_loader(loader, StartupData::None, false);
let fut = async move {
let spec = ModuleSpecifier::resolve_url("file:///circular1.js").unwrap();
@ -765,12 +756,8 @@ mod tests {
fn test_redirect_load() {
let loader = MockLoader::new();
let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader(
loader,
BasicState::new(),
StartupData::None,
false,
);
let mut runtime =
JsRuntime::new_with_loader(loader, StartupData::None, false);
let fut = async move {
let spec = ModuleSpecifier::resolve_url("file:///redirect1.js").unwrap();
@ -834,12 +821,8 @@ mod tests {
run_in_task(|mut cx| {
let loader = MockLoader::new();
let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader(
loader,
BasicState::new(),
StartupData::None,
false,
);
let mut runtime =
JsRuntime::new_with_loader(loader, StartupData::None, false);
let spec = ModuleSpecifier::resolve_url("file:///main.js").unwrap();
let mut recursive_load = runtime.load_module(&spec, None).boxed_local();
@ -884,12 +867,8 @@ mod tests {
fn loader_disappears_after_error() {
run_in_task(|mut cx| {
let loader = MockLoader::new();
let mut runtime = JsRuntime::new_with_loader(
loader,
BasicState::new(),
StartupData::None,
false,
);
let mut runtime =
JsRuntime::new_with_loader(loader, StartupData::None, false);
let spec = ModuleSpecifier::resolve_url("file:///bad_import.js").unwrap();
let mut load_fut = runtime.load_module(&spec, None).boxed_local();
let result = load_fut.poll_unpin(&mut cx);
@ -917,12 +896,8 @@ mod tests {
fn recursive_load_main_with_code() {
let loader = MockLoader::new();
let loads = loader.loads.clone();
let mut runtime = JsRuntime::new_with_loader(
loader,
BasicState::new(),
StartupData::None,
false,
);
let mut runtime =
JsRuntime::new_with_loader(loader, StartupData::None, false);
// In default resolution code should be empty.
// Instead we explicitly pass in our own code.
// 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.
use crate::gotham_state::GothamState;
use crate::BufVec;
use crate::ErrBox;
use crate::ZeroCopyBuf;
use futures::Future;
use futures::FutureExt;
use indexmap::IndexMap;
use serde_json::json;
use serde_json::Value;
use std::cell::RefCell;
use std::collections::HashMap;
use std::iter::once;
use std::ops::Deref;
@ -16,7 +16,7 @@ use std::pin::Pin;
use std::rc::Rc;
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 enum Op {
@ -28,119 +28,191 @@ pub enum Op {
NotFound,
}
pub trait OpRouter {
fn route_op(self: Rc<Self>, op_id: OpId, bufs: BufVec) -> Op;
pub struct OpState {
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 {
fn get_op_catalog(self: Rc<Self>) -> HashMap<String, OpId>;
impl Default for OpState {
// 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
where
F: Fn(Rc<Self>, BufVec) -> Op + 'static;
impl Deref for OpState {
type Target = GothamState;
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
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 result = serde_json::from_slice(&bufs[0])
.map_err(ErrBox::from)
.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)
let (op_id, prev) = self.0.insert_full(name.to_owned(), Rc::new(op_fn));
assert!(prev.is_none());
op_id
}
fn register_op_json_async<F, R>(self: &Rc<Self>, name: &str, op_fn: F) -> OpId
where
F: Fn(Rc<Self>, Value, BufVec) -> R + 'static,
R: Future<Output = Result<Value, ErrBox>> + 'static,
pub fn route_op(
op_id: OpId,
state: Rc<RefCell<OpState>>,
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>,
bufs: BufVec|
-> Result<Op, ErrBox> {
let op_table = &mut state.borrow_mut().op_table;
foo_id = op_table.register_op("foo", |_, _| Op::Sync(b"oof!"[..].into()));
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 promise_id = args
.get("promiseId")
.and_then(Value::as_u64)
.ok_or_else(|| ErrBox::type_error("missing or invalid `promiseId`"))?;
let bufs = bufs[1..].into();
use crate::futures::FutureExt;
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)))
};
let base_op_fn = move |state: Rc<Self>, bufs: BufVec| -> Op {
match try_dispatch_op(state.clone(), bufs) {
Ok(op) => op,
Err(err) => Op::Sync(state.json_serialize_op_result(None, Err(err))),
Box::new(move |state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
match try_dispatch_op(state.clone(), bufs) {
Ok(op) => op,
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)
}
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
}
}),
};
serde_json::to_vec(&value).unwrap().into_boxed_slice()
}

View file

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

View file

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