diff --git a/cli/ops/dispatch_json.rs b/cli/ops/dispatch_json.rs index 031e10c51b..e28c32382a 100644 --- a/cli/ops/dispatch_json.rs +++ b/cli/ops/dispatch_json.rs @@ -119,15 +119,3 @@ where } } } - -pub fn blocking_json(is_sync: bool, f: F) -> Result -where - F: 'static + Send + FnOnce() -> JsonResult, -{ - if is_sync { - Ok(JsonOp::Sync(f()?)) - } else { - let fut = async move { tokio::task::spawn_blocking(f).await.unwrap() }; - Ok(JsonOp::Async(fut.boxed_local())) - } -} diff --git a/cli/ops/errors.rs b/cli/ops/errors.rs index b9405fe541..558f9af2a4 100644 --- a/cli/ops/errors.rs +++ b/cli/ops/errors.rs @@ -1,23 +1,26 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::diagnostics::Diagnostic; use crate::source_maps::get_orig_position; use crate::source_maps::CachedMaps; use crate::state::State; use deno_core::CoreIsolate; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use std::collections::HashMap; use std::rc::Rc; pub fn init(i: &mut CoreIsolate, s: &Rc) { + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + i.register_op( "op_apply_source_map", - s.stateful_json_op(op_apply_source_map), + s.stateful_json_op_sync(t, op_apply_source_map), ); i.register_op( "op_format_diagnostic", - s.stateful_json_op(op_format_diagnostic), + s.stateful_json_op_sync(t, op_format_diagnostic), ); } @@ -30,10 +33,11 @@ struct ApplySourceMap { } fn op_apply_source_map( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: ApplySourceMap = serde_json::from_value(args)?; let mut mappings_map: CachedMaps = HashMap::new(); @@ -46,18 +50,19 @@ fn op_apply_source_map( &state.global_state.ts_compiler, ); - Ok(JsonOp::Sync(json!({ + Ok(json!({ "fileName": orig_file_name, "lineNumber": orig_line_number as u32, "columnNumber": orig_column_number as u32, - }))) + })) } fn op_format_diagnostic( - _state: &Rc, + _state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let diagnostic = serde_json::from_value::(args)?; - Ok(JsonOp::Sync(json!(diagnostic.to_string()))) + Ok(json!(diagnostic.to_string())) } diff --git a/cli/ops/fetch.rs b/cli/ops/fetch.rs index c7bfaf9f17..aea7bc7fcd 100644 --- a/cli/ops/fetch.rs +++ b/cli/ops/fetch.rs @@ -1,26 +1,29 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use super::io::{StreamResource, StreamResourceHolder}; use crate::http_util::{create_http_client, HttpBody}; use crate::state::State; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; -use futures::future::FutureExt; use http::header::HeaderName; use http::header::HeaderValue; use http::Method; use reqwest::Client; +use std::cell::RefCell; use std::convert::From; use std::path::PathBuf; use std::rc::Rc; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_fetch", s.stateful_json_op2(op_fetch)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_fetch", s.stateful_json_op_async(t, op_fetch)); i.register_op( "op_create_http_client", - s.stateful_json_op2(op_create_http_client), + s.stateful_json_op_sync(t, op_create_http_client), ); } @@ -33,25 +36,25 @@ struct FetchArgs { client_rid: Option, } -pub fn op_fetch( - isolate_state: &mut CoreIsolateState, - state: &Rc, +async fn op_fetch( + state: Rc, + resource_table: Rc>, args: Value, - data: &mut [ZeroCopyBuf], -) -> Result { + data: BufVec, +) -> Result { let args: FetchArgs = serde_json::from_value(args)?; let url = args.url; - let resource_table_ = isolate_state.resource_table.borrow(); + let resource_table2 = resource_table.clone(); - let mut client_ref_mut; let client = if let Some(rid) = args.client_rid { + let resource_table_ = resource_table.borrow(); let r = resource_table_ .get::(rid) .ok_or_else(ErrBox::bad_resource_id)?; - &r.client + r.client.clone() } else { - client_ref_mut = state.http_client.borrow_mut(); - &mut *client_ref_mut + let client_ref = state.http_client.borrow_mut(); + client_ref.clone() }; let method = match args.method { @@ -87,36 +90,32 @@ pub fn op_fetch( } debug!("Before fetch {}", url); - let resource_table = isolate_state.resource_table.clone(); - let future = async move { - let res = request.send().await?; - debug!("Fetch response {}", url); - let status = res.status(); - let mut res_headers = Vec::new(); - for (key, val) in res.headers().iter() { - res_headers.push((key.to_string(), val.to_str().unwrap().to_owned())); - } + let res = request.send().await?; - let body = HttpBody::from(res); - let mut resource_table = resource_table.borrow_mut(); - let rid = resource_table.add( - "httpBody", - Box::new(StreamResourceHolder::new(StreamResource::HttpBody( - Box::new(body), - ))), - ); + debug!("Fetch response {}", url); + let status = res.status(); + let mut res_headers = Vec::new(); + for (key, val) in res.headers().iter() { + res_headers.push((key.to_string(), val.to_str().unwrap().to_owned())); + } - let json_res = json!({ - "bodyRid": rid, - "status": status.as_u16(), - "statusText": status.canonical_reason().unwrap_or(""), - "headers": res_headers - }); + let body = HttpBody::from(res); + let mut resource_table = resource_table2.borrow_mut(); + let rid = resource_table.add( + "httpBody", + Box::new(StreamResourceHolder::new(StreamResource::HttpBody( + Box::new(body), + ))), + ); - Ok(json_res) - }; + let json_res = json!({ + "bodyRid": rid, + "status": status.as_u16(), + "statusText": status.canonical_reason().unwrap_or(""), + "headers": res_headers + }); - Ok(JsonOp::Async(future.boxed_local())) + Ok(json_res) } struct HttpClientResource { @@ -137,13 +136,12 @@ struct CreateHttpClientOptions { } fn op_create_http_client( - isolate_state: &mut CoreIsolateState, - state: &Rc, + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: CreateHttpClientOptions = serde_json::from_value(args)?; - let mut resource_table = isolate_state.resource_table.borrow_mut(); if let Some(ca_file) = args.ca_file.clone() { state.check_read(&PathBuf::from(ca_file))?; @@ -153,5 +151,5 @@ fn op_create_http_client( let rid = resource_table.add("httpClient", Box::new(HttpClientResource::new(client))); - Ok(JsonOp::Sync(json!(rid))) + Ok(json!(rid)) } diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs index 28b2a7e55c..3b8946057d 100644 --- a/cli/ops/fs.rs +++ b/cli/ops/fs.rs @@ -1,21 +1,20 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Some deserializer fields are only used on Unix and Windows build fails without it -use super::dispatch_json::{blocking_json, Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use super::io::std_file_resource; use super::io::{FileMetadata, StreamResource, StreamResourceHolder}; use crate::ops::dispatch_json::JsonResult; use crate::state::State; use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; -use futures::future::FutureExt; use std::cell::RefCell; use std::convert::From; use std::env::{current_dir, set_current_dir, temp_dir}; use std::io; +use std::io::{Seek, SeekFrom}; use std::path::{Path, PathBuf}; use std::rc::Rc; use std::time::SystemTime; @@ -29,30 +28,157 @@ pub fn init(i: &mut CoreIsolate, s: &Rc) { i.register_op("op_open_sync", s.stateful_json_op_sync(t, op_open_sync)); i.register_op("op_open_async", s.stateful_json_op_async(t, op_open_async)); - i.register_op("op_seek", s.stateful_json_op2(op_seek)); - i.register_op("op_fdatasync", s.stateful_json_op2(op_fdatasync)); - i.register_op("op_fsync", s.stateful_json_op2(op_fsync)); - i.register_op("op_fstat", s.stateful_json_op2(op_fstat)); - i.register_op("op_umask", s.stateful_json_op(op_umask)); - i.register_op("op_chdir", s.stateful_json_op(op_chdir)); - i.register_op("op_mkdir", s.stateful_json_op(op_mkdir)); - i.register_op("op_chmod", s.stateful_json_op(op_chmod)); - i.register_op("op_chown", s.stateful_json_op(op_chown)); - i.register_op("op_remove", s.stateful_json_op(op_remove)); - i.register_op("op_copy_file", s.stateful_json_op(op_copy_file)); - i.register_op("op_stat", s.stateful_json_op(op_stat)); - i.register_op("op_realpath", s.stateful_json_op(op_realpath)); - i.register_op("op_read_dir", s.stateful_json_op(op_read_dir)); - i.register_op("op_rename", s.stateful_json_op(op_rename)); - i.register_op("op_link", s.stateful_json_op(op_link)); - i.register_op("op_symlink", s.stateful_json_op(op_symlink)); - i.register_op("op_read_link", s.stateful_json_op(op_read_link)); - i.register_op("op_ftruncate", s.stateful_json_op2(op_ftruncate)); - i.register_op("op_truncate", s.stateful_json_op(op_truncate)); - i.register_op("op_make_temp_dir", s.stateful_json_op(op_make_temp_dir)); - i.register_op("op_make_temp_file", s.stateful_json_op(op_make_temp_file)); - i.register_op("op_cwd", s.stateful_json_op(op_cwd)); - i.register_op("op_utime", s.stateful_json_op(op_utime)); + i.register_op("op_seek_sync", s.stateful_json_op_sync(t, op_seek_sync)); + i.register_op("op_seek_async", s.stateful_json_op_async(t, op_seek_async)); + + i.register_op( + "op_fdatasync_sync", + s.stateful_json_op_sync(t, op_fdatasync_sync), + ); + i.register_op( + "op_fdatasync_async", + s.stateful_json_op_async(t, op_fdatasync_async), + ); + + i.register_op("op_fsync_sync", s.stateful_json_op_sync(t, op_fsync_sync)); + i.register_op( + "op_fsync_async", + s.stateful_json_op_async(t, op_fsync_async), + ); + + i.register_op("op_fstat_sync", s.stateful_json_op_sync(t, op_fstat_sync)); + i.register_op( + "op_fstat_async", + s.stateful_json_op_async(t, op_fstat_async), + ); + + i.register_op("op_umask", s.stateful_json_op_sync(t, op_umask)); + i.register_op("op_chdir", s.stateful_json_op_sync(t, op_chdir)); + + i.register_op("op_mkdir_sync", s.stateful_json_op_sync(t, op_mkdir_sync)); + i.register_op( + "op_mkdir_async", + s.stateful_json_op_async(t, op_mkdir_async), + ); + + i.register_op("op_chmod_sync", s.stateful_json_op_sync(t, op_chmod_sync)); + i.register_op( + "op_chmod_async", + s.stateful_json_op_async(t, op_chmod_async), + ); + + i.register_op("op_chown_sync", s.stateful_json_op_sync(t, op_chown_sync)); + i.register_op( + "op_chown_async", + s.stateful_json_op_async(t, op_chown_async), + ); + + i.register_op("op_remove_sync", s.stateful_json_op_sync(t, op_remove_sync)); + i.register_op( + "op_remove_async", + s.stateful_json_op_async(t, op_remove_async), + ); + + i.register_op( + "op_copy_file_sync", + s.stateful_json_op_sync(t, op_copy_file_sync), + ); + i.register_op( + "op_copy_file_async", + s.stateful_json_op_async(t, op_copy_file_async), + ); + + i.register_op("op_stat_sync", s.stateful_json_op_sync(t, op_stat_sync)); + i.register_op("op_stat_async", s.stateful_json_op_async(t, op_stat_async)); + + i.register_op( + "op_realpath_sync", + s.stateful_json_op_sync(t, op_realpath_sync), + ); + i.register_op( + "op_realpath_async", + s.stateful_json_op_async(t, op_realpath_async), + ); + + i.register_op( + "op_read_dir_sync", + s.stateful_json_op_sync(t, op_read_dir_sync), + ); + i.register_op( + "op_read_dir_async", + s.stateful_json_op_async(t, op_read_dir_async), + ); + + i.register_op("op_rename_sync", s.stateful_json_op_sync(t, op_rename_sync)); + i.register_op( + "op_rename_async", + s.stateful_json_op_async(t, op_rename_async), + ); + + i.register_op("op_link_sync", s.stateful_json_op_sync(t, op_link_sync)); + i.register_op("op_link_async", s.stateful_json_op_async(t, op_link_async)); + + i.register_op( + "op_symlink_sync", + s.stateful_json_op_sync(t, op_symlink_sync), + ); + i.register_op( + "op_symlink_async", + s.stateful_json_op_async(t, op_symlink_async), + ); + + i.register_op( + "op_read_link_sync", + s.stateful_json_op_sync(t, op_read_link_sync), + ); + i.register_op( + "op_read_link_async", + s.stateful_json_op_async(t, op_read_link_async), + ); + + i.register_op( + "op_ftruncate_sync", + s.stateful_json_op_sync(t, op_ftruncate_sync), + ); + i.register_op( + "op_ftruncate_async", + s.stateful_json_op_async(t, op_ftruncate_async), + ); + + i.register_op( + "op_truncate_sync", + s.stateful_json_op_sync(t, op_truncate_sync), + ); + i.register_op( + "op_truncate_async", + s.stateful_json_op_async(t, op_truncate_async), + ); + + i.register_op( + "op_make_temp_dir_sync", + s.stateful_json_op_sync(t, op_make_temp_dir_sync), + ); + i.register_op( + "op_make_temp_dir_async", + s.stateful_json_op_async(t, op_make_temp_dir_async), + ); + + i.register_op( + "op_make_temp_file_sync", + s.stateful_json_op_sync(t, op_make_temp_file_sync), + ); + i.register_op( + "op_make_temp_file_async", + s.stateful_json_op_async(t, op_make_temp_file_async), + ); + + i.register_op("op_cwd", s.stateful_json_op_sync(t, op_cwd)); + + i.register_op("op_utime_sync", s.stateful_json_op_sync(t, op_utime_sync)); + i.register_op( + "op_utime_async", + s.stateful_json_op_async(t, op_utime_async), + ); } fn into_string(s: std::ffi::OsString) -> Result { @@ -165,19 +291,12 @@ async fn op_open_async( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct SeekArgs { - promise_id: Option, rid: i32, offset: i64, whence: i32, } -fn op_seek( - isolate_state: &mut CoreIsolateState, - _state: &Rc, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { - use std::io::{Seek, SeekFrom}; +fn seek_helper(args: Value) -> Result<(u32, SeekFrom), ErrBox> { let args: SeekArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let offset = args.offset; @@ -192,154 +311,171 @@ fn op_seek( } }; - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); + Ok((rid, seek_from)) +} - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - let pos = std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot seek on this type of resource")), - })?; - Ok(JsonOp::Sync(json!(pos))) - } else { - // TODO(ry) This is a fake async op. We need to use poll_fn, - // tokio::fs::File::start_seek and tokio::fs::File::poll_complete - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - let pos = std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), - Err(_) => { - Err(ErrBox::type_error("cannot seek on this type of resource")) - } - })?; - Ok(json!(pos)) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +fn op_seek_sync( + _state: &State, + resource_table: &mut ResourceTable, + args: Value, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result { + let (rid, seek_from) = seek_helper(args)?; + let pos = std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot seek on this type of resource".to_string(), + )), + })?; + Ok(json!(pos)) +} + +async fn op_seek_async( + _state: Rc, + resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let (rid, seek_from) = seek_helper(args)?; + // TODO(ry) This is a fake async op. We need to use poll_fn, + // tokio::fs::File::start_seek and tokio::fs::File::poll_complete + let mut resource_table = resource_table.borrow_mut(); + let pos = std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.seek(seek_from).map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot seek on this type of resource".to_string(), + )), + })?; + Ok(json!(pos)) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FdatasyncArgs { - promise_id: Option, rid: i32, } -fn op_fdatasync( - isolate_state: &mut CoreIsolateState, - state: &Rc, +fn op_fdatasync_sync( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.fdatasync"); let args: FdatasyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; + std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) +} - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); - - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot sync this type of resource")), - })?; - Ok(JsonOp::Sync(json!({}))) - } else { - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot sync this type of resource")), - })?; - Ok(json!({})) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +async fn op_fdatasync_async( + state: Rc, + resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + state.check_unstable("Deno.fdatasync"); + let args: FdatasyncArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let mut resource_table = resource_table.borrow_mut(); + std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.sync_data().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FsyncArgs { - promise_id: Option, rid: i32, } -fn op_fsync( - isolate_state: &mut CoreIsolateState, - state: &Rc, +fn op_fsync_sync( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.fsync"); let args: FsyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; + std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) +} - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); - - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot sync this type of resource")), - })?; - Ok(JsonOp::Sync(json!({}))) - } else { - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot sync this type of resource")), - })?; - Ok(json!({})) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +async fn op_fsync_async( + state: Rc, + resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + state.check_unstable("Deno.fsync"); + let args: FsyncArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let mut resource_table = resource_table.borrow_mut(); + std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.sync_all().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot sync this type of resource".to_string(), + )), + })?; + Ok(json!({})) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FstatArgs { - promise_id: Option, rid: i32, } -fn op_fstat( - isolate_state: &mut CoreIsolateState, - state: &Rc, +fn op_fstat_sync( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.fstat"); let args: FstatArgs = serde_json::from_value(args)?; let rid = args.rid as u32; + let metadata = std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.metadata().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot stat this type of resource".to_string(), + )), + })?; + Ok(get_stat_json(metadata).unwrap()) +} - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); - - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - let metadata = std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.metadata().map_err(ErrBox::from), - Err(_) => Err(ErrBox::type_error("cannot stat this type of resource")), - })?; - Ok(JsonOp::Sync(get_stat_json(metadata).unwrap())) - } else { - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - let metadata = - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.metadata().map_err(ErrBox::from), - Err(_) => { - Err(ErrBox::type_error("cannot stat this type of resource")) - } - })?; - Ok(get_stat_json(metadata).unwrap()) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +async fn op_fstat_async( + state: Rc, + resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + state.check_unstable("Deno.fstat"); + let args: FstatArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let mut resource_table = resource_table.borrow_mut(); + let metadata = std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.metadata().map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error( + "cannot stat this type of resource".to_string(), + )), + })?; + Ok(get_stat_json(metadata).unwrap()) } #[derive(Deserialize)] @@ -348,10 +484,11 @@ struct UmaskArgs { } fn op_umask( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.umask"); let args: UmaskArgs = serde_json::from_value(args)?; // TODO implement umask for Windows @@ -376,7 +513,7 @@ fn op_umask( let _ = umask(prev); prev }; - Ok(JsonOp::Sync(json!(r.bits() as u32))) + Ok(json!(r.bits() as u32)) } } @@ -386,39 +523,59 @@ struct ChdirArgs { } fn op_chdir( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: ChdirArgs = serde_json::from_value(args)?; let d = PathBuf::from(&args.directory); state.check_read(&d)?; set_current_dir(&d)?; - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct MkdirArgs { - promise_id: Option, path: String, recursive: bool, mode: Option, } -fn op_mkdir( - state: &Rc, +fn op_mkdir_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: MkdirArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); let mode = args.mode.unwrap_or(0o777) & 0o777; - state.check_write(&path)?; + debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); + let mut builder = std::fs::DirBuilder::new(); + builder.recursive(args.recursive); + #[cfg(unix)] + { + use std::os::unix::fs::DirBuilderExt; + builder.mode(mode); + } + builder.create(path)?; + Ok(json!({})) +} - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { +async fn op_mkdir_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: MkdirArgs = serde_json::from_value(args)?; + let path = Path::new(&args.path).to_path_buf(); + let mode = args.mode.unwrap_or(0o777) & 0o777; + state.check_write(&path)?; + tokio::task::spawn_blocking(move || { debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); let mut builder = std::fs::DirBuilder::new(); builder.recursive(args.recursive); @@ -430,30 +587,57 @@ fn op_mkdir( builder.create(path)?; Ok(json!({})) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ChmodArgs { - promise_id: Option, path: String, mode: u32, } -fn op_chmod( - state: &Rc, +fn op_chmod_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: ChmodArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); let mode = args.mode & 0o777; state.check_write(&path)?; + debug!("op_chmod_sync {} {:o}", path.display(), mode); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let permissions = PermissionsExt::from_mode(mode); + std::fs::set_permissions(&path, permissions)?; + Ok(json!({})) + } + // TODO Implement chmod for Windows (#4357) + #[cfg(not(unix))] + { + // Still check file/dir exists on Windows + let _metadata = std::fs::metadata(&path)?; + Err(ErrBox::error("Not implemented")) + } +} - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_chmod {} {:o}", path.display(), mode); +async fn op_chmod_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: ChmodArgs = serde_json::from_value(args)?; + let path = Path::new(&args.path).to_path_buf(); + let mode = args.mode & 0o777; + state.check_write(&path)?; + tokio::task::spawn_blocking(move || { + debug!("op_chmod_async {} {:o}", path.display(), mode); #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; @@ -469,30 +653,64 @@ fn op_chmod( Err(ErrBox::not_supported()) } }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ChownArgs { - promise_id: Option, path: String, uid: Option, gid: Option, } -fn op_chown( - state: &Rc, +fn op_chown_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: ChownArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); - state.check_write(&path)?; + debug!( + "op_chown_sync {} {:?} {:?}", + path.display(), + args.uid, + args.gid, + ); + #[cfg(unix)] + { + use nix::unistd::{chown, Gid, Uid}; + let nix_uid = args.uid.map(Uid::from_raw); + let nix_gid = args.gid.map(Gid::from_raw); + chown(&path, nix_uid, nix_gid)?; + Ok(json!({})) + } + // TODO Implement chown for Windows + #[cfg(not(unix))] + { + Err(ErrBox::error("Not implemented")) + } +} - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_chown {} {:?} {:?}", path.display(), args.uid, args.gid,); +async fn op_chown_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: ChownArgs = serde_json::from_value(args)?; + let path = Path::new(&args.path).to_path_buf(); + state.check_write(&path)?; + tokio::task::spawn_blocking(move || { + debug!( + "op_chown_async {} {:?} {:?}", + path.display(), + args.uid, + args.gid, + ); #[cfg(unix)] { use nix::unistd::{chown, Gid, Uid}; @@ -505,35 +723,80 @@ fn op_chown( #[cfg(not(unix))] Err(ErrBox::not_supported()) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct RemoveArgs { - promise_id: Option, path: String, recursive: bool, } -fn op_remove( - state: &Rc, +fn op_remove_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: RemoveArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let recursive = args.recursive; state.check_write(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { + #[cfg(not(unix))] + use std::os::windows::prelude::MetadataExt; + + let metadata = std::fs::symlink_metadata(&path)?; + + debug!("op_remove_sync {} {}", path.display(), recursive); + let file_type = metadata.file_type(); + if file_type.is_file() { + std::fs::remove_file(&path)?; + } else if recursive { + std::fs::remove_dir_all(&path)?; + } else if file_type.is_symlink() { + #[cfg(unix)] + std::fs::remove_file(&path)?; + #[cfg(not(unix))] + { + use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; + if metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 { + std::fs::remove_dir(&path)?; + } else { + std::fs::remove_file(&path)?; + } + } + } else if file_type.is_dir() { + std::fs::remove_dir(&path)?; + } else { + // pipes, sockets, etc... + std::fs::remove_file(&path)?; + } + Ok(json!({})) +} + +async fn op_remove_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: RemoveArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + let recursive = args.recursive; + + state.check_write(&path)?; + + tokio::task::spawn_blocking(move || { #[cfg(not(unix))] use std::os::windows::prelude::MetadataExt; let metadata = std::fs::symlink_metadata(&path)?; - debug!("op_remove {} {}", path.display(), recursive); + debug!("op_remove_async {} {}", path.display(), recursive); let file_type = metadata.file_type(); if file_type.is_file() { std::fs::remove_file(&path)?; @@ -559,21 +822,23 @@ fn op_remove( } Ok(json!({})) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct CopyFileArgs { - promise_id: Option, from: String, to: String, } -fn op_copy_file( - state: &Rc, +fn op_copy_file_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: CopyFileArgs = serde_json::from_value(args)?; let from = PathBuf::from(&args.from); let to = PathBuf::from(&args.to); @@ -581,9 +846,34 @@ fn op_copy_file( state.check_read(&from)?; state.check_write(&to)?; - debug!("op_copy_file {} {}", from.display(), to.display()); - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { + debug!("op_copy_file_sync {} {}", from.display(), to.display()); + // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput + // See https://github.com/rust-lang/rust/issues/54800 + // Once the issue is resolved, we should remove this workaround. + if cfg!(unix) && !from.is_file() { + return Err(ErrBox::new("NotFound", "File not found")); + } + + // returns size of from as u64 (we ignore) + std::fs::copy(&from, &to)?; + Ok(json!({})) +} + +async fn op_copy_file_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: CopyFileArgs = serde_json::from_value(args)?; + let from = PathBuf::from(&args.from); + let to = PathBuf::from(&args.to); + + state.check_read(&from)?; + state.check_write(&to)?; + + debug!("op_copy_file_async {} {}", from.display(), to.display()); + tokio::task::spawn_blocking(move || { // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput // See https://github.com/rust-lang/rust/issues/54800 // Once the issue is resolved, we should remove this workaround. @@ -595,6 +885,8 @@ fn op_copy_file( std::fs::copy(&from, &to)?; Ok(json!({})) }) + .await + .unwrap() } fn to_msec(maybe_time: Result) -> serde_json::Value { @@ -658,25 +950,43 @@ fn get_stat_json(metadata: std::fs::Metadata) -> JsonResult { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct StatArgs { - promise_id: Option, path: String, lstat: bool, } -fn op_stat( - state: &Rc, +fn op_stat_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { + let args: StatArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + let lstat = args.lstat; + state.check_read(&path)?; + debug!("op_stat_sync {} {}", path.display(), lstat); + let metadata = if lstat { + std::fs::symlink_metadata(&path)? + } else { + std::fs::metadata(&path)? + }; + get_stat_json(metadata) +} + +async fn op_stat_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { let args: StatArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let lstat = args.lstat; state.check_read(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_stat {} {}", path.display(), lstat); + tokio::task::spawn_blocking(move || { + debug!("op_stat_async {} {}", path.display(), lstat); let metadata = if lstat { std::fs::symlink_metadata(&path)? } else { @@ -684,20 +994,22 @@ fn op_stat( }; get_stat_json(metadata) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct RealpathArgs { - promise_id: Option, path: String, } -fn op_realpath( - state: &Rc, +fn op_realpath_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: RealpathArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); @@ -706,9 +1018,34 @@ fn op_realpath( state.check_read_blind(¤t_dir()?, "CWD")?; } - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_realpath {}", path.display()); + debug!("op_realpath_sync {}", path.display()); + // corresponds to the realpath on Unix and + // CreateFile and GetFinalPathNameByHandle on Windows + let realpath = std::fs::canonicalize(&path)?; + let mut realpath_str = + into_string(realpath.into_os_string())?.replace("\\", "/"); + if cfg!(windows) { + realpath_str = realpath_str.trim_start_matches("//?/").to_string(); + } + Ok(json!(realpath_str)) +} + +async fn op_realpath_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: RealpathArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + + state.check_read(&path)?; + if path.is_relative() { + state.check_read_blind(¤t_dir()?, "CWD")?; + } + + tokio::task::spawn_blocking(move || { + debug!("op_realpath_async {}", path.display()); // corresponds to the realpath on Unix and // CreateFile and GetFinalPathNameByHandle on Windows let realpath = std::fs::canonicalize(&path)?; @@ -719,28 +1056,62 @@ fn op_realpath( } Ok(json!(realpath_str)) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ReadDirArgs { - promise_id: Option, path: String, } -fn op_read_dir( - state: &Rc, +fn op_read_dir_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: ReadDirArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); state.check_read(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_read_dir {}", path.display()); + debug!("op_read_dir_sync {}", path.display()); + let entries: Vec<_> = std::fs::read_dir(path)? + .filter_map(|entry| { + let entry = entry.unwrap(); + let file_type = entry.file_type().unwrap(); + // Not all filenames can be encoded as UTF-8. Skip those for now. + if let Ok(name) = into_string(entry.file_name()) { + Some(json!({ + "name": name, + "isFile": file_type.is_file(), + "isDirectory": file_type.is_dir(), + "isSymlink": file_type.is_symlink() + })) + } else { + None + } + }) + .collect(); + + Ok(json!({ "entries": entries })) +} + +async fn op_read_dir_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: ReadDirArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + + state.check_read(&path)?; + + tokio::task::spawn_blocking(move || { + debug!("op_read_dir_async {}", path.display()); let entries: Vec<_> = std::fs::read_dir(path)? .filter_map(|entry| { let entry = entry.unwrap(); @@ -761,21 +1132,41 @@ fn op_read_dir( Ok(json!({ "entries": entries })) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct RenameArgs { - promise_id: Option, oldpath: String, newpath: String, } -fn op_rename( - state: &Rc, +fn op_rename_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { + let args: RenameArgs = serde_json::from_value(args)?; + let oldpath = PathBuf::from(&args.oldpath); + let newpath = PathBuf::from(&args.newpath); + + state.check_read(&oldpath)?; + state.check_write(&oldpath)?; + state.check_write(&newpath)?; + debug!("op_rename_sync {} {}", oldpath.display(), newpath.display()); + std::fs::rename(&oldpath, &newpath)?; + Ok(json!({})) +} + +async fn op_rename_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { let args: RenameArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); @@ -784,27 +1175,32 @@ fn op_rename( state.check_write(&oldpath)?; state.check_write(&newpath)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_rename {} {}", oldpath.display(), newpath.display()); + tokio::task::spawn_blocking(move || { + debug!( + "op_rename_async {} {}", + oldpath.display(), + newpath.display() + ); std::fs::rename(&oldpath, &newpath)?; Ok(json!({})) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct LinkArgs { - promise_id: Option, oldpath: String, newpath: String, } -fn op_link( - state: &Rc, +fn op_link_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.link"); let args: LinkArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); @@ -813,18 +1209,37 @@ fn op_link( state.check_read(&oldpath)?; state.check_write(&newpath)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_link {} {}", oldpath.display(), newpath.display()); + debug!("op_link_sync {} {}", oldpath.display(), newpath.display()); + std::fs::hard_link(&oldpath, &newpath)?; + Ok(json!({})) +} + +async fn op_link_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + state.check_unstable("Deno.link"); + let args: LinkArgs = serde_json::from_value(args)?; + let oldpath = PathBuf::from(&args.oldpath); + let newpath = PathBuf::from(&args.newpath); + + state.check_read(&oldpath)?; + state.check_write(&newpath)?; + + tokio::task::spawn_blocking(move || { + debug!("op_link_async {} {}", oldpath.display(), newpath.display()); std::fs::hard_link(&oldpath, &newpath)?; Ok(json!({})) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct SymlinkArgs { - promise_id: Option, oldpath: String, newpath: String, #[cfg(not(unix))] @@ -838,11 +1253,12 @@ struct SymlinkOptions { _type: String, } -fn op_symlink( - state: &Rc, +fn op_symlink_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.symlink"); let args: SymlinkArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); @@ -850,9 +1266,63 @@ fn op_symlink( state.check_write(&newpath)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_symlink {} {}", oldpath.display(), newpath.display()); + debug!( + "op_symlink_sync {} {}", + oldpath.display(), + newpath.display() + ); + #[cfg(unix)] + { + use std::os::unix::fs::symlink; + symlink(&oldpath, &newpath)?; + Ok(json!({})) + } + #[cfg(not(unix))] + { + use std::os::windows::fs::{symlink_dir, symlink_file}; + + match args.options { + Some(options) => match options._type.as_ref() { + "file" => symlink_file(&oldpath, &newpath)?, + "dir" => symlink_dir(&oldpath, &newpath)?, + _ => return Err(ErrBox::type_error("unsupported type")), + }, + None => { + let old_meta = std::fs::metadata(&oldpath); + match old_meta { + Ok(metadata) => { + if metadata.is_file() { + symlink_file(&oldpath, &newpath)? + } else if metadata.is_dir() { + symlink_dir(&oldpath, &newpath)? + } + } + Err(_) => return Err(ErrBox::type_error( + "you must pass a `options` argument for non-existent target path in windows" + .to_string(), + )), + } + } + }; + Ok(json!({})) + } +} + +async fn op_symlink_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + state.check_unstable("Deno.symlink"); + let args: SymlinkArgs = serde_json::from_value(args)?; + let oldpath = PathBuf::from(&args.oldpath); + let newpath = PathBuf::from(&args.newpath); + + state.check_write(&newpath)?; + + tokio::task::spawn_blocking(move || { + debug!("op_symlink_async {} {}", oldpath.display(), newpath.display()); #[cfg(unix)] { use std::os::unix::fs::symlink; @@ -889,106 +1359,141 @@ fn op_symlink( Ok(json!({})) } }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ReadLinkArgs { - promise_id: Option, path: String, } -fn op_read_link( - state: &Rc, +fn op_read_link_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: ReadLinkArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); state.check_read(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_read_link {}", path.display()); + debug!("op_read_link_value {}", path.display()); + let target = std::fs::read_link(&path)?.into_os_string(); + let targetstr = into_string(target)?; + Ok(json!(targetstr)) +} + +async fn op_read_link_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: ReadLinkArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + + state.check_read(&path)?; + + tokio::task::spawn_blocking(move || { + debug!("op_read_link_async {}", path.display()); let target = std::fs::read_link(&path)?.into_os_string(); let targetstr = into_string(target)?; Ok(json!(targetstr)) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct FtruncateArgs { - promise_id: Option, rid: i32, len: i32, } -fn op_ftruncate( - isolate_state: &mut CoreIsolateState, - state: &Rc, +fn op_ftruncate_sync( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.ftruncate"); let args: FtruncateArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let len = args.len as u64; + std_file_resource(resource_table, rid, |r| match r { + Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error("cannot truncate this type of resource")), + })?; + Ok(json!({})) +} - let resource_table = isolate_state.resource_table.clone(); - let is_sync = args.promise_id.is_none(); - - if is_sync { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), - Err(_) => { - Err(ErrBox::type_error("cannot truncate this type of resource")) - } - })?; - Ok(JsonOp::Sync(json!({}))) - } else { - let fut = async move { - let mut resource_table = resource_table.borrow_mut(); - std_file_resource(&mut resource_table, rid, |r| match r { - Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), - Err(_) => { - Err(ErrBox::type_error("cannot truncate this type of resource")) - } - })?; - Ok(json!({})) - }; - Ok(JsonOp::Async(fut.boxed_local())) - } +async fn op_ftruncate_async( + state: Rc, + resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + state.check_unstable("Deno.ftruncate"); + let args: FtruncateArgs = serde_json::from_value(args)?; + let rid = args.rid as u32; + let len = args.len as u64; + let mut resource_table = resource_table.borrow_mut(); + std_file_resource(&mut resource_table, rid, |r| match r { + Ok(std_file) => std_file.set_len(len).map_err(ErrBox::from), + Err(_) => Err(ErrBox::type_error("cannot truncate this type of resource")), + })?; + Ok(json!({})) } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct TruncateArgs { - promise_id: Option, path: String, len: u64, } -fn op_truncate( - state: &Rc, +fn op_truncate_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: TruncateArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let len = args.len; state.check_write(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_truncate {} {}", path.display(), len); + debug!("op_truncate_sync {} {}", path.display(), len); + let f = std::fs::OpenOptions::new().write(true).open(&path)?; + f.set_len(len)?; + Ok(json!({})) +} + +async fn op_truncate_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: TruncateArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + let len = args.len; + + state.check_write(&path)?; + + tokio::task::spawn_blocking(move || { + debug!("op_truncate_async {} {}", path.display(), len); let f = std::fs::OpenOptions::new().write(true).open(&path)?; f.set_len(len)?; Ok(json!({})) }) + .await + .unwrap() } fn make_temp( @@ -1039,17 +1544,17 @@ fn make_temp( #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct MakeTempArgs { - promise_id: Option, dir: Option, prefix: Option, suffix: Option, } -fn op_make_temp_dir( - state: &Rc, +fn op_make_temp_dir_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: MakeTempArgs = serde_json::from_value(args)?; let dir = args.dir.map(|s| PathBuf::from(&s)); @@ -1058,8 +1563,36 @@ fn op_make_temp_dir( state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { + // TODO(piscisaureus): use byte vector for paths, not a string. + // See https://github.com/denoland/deno/issues/627. + // We can't assume that paths are always valid utf8 strings. + let path = make_temp( + // Converting Option to Option<&str> + dir.as_deref(), + prefix.as_deref(), + suffix.as_deref(), + true, + )?; + let path_str = into_string(path.into_os_string())?; + + Ok(json!(path_str)) +} + +async fn op_make_temp_dir_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: MakeTempArgs = serde_json::from_value(args)?; + + let dir = args.dir.map(|s| PathBuf::from(&s)); + let prefix = args.prefix.map(String::from); + let suffix = args.suffix.map(String::from); + + state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + + tokio::task::spawn_blocking(move || { // TODO(piscisaureus): use byte vector for paths, not a string. // See https://github.com/denoland/deno/issues/627. // We can't assume that paths are always valid utf8 strings. @@ -1074,13 +1607,16 @@ fn op_make_temp_dir( Ok(json!(path_str)) }) + .await + .unwrap() } -fn op_make_temp_file( - state: &Rc, +fn op_make_temp_file_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: MakeTempArgs = serde_json::from_value(args)?; let dir = args.dir.map(|s| PathBuf::from(&s)); @@ -1089,8 +1625,36 @@ fn op_make_temp_file( state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { + // TODO(piscisaureus): use byte vector for paths, not a string. + // See https://github.com/denoland/deno/issues/627. + // We can't assume that paths are always valid utf8 strings. + let path = make_temp( + // Converting Option to Option<&str> + dir.as_deref(), + prefix.as_deref(), + suffix.as_deref(), + false, + )?; + let path_str = into_string(path.into_os_string())?; + + Ok(json!(path_str)) +} + +async fn op_make_temp_file_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + let args: MakeTempArgs = serde_json::from_value(args)?; + + let dir = args.dir.map(|s| PathBuf::from(&s)); + let prefix = args.prefix.map(String::from); + let suffix = args.suffix.map(String::from); + + state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + + tokio::task::spawn_blocking(move || { // TODO(piscisaureus): use byte vector for paths, not a string. // See https://github.com/denoland/deno/issues/627. // We can't assume that paths are always valid utf8 strings. @@ -1105,22 +1669,41 @@ fn op_make_temp_file( Ok(json!(path_str)) }) + .await + .unwrap() } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct UtimeArgs { - promise_id: Option, path: String, atime: i64, mtime: i64, } -fn op_utime( - state: &Rc, +fn op_utime_sync( + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { + state.check_unstable("Deno.utime"); + + let args: UtimeArgs = serde_json::from_value(args)?; + let path = PathBuf::from(&args.path); + + state.check_write(&path)?; + debug!("op_utime_sync {} {} {}", args.path, args.atime, args.mtime); + utime::set_file_times(args.path, args.atime, args.mtime)?; + Ok(json!({})) +} + +async fn op_utime_async( + state: Rc, + _resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { state.check_unstable("Deno.utime"); let args: UtimeArgs = serde_json::from_value(args)?; @@ -1128,21 +1711,23 @@ fn op_utime( state.check_write(&path)?; - let is_sync = args.promise_id.is_none(); - blocking_json(is_sync, move || { - debug!("op_utime {} {} {}", args.path, args.atime, args.mtime); + tokio::task::spawn_blocking(move || { + debug!("op_utime_async {} {} {}", args.path, args.atime, args.mtime); utime::set_file_times(args.path, args.atime, args.mtime)?; Ok(json!({})) }) + .await + .unwrap() } fn op_cwd( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let path = current_dir()?; state.check_read_blind(&path, "CWD")?; let path_str = into_string(path.into_os_string())?; - Ok(JsonOp::Sync(json!(path_str))) + Ok(json!(path_str)) } diff --git a/cli/ops/fs_events.rs b/cli/ops/fs_events.rs index e798796be6..e1c98b8dea 100644 --- a/cli/ops/fs_events.rs +++ b/cli/ops/fs_events.rs @@ -1,12 +1,12 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::state::State; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; -use futures::future::FutureExt; use notify::event::Event as NotifyEvent; use notify::Error as NotifyError; use notify::EventKind; @@ -14,14 +14,23 @@ use notify::RecommendedWatcher; use notify::RecursiveMode; use notify::Watcher; use serde::Serialize; +use std::cell::RefCell; use std::convert::From; use std::path::PathBuf; use std::rc::Rc; use tokio::sync::mpsc; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_fs_events_open", s.stateful_json_op2(op_fs_events_open)); - i.register_op("op_fs_events_poll", s.stateful_json_op2(op_fs_events_poll)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op( + "op_fs_events_open", + s.stateful_json_op_sync(t, op_fs_events_open), + ); + i.register_op( + "op_fs_events_poll", + s.stateful_json_op_async(t, op_fs_events_poll), + ); } struct FsEventsResource { @@ -62,12 +71,12 @@ impl From for FsEvent { } } -pub fn op_fs_events_open( - isolate_state: &mut CoreIsolateState, - state: &Rc, +fn op_fs_events_open( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { #[derive(Deserialize)] struct OpenArgs { recursive: bool, @@ -94,24 +103,22 @@ pub fn op_fs_events_open( watcher.watch(path, recursive_mode)?; } let resource = FsEventsResource { watcher, receiver }; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let rid = resource_table.add("fsEvents", Box::new(resource)); - Ok(JsonOp::Sync(json!(rid))) + Ok(json!(rid)) } -pub fn op_fs_events_poll( - isolate_state: &mut CoreIsolateState, - _state: &Rc, +async fn op_fs_events_poll( + _state: Rc, + resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { #[derive(Deserialize)] struct PollArgs { rid: u32, } let PollArgs { rid } = serde_json::from_value(args)?; - let resource_table = isolate_state.resource_table.clone(); - let f = poll_fn(move |cx| { + poll_fn(move |cx| { let mut resource_table = resource_table.borrow_mut(); let watcher = resource_table .get_mut::(rid) @@ -124,6 +131,6 @@ pub fn op_fs_events_poll( Some(Err(err)) => Err(err), None => Ok(json!({ "done": true })), }) - }); - Ok(JsonOp::Async(f.boxed_local())) + }) + .await } diff --git a/cli/ops/idna.rs b/cli/ops/idna.rs index 9585e09776..392eceb249 100644 --- a/cli/ops/idna.rs +++ b/cli/ops/idna.rs @@ -2,16 +2,21 @@ //! https://url.spec.whatwg.org/#idna -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::state::State; use deno_core::CoreIsolate; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use idna::{domain_to_ascii, domain_to_ascii_strict}; use std::rc::Rc; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_domain_to_ascii", s.stateful_json_op(op_domain_to_ascii)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + i.register_op( + "op_domain_to_ascii", + s.stateful_json_op_sync(t, op_domain_to_ascii), + ); } #[derive(Deserialize)] @@ -22,10 +27,11 @@ struct DomainToAscii { } fn op_domain_to_ascii( - _state: &Rc, + _state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: DomainToAscii = serde_json::from_value(args)?; if args.be_strict { domain_to_ascii_strict(args.domain.as_str()) @@ -36,5 +42,5 @@ fn op_domain_to_ascii( let message = format!("Invalid IDNA encoded domain name: {:?}", err); ErrBox::new("URIError", message) }) - .map(|domain| JsonOp::Sync(json!(domain))) + .map(|domain| json!(domain)) } diff --git a/cli/ops/net.rs b/cli/ops/net.rs index d979f44aef..9cb6eb79d3 100644 --- a/cli/ops/net.rs +++ b/cli/ops/net.rs @@ -1,15 +1,15 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use super::io::{StreamResource, StreamResourceHolder}; use crate::resolve_addr::resolve_addr; use crate::state::State; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; -use futures::future::FutureExt; +use std::cell::RefCell; use std::net::Shutdown; use std::net::SocketAddr; use std::rc::Rc; @@ -23,15 +23,20 @@ use tokio::net::UdpSocket; use super::net_unix; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_accept", s.stateful_json_op2(op_accept)); - i.register_op("op_connect", s.stateful_json_op2(op_connect)); - i.register_op("op_shutdown", s.stateful_json_op2(op_shutdown)); - i.register_op("op_listen", s.stateful_json_op2(op_listen)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_accept", s.stateful_json_op_async(t, op_accept)); + i.register_op("op_connect", s.stateful_json_op_async(t, op_connect)); + i.register_op("op_shutdown", s.stateful_json_op_sync(t, op_shutdown)); + i.register_op("op_listen", s.stateful_json_op_sync(t, op_listen)); i.register_op( "op_datagram_receive", - s.stateful_json_op2(op_datagram_receive), + s.stateful_json_op_async(t, op_datagram_receive), + ); + i.register_op( + "op_datagram_send", + s.stateful_json_op_async(t, op_datagram_send), ); - i.register_op("op_datagram_send", s.stateful_json_op2(op_datagram_send)); } #[derive(Deserialize)] @@ -40,75 +45,72 @@ struct AcceptArgs { transport: String, } -fn accept_tcp( - isolate_state: &mut CoreIsolateState, +async fn accept_tcp( + resource_table: Rc>, args: AcceptArgs, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { let rid = args.rid as u32; - let resource_table = isolate_state.resource_table.clone(); - let op = async move { - let accept_fut = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); - let listener_resource = resource_table - .get_mut::(rid) - .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?; - let listener = &mut listener_resource.listener; - match listener.poll_accept(cx).map_err(ErrBox::from) { - Poll::Ready(Ok((stream, addr))) => { - listener_resource.untrack_task(); - Poll::Ready(Ok((stream, addr))) - } - Poll::Pending => { - listener_resource.track_task(cx)?; - Poll::Pending - } - Poll::Ready(Err(e)) => { - listener_resource.untrack_task(); - Poll::Ready(Err(e)) - } - } - }); - let (tcp_stream, _socket_addr) = accept_fut.await?; - let local_addr = tcp_stream.local_addr()?; - let remote_addr = tcp_stream.peer_addr()?; + let accept_fut = poll_fn(|cx| { let mut resource_table = resource_table.borrow_mut(); - let rid = resource_table.add( - "tcpStream", - Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some( - tcp_stream, - )))), - ); - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": "tcp", - }, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": "tcp", + let listener_resource = resource_table + .get_mut::(rid) + .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?; + let listener = &mut listener_resource.listener; + match listener.poll_accept(cx).map_err(ErrBox::from) { + Poll::Ready(Ok((stream, addr))) => { + listener_resource.untrack_task(); + Poll::Ready(Ok((stream, addr))) } - })) - }; - - Ok(JsonOp::Async(op.boxed_local())) + Poll::Pending => { + listener_resource.track_task(cx)?; + Poll::Pending + } + Poll::Ready(Err(e)) => { + listener_resource.untrack_task(); + Poll::Ready(Err(e)) + } + } + }); + let (tcp_stream, _socket_addr) = accept_fut.await?; + let local_addr = tcp_stream.local_addr()?; + let remote_addr = tcp_stream.peer_addr()?; + let mut resource_table = resource_table.borrow_mut(); + let rid = resource_table.add( + "tcpStream", + Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some( + tcp_stream, + )))), + ); + Ok(json!({ + "rid": rid, + "localAddr": { + "hostname": local_addr.ip().to_string(), + "port": local_addr.port(), + "transport": "tcp", + }, + "remoteAddr": { + "hostname": remote_addr.ip().to_string(), + "port": remote_addr.port(), + "transport": "tcp", + } + })) } -fn op_accept( - isolate_state: &mut CoreIsolateState, - _state: &Rc, +async fn op_accept( + _state: Rc, + resource_table: Rc>, args: Value, - zero_copy: &mut [ZeroCopyBuf], -) -> Result { + zero_copy: BufVec, +) -> Result { let args: AcceptArgs = serde_json::from_value(args)?; match args.transport.as_str() { - "tcp" => accept_tcp(isolate_state, args, zero_copy), + "tcp" => accept_tcp(resource_table, args, zero_copy).await, #[cfg(unix)] - "unix" => net_unix::accept_unix(isolate_state, args.rid as u32, zero_copy), + "unix" => { + net_unix::accept_unix(resource_table, args.rid as u32, zero_copy).await + } _ => Err(ErrBox::error(format!( "Unsupported transport protocol {}", args.transport @@ -122,58 +124,53 @@ struct ReceiveArgs { transport: String, } -fn receive_udp( - isolate_state: &mut CoreIsolateState, +async fn receive_udp( + resource_table: Rc>, _state: &Rc, args: ReceiveArgs, - zero_copy: &mut [ZeroCopyBuf], -) -> Result { + zero_copy: BufVec, +) -> Result { assert_eq!(zero_copy.len(), 1, "Invalid number of arguments"); let mut zero_copy = zero_copy[0].clone(); let rid = args.rid as u32; - let resource_table = isolate_state.resource_table.clone(); - - let op = async move { - let receive_fut = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); - let resource = resource_table - .get_mut::(rid) - .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; - let socket = &mut resource.socket; - socket - .poll_recv_from(cx, &mut zero_copy) - .map_err(ErrBox::from) - }); - let (size, remote_addr) = receive_fut.await?; - Ok(json!({ - "size": size, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": "udp", - } - })) - }; - - Ok(JsonOp::Async(op.boxed_local())) + let receive_fut = poll_fn(|cx| { + let mut resource_table = resource_table.borrow_mut(); + let resource = resource_table + .get_mut::(rid) + .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; + let socket = &mut resource.socket; + socket + .poll_recv_from(cx, &mut zero_copy) + .map_err(ErrBox::from) + }); + let (size, remote_addr) = receive_fut.await?; + Ok(json!({ + "size": size, + "remoteAddr": { + "hostname": remote_addr.ip().to_string(), + "port": remote_addr.port(), + "transport": "udp", + } + })) } -fn op_datagram_receive( - isolate_state: &mut CoreIsolateState, - state: &Rc, +async fn op_datagram_receive( + state: Rc, + resource_table: Rc>, args: Value, - zero_copy: &mut [ZeroCopyBuf], -) -> Result { + zero_copy: BufVec, +) -> Result { assert_eq!(zero_copy.len(), 1, "Invalid number of arguments"); let args: ReceiveArgs = serde_json::from_value(args)?; match args.transport.as_str() { - "udp" => receive_udp(isolate_state, state, args, zero_copy), + "udp" => receive_udp(resource_table, &state, args, zero_copy).await, #[cfg(unix)] "unixpacket" => { - net_unix::receive_unix_packet(isolate_state, args.rid as u32, zero_copy) + net_unix::receive_unix_packet(resource_table, args.rid as u32, zero_copy) + .await } _ => Err(ErrBox::error(format!( "Unsupported transport protocol {}", @@ -190,16 +187,15 @@ struct SendArgs { transport_args: ArgsEnum, } -fn op_datagram_send( - isolate_state: &mut CoreIsolateState, - state: &Rc, +async fn op_datagram_send( + state: Rc, + resource_table: Rc>, args: Value, - zero_copy: &mut [ZeroCopyBuf], -) -> Result { + zero_copy: BufVec, +) -> Result { assert_eq!(zero_copy.len(), 1, "Invalid number of arguments"); let zero_copy = zero_copy[0].clone(); - let resource_table = isolate_state.resource_table.clone(); match serde_json::from_value(args)? { SendArgs { rid, @@ -208,7 +204,7 @@ fn op_datagram_send( } if transport == "udp" => { state.check_net(&args.hostname, args.port)?; let addr = resolve_addr(&args.hostname, args.port)?; - let f = poll_fn(move |cx| { + poll_fn(move |cx| { let mut resource_table = resource_table.borrow_mut(); let resource = resource_table .get_mut::(rid as u32) @@ -218,8 +214,8 @@ fn op_datagram_send( .poll_send_to(cx, &zero_copy, &addr) .map_ok(|byte_length| json!(byte_length)) .map_err(ErrBox::from) - }); - Ok(JsonOp::Async(f.boxed_local())) + }) + .await } #[cfg(unix)] SendArgs { @@ -229,22 +225,16 @@ fn op_datagram_send( } if transport == "unixpacket" => { let address_path = net_unix::Path::new(&args.path); state.check_read(&address_path)?; - let op = async move { - let mut resource_table = resource_table.borrow_mut(); - let resource = resource_table - .get_mut::(rid as u32) - .ok_or_else(|| { - ErrBox::new("NotConnected", "Socket has been closed") - })?; - let socket = &mut resource.socket; - let byte_length = socket - .send_to(&zero_copy, &resource.local_addr.as_pathname().unwrap()) - .await?; + let mut resource_table = resource_table.borrow_mut(); + let resource = resource_table + .get_mut::(rid as u32) + .ok_or_else(|| ErrBox::new("NotConnected", "Socket has been closed"))?; + let socket = &mut resource.socket; + let byte_length = socket + .send_to(&zero_copy, &resource.local_addr.as_pathname().unwrap()) + .await?; - Ok(json!(byte_length)) - }; - - Ok(JsonOp::Async(op.boxed_local())) + Ok(json!(byte_length)) } _ => Err(ErrBox::type_error("Wrong argument format!")), } @@ -257,46 +247,42 @@ struct ConnectArgs { transport_args: ArgsEnum, } -fn op_connect( - isolate_state: &mut CoreIsolateState, - state: &Rc, +async fn op_connect( + state: Rc, + resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { - let resource_table = isolate_state.resource_table.clone(); + _zero_copy: BufVec, +) -> Result { match serde_json::from_value(args)? { ConnectArgs { transport, transport_args: ArgsEnum::Ip(args), } if transport == "tcp" => { state.check_net(&args.hostname, args.port)?; - let op = async move { - 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 mut resource_table = resource_table.borrow_mut(); - let rid = resource_table.add( - "tcpStream", - Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some( - tcp_stream, - )))), - ); - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": transport, - }, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": transport, - } - })) - }; - Ok(JsonOp::Async(op.boxed_local())) + 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 mut resource_table = resource_table.borrow_mut(); + let rid = resource_table.add( + "tcpStream", + Box::new(StreamResourceHolder::new(StreamResource::TcpStream(Some( + tcp_stream, + )))), + ); + Ok(json!({ + "rid": rid, + "localAddr": { + "hostname": local_addr.ip().to_string(), + "port": local_addr.port(), + "transport": transport, + }, + "remoteAddr": { + "hostname": remote_addr.ip().to_string(), + "port": remote_addr.port(), + "transport": transport, + } + })) } #[cfg(unix)] ConnectArgs { @@ -306,32 +292,29 @@ fn op_connect( let address_path = net_unix::Path::new(&args.path); state.check_unstable("Deno.connect"); state.check_read(&address_path)?; - let op = async move { - 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 mut resource_table = resource_table.borrow_mut(); - let rid = resource_table.add( - "unixStream", - Box::new(StreamResourceHolder::new(StreamResource::UnixStream( - unix_stream, - ))), - ); - Ok(json!({ - "rid": rid, - "localAddr": { - "path": local_addr.as_pathname(), - "transport": transport, - }, - "remoteAddr": { - "path": remote_addr.as_pathname(), - "transport": transport, - } - })) - }; - Ok(JsonOp::Async(op.boxed_local())) + 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 mut resource_table = resource_table.borrow_mut(); + let rid = resource_table.add( + "unixStream", + Box::new(StreamResourceHolder::new(StreamResource::UnixStream( + unix_stream, + ))), + ); + Ok(json!({ + "rid": rid, + "localAddr": { + "path": local_addr.as_pathname(), + "transport": transport, + }, + "remoteAddr": { + "path": remote_addr.as_pathname(), + "transport": transport, + } + })) } _ => Err(ErrBox::type_error("Wrong argument format!")), } @@ -344,11 +327,11 @@ struct ShutdownArgs { } fn op_shutdown( - isolate_state: &mut CoreIsolateState, - state: &Rc, + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.shutdown"); let args: ShutdownArgs = serde_json::from_value(args)?; @@ -362,7 +345,6 @@ fn op_shutdown( _ => unimplemented!(), }; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let resource_holder = resource_table .get_mut::(rid) .ok_or_else(ErrBox::bad_resource_id)?; @@ -377,7 +359,7 @@ fn op_shutdown( _ => return Err(ErrBox::bad_resource_id()), } - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } #[allow(dead_code)] @@ -485,12 +467,11 @@ fn listen_udp( } fn op_listen( - isolate_state: &mut CoreIsolateState, - state: &Rc, + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { - let mut resource_table = isolate_state.resource_table.borrow_mut(); +) -> Result { match serde_json::from_value(args)? { ListenArgs { transport, @@ -502,9 +483,9 @@ fn op_listen( state.check_net(&args.hostname, args.port)?; let addr = resolve_addr(&args.hostname, args.port)?; let (rid, local_addr) = if transport == "tcp" { - listen_tcp(&mut resource_table, addr)? + listen_tcp(resource_table, addr)? } else { - listen_udp(&mut resource_table, addr)? + listen_udp(resource_table, addr)? }; debug!( "New listener {} {}:{}", @@ -512,14 +493,14 @@ fn op_listen( local_addr.ip().to_string(), local_addr.port() ); - Ok(JsonOp::Sync(json!({ + Ok(json!({ "rid": rid, "localAddr": { "hostname": local_addr.ip().to_string(), "port": local_addr.port(), "transport": transport, }, - }))) + })) } #[cfg(unix)] ListenArgs { @@ -536,22 +517,22 @@ fn op_listen( state.check_read(&address_path)?; state.check_write(&address_path)?; let (rid, local_addr) = if transport == "unix" { - net_unix::listen_unix(&mut resource_table, &address_path)? + net_unix::listen_unix(resource_table, &address_path)? } else { - net_unix::listen_unix_packet(&mut resource_table, &address_path)? + net_unix::listen_unix_packet(resource_table, &address_path)? }; debug!( "New listener {} {}", rid, local_addr.as_pathname().unwrap().display(), ); - Ok(JsonOp::Sync(json!({ + Ok(json!({ "rid": rid, "localAddr": { "path": local_addr.as_pathname(), "transport": transport, }, - }))) + })) } #[cfg(unix)] _ => Err(ErrBox::type_error("Wrong argument format!")), diff --git a/cli/ops/net_unix.rs b/cli/ops/net_unix.rs index e03a7ba87e..29851b093a 100644 --- a/cli/ops/net_unix.rs +++ b/cli/ops/net_unix.rs @@ -1,13 +1,13 @@ -use super::dispatch_json::{Deserialize, JsonOp}; +use super::dispatch_json::{Deserialize, Value}; use super::io::{StreamResource, StreamResourceHolder}; -use deno_core::CoreIsolateState; +use deno_core::BufVec; use deno_core::ErrBox; use deno_core::ResourceTable; -use deno_core::ZeroCopyBuf; -use futures::future::FutureExt; +use std::cell::RefCell; use std::fs::remove_file; use std::os::unix; pub use std::path::Path; +use std::rc::Rc; use tokio::net::UnixDatagram; use tokio::net::UnixListener; pub use tokio::net::UnixStream; @@ -26,80 +26,63 @@ pub struct UnixListenArgs { pub path: String, } -pub fn accept_unix( - isolate_state: &mut CoreIsolateState, +pub async fn accept_unix( + resource_table: Rc>, rid: u32, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { - let resource_table = isolate_state.resource_table.clone(); - { - let _ = resource_table - .borrow() - .get::(rid) - .ok_or_else(ErrBox::bad_resource_id)?; - } - let op = async move { - let mut resource_table_ = resource_table.borrow_mut(); - let listener_resource = { - resource_table_ - .get_mut::(rid) - .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))? - }; - - let (unix_stream, _socket_addr) = - listener_resource.listener.accept().await?; - drop(resource_table_); - - let local_addr = unix_stream.local_addr()?; - let remote_addr = unix_stream.peer_addr()?; - let mut resource_table_ = resource_table.borrow_mut(); - let rid = resource_table_.add( - "unixStream", - Box::new(StreamResourceHolder::new(StreamResource::UnixStream( - unix_stream, - ))), - ); - Ok(json!({ - "rid": rid, - "localAddr": { - "path": local_addr.as_pathname(), - "transport": "unix", - }, - "remoteAddr": { - "path": remote_addr.as_pathname(), - "transport": "unix", - } - })) + _zero_copy: BufVec, +) -> Result { + let mut resource_table_ = resource_table.borrow_mut(); + let listener_resource = { + resource_table_ + .get_mut::(rid) + .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))? }; - Ok(JsonOp::Async(op.boxed_local())) + let (unix_stream, _socket_addr) = listener_resource.listener.accept().await?; + drop(resource_table_); + + let local_addr = unix_stream.local_addr()?; + let remote_addr = unix_stream.peer_addr()?; + let mut resource_table_ = resource_table.borrow_mut(); + let rid = resource_table_.add( + "unixStream", + Box::new(StreamResourceHolder::new(StreamResource::UnixStream( + unix_stream, + ))), + ); + Ok(json!({ + "rid": rid, + "localAddr": { + "path": local_addr.as_pathname(), + "transport": "unix", + }, + "remoteAddr": { + "path": remote_addr.as_pathname(), + "transport": "unix", + } + })) } -pub fn receive_unix_packet( - isolate_state: &mut CoreIsolateState, +pub async fn receive_unix_packet( + resource_table: Rc>, rid: u32, - zero_copy: &mut [ZeroCopyBuf], -) -> Result { + zero_copy: BufVec, +) -> Result { assert_eq!(zero_copy.len(), 1, "Invalid number of arguments"); let mut zero_copy = zero_copy[0].clone(); - let resource_table = isolate_state.resource_table.clone(); - let op = async move { - let mut resource_table_ = resource_table.borrow_mut(); - let resource = resource_table_ - .get_mut::(rid) - .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; - let (size, remote_addr) = resource.socket.recv_from(&mut zero_copy).await?; - Ok(json!({ - "size": size, - "remoteAddr": { - "path": remote_addr.as_pathname(), - "transport": "unixpacket", - } - })) - }; - - Ok(JsonOp::Async(op.boxed_local())) + let mut resource_table_ = resource_table.borrow_mut(); + let resource = resource_table_ + .get_mut::(rid) + .ok_or_else(|| ErrBox::bad_resource("Socket has been closed"))?; + let (size, remote_addr) = resource.socket.recv_from(&mut zero_copy).await?; + Ok(json!({ + "size": size, + "remoteAddr": { + "path": remote_addr.as_pathname(), + "transport": "unixpacket", + } + })) } pub fn listen_unix( diff --git a/cli/ops/os.rs b/cli/ops/os.rs index 1b961164e6..7a2a7155e0 100644 --- a/cli/ops/os.rs +++ b/cli/ops/os.rs @@ -1,8 +1,9 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::state::State; use deno_core::CoreIsolate; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use std::collections::HashMap; use std::env; @@ -10,29 +11,32 @@ use std::rc::Rc; use url::Url; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_exit", s.stateful_json_op(op_exit)); - i.register_op("op_env", s.stateful_json_op(op_env)); - i.register_op("op_exec_path", s.stateful_json_op(op_exec_path)); - i.register_op("op_set_env", s.stateful_json_op(op_set_env)); - i.register_op("op_get_env", s.stateful_json_op(op_get_env)); - i.register_op("op_delete_env", s.stateful_json_op(op_delete_env)); - i.register_op("op_hostname", s.stateful_json_op(op_hostname)); - i.register_op("op_loadavg", s.stateful_json_op(op_loadavg)); - i.register_op("op_os_release", s.stateful_json_op(op_os_release)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_exit", s.stateful_json_op_sync(t, op_exit)); + i.register_op("op_env", s.stateful_json_op_sync(t, op_env)); + i.register_op("op_exec_path", s.stateful_json_op_sync(t, op_exec_path)); + i.register_op("op_set_env", s.stateful_json_op_sync(t, op_set_env)); + i.register_op("op_get_env", s.stateful_json_op_sync(t, op_get_env)); + i.register_op("op_delete_env", s.stateful_json_op_sync(t, op_delete_env)); + i.register_op("op_hostname", s.stateful_json_op_sync(t, op_hostname)); + i.register_op("op_loadavg", s.stateful_json_op_sync(t, op_loadavg)); + i.register_op("op_os_release", s.stateful_json_op_sync(t, op_os_release)); } fn op_exec_path( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let current_exe = env::current_exe().unwrap(); state.check_read_blind(¤t_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(); let path = exe_url.to_file_path().unwrap(); - Ok(JsonOp::Sync(json!(path))) + Ok(json!(path)) } #[derive(Deserialize)] @@ -42,24 +46,26 @@ struct SetEnv { } fn op_set_env( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: SetEnv = serde_json::from_value(args)?; state.check_env()?; env::set_var(args.key, args.value); - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } fn op_env( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_env()?; let v = env::vars().collect::>(); - Ok(JsonOp::Sync(json!(v))) + Ok(json!(v)) } #[derive(Deserialize)] @@ -68,17 +74,18 @@ struct GetEnv { } fn op_get_env( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: GetEnv = serde_json::from_value(args)?; state.check_env()?; let r = match env::var(args.key) { Err(env::VarError::NotPresent) => json!([]), v => json!([v?]), }; - Ok(JsonOp::Sync(r)) + Ok(r) } #[derive(Deserialize)] @@ -87,14 +94,15 @@ struct DeleteEnv { } fn op_delete_env( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: DeleteEnv = serde_json::from_value(args)?; state.check_env()?; env::remove_var(args.key); - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } #[derive(Deserialize)] @@ -103,49 +111,49 @@ struct Exit { } fn op_exit( - _s: &Rc, + _state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: Exit = serde_json::from_value(args)?; std::process::exit(args.code) } fn op_loadavg( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.loadavg"); state.check_env()?; match sys_info::loadavg() { - Ok(loadavg) => Ok(JsonOp::Sync(json!([ - loadavg.one, - loadavg.five, - loadavg.fifteen - ]))), - Err(_) => Ok(JsonOp::Sync(json!([0f64, 0f64, 0f64]))), + Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])), + Err(_) => Ok(json!([0f64, 0f64, 0f64])), } } fn op_hostname( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.hostname"); state.check_env()?; let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string()); - Ok(JsonOp::Sync(json!(hostname))) + Ok(json!(hostname)) } fn op_os_release( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.osRelease"); state.check_env()?; let release = sys_info::os_release().unwrap_or_else(|_| "".to_string()); - Ok(JsonOp::Sync(json!(release))) + Ok(json!(release)) } diff --git a/cli/ops/permissions.rs b/cli/ops/permissions.rs index 6ebabfa5c9..1d19f91d43 100644 --- a/cli/ops/permissions.rs +++ b/cli/ops/permissions.rs @@ -1,24 +1,27 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::state::State; use deno_core::CoreIsolate; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use std::path::Path; use std::rc::Rc; pub fn init(i: &mut CoreIsolate, s: &Rc) { + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + i.register_op( "op_query_permission", - s.stateful_json_op(op_query_permission), + s.stateful_json_op_sync(t, op_query_permission), ); i.register_op( "op_revoke_permission", - s.stateful_json_op(op_revoke_permission), + s.stateful_json_op_sync(t, op_revoke_permission), ); i.register_op( "op_request_permission", - s.stateful_json_op(op_request_permission), + s.stateful_json_op_sync(t, op_request_permission), ); } @@ -30,10 +33,11 @@ struct PermissionArgs { } pub fn op_query_permission( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: PermissionArgs = serde_json::from_value(args)?; let permissions = state.permissions.borrow(); let path = args.path.as_deref(); @@ -52,14 +56,15 @@ pub fn op_query_permission( )) } }; - Ok(JsonOp::Sync(json!({ "state": perm.to_string() }))) + Ok(json!({ "state": perm.to_string() })) } pub fn op_revoke_permission( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: PermissionArgs = serde_json::from_value(args)?; let mut permissions = state.permissions.borrow_mut(); let path = args.path.as_deref(); @@ -78,14 +83,15 @@ pub fn op_revoke_permission( )) } }; - Ok(JsonOp::Sync(json!({ "state": perm.to_string() }))) + Ok(json!({ "state": perm.to_string() })) } pub fn op_request_permission( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: PermissionArgs = serde_json::from_value(args)?; let permissions = &mut state.permissions.borrow_mut(); let path = args.path.as_deref(); @@ -104,5 +110,5 @@ pub fn op_request_permission( )) } }; - Ok(JsonOp::Sync(json!({ "state": perm.to_string() }))) + Ok(json!({ "state": perm.to_string() })) } diff --git a/cli/ops/plugin.rs b/cli/ops/plugin.rs index f06105498d..bd1a0a0022 100644 --- a/cli/ops/plugin.rs +++ b/cli/ops/plugin.rs @@ -2,7 +2,6 @@ use crate::ops::dispatch_json::Deserialize; use crate::ops::dispatch_json::JsonOp; use crate::ops::dispatch_json::Value; -use crate::ops::json_op; use crate::state::State; use deno_core::plugin_api; use deno_core::CoreIsolate; @@ -21,10 +20,7 @@ use std::task::Context; use std::task::Poll; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op( - "op_open_plugin", - s.core_op(json_op(s.stateful_op2(op_open_plugin))), - ); + i.register_op("op_open_plugin", s.stateful_json_op2(op_open_plugin)); } #[derive(Deserialize)] diff --git a/cli/ops/process.rs b/cli/ops/process.rs index 1754812a23..836db08cd4 100644 --- a/cli/ops/process.rs +++ b/cli/ops/process.rs @@ -1,15 +1,16 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use super::io::{std_file_resource, StreamResource, StreamResourceHolder}; use crate::signal::kill; use crate::state::State; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; use futures::future::FutureExt; +use std::cell::RefCell; use std::rc::Rc; use tokio::process::Command; @@ -17,9 +18,11 @@ use tokio::process::Command; use std::os::unix::process::ExitStatusExt; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_run", s.stateful_json_op2(op_run)); - i.register_op("op_run_status", s.stateful_json_op2(op_run_status)); - i.register_op("op_kill", s.stateful_json_op(op_kill)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_run", s.stateful_json_op_sync(t, op_run)); + i.register_op("op_run_status", s.stateful_json_op_async(t, op_run_status)); + i.register_op("op_kill", s.stateful_json_op_sync(t, op_kill)); } fn clone_file( @@ -60,15 +63,14 @@ struct ChildResource { } fn op_run( - isolate_state: &mut CoreIsolateState, - state: &Rc, + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let run_args: RunArgs = serde_json::from_value(args)?; state.check_run()?; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let args = run_args.cmd; let env = run_args.env; @@ -88,21 +90,21 @@ fn op_run( if run_args.stdin != "" { c.stdin(subprocess_stdio_map(run_args.stdin.as_ref())?); } else { - let file = clone_file(run_args.stdin_rid, &mut resource_table)?; + let file = clone_file(run_args.stdin_rid, resource_table)?; c.stdin(file); } if run_args.stdout != "" { c.stdout(subprocess_stdio_map(run_args.stdout.as_ref())?); } else { - let file = clone_file(run_args.stdout_rid, &mut resource_table)?; + let file = clone_file(run_args.stdout_rid, resource_table)?; c.stdout(file); } if run_args.stderr != "" { c.stderr(subprocess_stdio_map(run_args.stderr.as_ref())?); } else { - let file = clone_file(run_args.stderr_rid, &mut resource_table)?; + let file = clone_file(run_args.stderr_rid, resource_table)?; c.stderr(file); } @@ -155,13 +157,13 @@ fn op_run( let child_resource = ChildResource { child }; let child_rid = resource_table.add("child", Box::new(child_resource)); - Ok(JsonOp::Sync(json!({ + Ok(json!({ "rid": child_rid, "pid": pid, "stdinRid": stdin_rid, "stdoutRid": stdout_rid, "stderrRid": stderr_rid, - }))) + })) } #[derive(Deserialize)] @@ -170,49 +172,44 @@ struct RunStatusArgs { rid: i32, } -fn op_run_status( - isolate_state: &mut CoreIsolateState, - state: &Rc, +async fn op_run_status( + state: Rc, + resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { let args: RunStatusArgs = serde_json::from_value(args)?; let rid = args.rid as u32; state.check_run()?; - let resource_table = isolate_state.resource_table.clone(); - let future = async move { - let run_status = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); - let child_resource = resource_table - .get_mut::(rid) - .ok_or_else(ErrBox::bad_resource_id)?; - let child = &mut child_resource.child; - child.poll_unpin(cx).map_err(ErrBox::from) - }) - .await?; + let run_status = poll_fn(|cx| { + let mut resource_table = resource_table.borrow_mut(); + let child_resource = resource_table + .get_mut::(rid) + .ok_or_else(ErrBox::bad_resource_id)?; + let child = &mut child_resource.child; + child.poll_unpin(cx).map_err(ErrBox::from) + }) + .await?; - let code = run_status.code(); + let code = run_status.code(); - #[cfg(unix)] - let signal = run_status.signal(); - #[cfg(not(unix))] - let signal = None; + #[cfg(unix)] + let signal = run_status.signal(); + #[cfg(not(unix))] + let signal = None; - code - .or(signal) - .expect("Should have either an exit code or a signal."); - let got_signal = signal.is_some(); + code + .or(signal) + .expect("Should have either an exit code or a signal."); + let got_signal = signal.is_some(); - Ok(json!({ - "gotSignal": got_signal, - "exitCode": code.unwrap_or(-1), - "exitSignal": signal.unwrap_or(-1), - })) - }; - - Ok(JsonOp::Async(future.boxed_local())) + Ok(json!({ + "gotSignal": got_signal, + "exitCode": code.unwrap_or(-1), + "exitSignal": signal.unwrap_or(-1), + })) } #[derive(Deserialize)] @@ -222,14 +219,15 @@ struct KillArgs { } fn op_kill( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.kill"); state.check_run()?; let args: KillArgs = serde_json::from_value(args)?; kill(args.pid, args.signo)?; - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } diff --git a/cli/ops/random.rs b/cli/ops/random.rs index 3ff5ad49f7..fb2286116e 100644 --- a/cli/ops/random.rs +++ b/cli/ops/random.rs @@ -1,25 +1,29 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{JsonOp, Value}; +use super::dispatch_json::Value; use crate::state::State; use deno_core::CoreIsolate; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use rand::thread_rng; use rand::Rng; use std::rc::Rc; pub fn init(i: &mut CoreIsolate, s: &Rc) { + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + i.register_op( "op_get_random_values", - s.stateful_json_op(op_get_random_values), + s.stateful_json_op_sync(t, op_get_random_values), ); } fn op_get_random_values( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { assert_eq!(zero_copy.len(), 1); if let Some(seeded_rng) = &state.seeded_rng { @@ -29,5 +33,5 @@ fn op_get_random_values( rng.fill(&mut *zero_copy[0]); } - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } diff --git a/cli/ops/repl.rs b/cli/ops/repl.rs index b051dd5748..82fa3e23e8 100644 --- a/cli/ops/repl.rs +++ b/cli/ops/repl.rs @@ -1,19 +1,26 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{blocking_json, Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::repl; use crate::repl::Repl; use crate::state::State; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; +use std::cell::RefCell; use std::rc::Rc; use std::sync::Arc; use std::sync::Mutex; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_repl_start", s.stateful_json_op2(op_repl_start)); - i.register_op("op_repl_readline", s.stateful_json_op2(op_repl_readline)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_repl_start", s.stateful_json_op_sync(t, op_repl_start)); + i.register_op( + "op_repl_readline", + s.stateful_json_op_async(t, op_repl_readline), + ); } struct ReplResource(Arc>); @@ -25,20 +32,19 @@ struct ReplStartArgs { } fn op_repl_start( - isolate_state: &mut CoreIsolateState, - state: &Rc, + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { 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 repl = repl::Repl::new(history_path); let resource = ReplResource(Arc::new(Mutex::new(repl))); - let mut resource_table = isolate_state.resource_table.borrow_mut(); let rid = resource_table.add("repl", Box::new(resource)); - Ok(JsonOp::Sync(json!(rid))) + Ok(json!(rid)) } #[derive(Deserialize)] @@ -47,24 +53,26 @@ struct ReplReadlineArgs { prompt: String, } -fn op_repl_readline( - isolate_state: &mut CoreIsolateState, - _state: &Rc, +async fn op_repl_readline( + _state: Rc, + resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { let args: ReplReadlineArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let prompt = args.prompt; debug!("op_repl_readline {} {}", rid, prompt); - let resource_table = isolate_state.resource_table.borrow(); + let resource_table = resource_table.borrow(); let resource = resource_table .get::(rid) .ok_or_else(ErrBox::bad_resource_id)?; let repl = resource.0.clone(); - - blocking_json(false, move || { + drop(resource_table); + tokio::task::spawn_blocking(move || { let line = repl.lock().unwrap().readline(&prompt)?; Ok(json!(line)) }) + .await + .unwrap() } diff --git a/cli/ops/resources.rs b/cli/ops/resources.rs index fb3c1bc791..0493aeed32 100644 --- a/cli/ops/resources.rs +++ b/cli/ops/resources.rs @@ -1,42 +1,43 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::state::State; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use std::rc::Rc; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_resources", s.stateful_json_op2(op_resources)); - i.register_op("op_close", s.stateful_json_op2(op_close)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_resources", s.stateful_json_op_sync(t, op_resources)); + i.register_op("op_close", s.stateful_json_op_sync(t, op_close)); } fn op_resources( - isolate_state: &mut CoreIsolateState, - _state: &Rc, + _state: &State, + resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { - let serialized_resources = isolate_state.resource_table.borrow().entries(); - Ok(JsonOp::Sync(json!(serialized_resources))) +) -> Result { + let serialized_resources = resource_table.entries(); + Ok(json!(serialized_resources)) } /// op_close removes a resource from the resource table. fn op_close( - isolate_state: &mut CoreIsolateState, - _state: &Rc, + _state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { #[derive(Deserialize)] struct CloseArgs { rid: i32, } let args: CloseArgs = serde_json::from_value(args)?; - let mut resource_table = isolate_state.resource_table.borrow_mut(); resource_table .close(args.rid as u32) .ok_or_else(ErrBox::bad_resource_id)?; - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } diff --git a/cli/ops/runtime.rs b/cli/ops/runtime.rs index 26e1b2a338..119e152c88 100644 --- a/cli/ops/runtime.rs +++ b/cli/ops/runtime.rs @@ -1,5 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{JsonOp, Value}; +use super::dispatch_json::Value; use crate::colors; use crate::state::State; use crate::version; @@ -7,24 +7,28 @@ use crate::DenoSubcommand; use deno_core::CoreIsolate; use deno_core::ErrBox; use deno_core::ModuleSpecifier; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use std::env; use std::rc::Rc; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_start", s.stateful_json_op(op_start)); - i.register_op("op_main_module", s.stateful_json_op(op_main_module)); - i.register_op("op_metrics", s.stateful_json_op(op_metrics)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_start", s.stateful_json_op_sync(t, op_start)); + i.register_op("op_main_module", s.stateful_json_op_sync(t, op_main_module)); + i.register_op("op_metrics", s.stateful_json_op_sync(t, op_metrics)); } fn op_start( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let gs = &state.global_state; - Ok(JsonOp::Sync(json!({ + Ok(json!({ // TODO(bartlomieju): `cwd` field is not used in JS, remove? "args": gs.flags.argv.clone(), "cwd": &env::current_dir().unwrap(), @@ -39,31 +43,33 @@ fn op_start( "unstableFlag": gs.flags.unstable, "v8Version": version::v8(), "versionFlag": gs.flags.version, - }))) + })) } fn op_main_module( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let main = &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")?; } - Ok(JsonOp::Sync(json!(&main))) + Ok(json!(&main)) } fn op_metrics( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let m = &state.metrics.borrow(); - Ok(JsonOp::Sync(json!({ + Ok(json!({ "opsDispatched": m.ops_dispatched, "opsDispatchedSync": m.ops_dispatched_sync, "opsDispatchedAsync": m.ops_dispatched_async, @@ -75,7 +81,7 @@ fn op_metrics( "bytesSentControl": m.bytes_sent_control, "bytesSentData": m.bytes_sent_data, "bytesReceived": m.bytes_received - }))) + })) } fn ppid() -> Value { diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index 3aaaf019db..a5991dabf2 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -1,19 +1,23 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; 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::CoreIsolate; use deno_core::ErrBox; -use deno_core::ZeroCopyBuf; +use deno_core::ResourceTable; +use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_compile", s.stateful_json_op(op_compile)); - i.register_op("op_transpile", s.stateful_json_op(op_transpile)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_compile", s.stateful_json_op_async(t, op_compile)); + i.register_op("op_transpile", s.stateful_json_op_async(t, op_transpile)); } #[derive(Deserialize, Debug)] @@ -25,40 +29,37 @@ struct CompileArgs { options: Option, } -fn op_compile( - state: &Rc, +async fn op_compile( + state: Rc, + _resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _data: BufVec, +) -> Result { 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 fut = async move { - let fut = if args.bundle { - runtime_bundle( - &global_state, - permissions, - &args.root_name, - &args.sources, - &args.options, - ) - .boxed_local() - } else { - runtime_compile( - &global_state, - permissions, - &args.root_name, - &args.sources, - &args.options, - ) - .boxed_local() - }; - - fut.await - } - .boxed_local(); - Ok(JsonOp::Async(fut)) + let fut = if args.bundle { + runtime_bundle( + &global_state, + permissions, + &args.root_name, + &args.sources, + &args.options, + ) + .boxed_local() + } else { + runtime_compile( + &global_state, + permissions, + &args.root_name, + &args.sources, + &args.options, + ) + .boxed_local() + }; + let result = fut.await?; + Ok(result) } #[derive(Deserialize, Debug)] @@ -67,19 +68,18 @@ struct TranspileArgs { options: Option, } -fn op_transpile( - state: &Rc, +async fn op_transpile( + state: Rc, + _resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _data: BufVec, +) -> Result { 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 fut = async move { + let result = runtime_transpile(&global_state, permissions, &args.sources, &args.options) - .await - } - .boxed_local(); - Ok(JsonOp::Async(fut)) + .await?; + Ok(result) } diff --git a/cli/ops/signal.rs b/cli/ops/signal.rs index 3868c6e174..8c0b338b3a 100644 --- a/cli/ops/signal.rs +++ b/cli/ops/signal.rs @@ -1,26 +1,35 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{JsonOp, Value}; +use super::dispatch_json::Value; use crate::state::State; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; +use std::cell::RefCell; use std::rc::Rc; #[cfg(unix)] use super::dispatch_json::Deserialize; #[cfg(unix)] -#[cfg(unix)] -use futures::future::{poll_fn, FutureExt}; +use futures::future::poll_fn; #[cfg(unix)] use std::task::Waker; #[cfg(unix)] use tokio::signal::unix::{signal, Signal, SignalKind}; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_signal_bind", s.stateful_json_op2(op_signal_bind)); - i.register_op("op_signal_unbind", s.stateful_json_op2(op_signal_unbind)); - i.register_op("op_signal_poll", s.stateful_json_op2(op_signal_poll)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_signal_bind", s.stateful_json_op_sync(t, op_signal_bind)); + i.register_op( + "op_signal_unbind", + s.stateful_json_op_sync(t, op_signal_unbind), + ); + i.register_op( + "op_signal_poll", + s.stateful_json_op_async(t, op_signal_poll), + ); } #[cfg(unix)] @@ -42,14 +51,13 @@ struct SignalArgs { #[cfg(unix)] fn op_signal_bind( - isolate_state: &mut CoreIsolateState, - state: &Rc, + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.signal"); let args: BindSignalArgs = serde_json::from_value(args)?; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let rid = resource_table.add( "signal", Box::new(SignalStreamResource( @@ -57,22 +65,21 @@ fn op_signal_bind( None, )), ); - Ok(JsonOp::Sync(json!({ + Ok(json!({ "rid": rid, - }))) + })) } #[cfg(unix)] -fn op_signal_poll( - isolate_state: &mut CoreIsolateState, - state: &Rc, +async fn op_signal_poll( + state: Rc, + resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { state.check_unstable("Deno.signal"); let args: SignalArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - let resource_table = isolate_state.resource_table.clone(); let future = poll_fn(move |cx| { let mut resource_table = resource_table.borrow_mut(); @@ -83,23 +90,21 @@ fn op_signal_poll( return signal.0.poll_recv(cx); } std::task::Poll::Ready(None) - }) - .then(|result| async move { Ok(json!({ "done": result.is_none() })) }); - - Ok(JsonOp::AsyncUnref(future.boxed_local())) + }); + let result = future.await; + Ok(json!({ "done": result.is_none() })) } #[cfg(unix)] pub fn op_signal_unbind( - isolate_state: &mut CoreIsolateState, - state: &Rc, + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.signal"); let args: SignalArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let resource = resource_table.get::(rid); if let Some(signal) = resource { if let Some(waker) = &signal.1 { @@ -111,35 +116,35 @@ pub fn op_signal_unbind( resource_table .close(rid) .ok_or_else(ErrBox::bad_resource_id)?; - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } #[cfg(not(unix))] pub fn op_signal_bind( - _isolate_state: &mut CoreIsolateState, - _state: &Rc, + _state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { unimplemented!(); } #[cfg(not(unix))] fn op_signal_unbind( - _isolate_state: &mut CoreIsolateState, - _state: &Rc, + _state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { unimplemented!(); } #[cfg(not(unix))] -fn op_signal_poll( - _isolate_state: &mut CoreIsolateState, - _state: &Rc, +async fn op_signal_poll( + _state: Rc, + _resource_table: Rc>, _args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { unimplemented!(); } diff --git a/cli/ops/timers.rs b/cli/ops/timers.rs index 379bacf98f..66a9b007b2 100644 --- a/cli/ops/timers.rs +++ b/cli/ops/timers.rs @@ -1,30 +1,39 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::state::State; +use deno_core::BufVec; use deno_core::CoreIsolate; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use futures::future::FutureExt; +use std::cell::RefCell; use std::rc::Rc; use std::time::Duration; use std::time::Instant; pub fn init(i: &mut CoreIsolate, s: &Rc) { + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + i.register_op( "op_global_timer_stop", - s.stateful_json_op(op_global_timer_stop), + s.stateful_json_op_sync(t, op_global_timer_stop), ); - i.register_op("op_global_timer", s.stateful_json_op(op_global_timer)); - i.register_op("op_now", s.stateful_json_op(op_now)); + i.register_op( + "op_global_timer", + s.stateful_json_op_async(t, op_global_timer), + ); + i.register_op("op_now", s.stateful_json_op_sync(t, op_now)); } fn op_global_timer_stop( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.global_timer.borrow_mut().cancel(); - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } #[derive(Deserialize)] @@ -32,22 +41,23 @@ struct GlobalTimerArgs { timeout: u64, } -fn op_global_timer( - state: &Rc, +async fn op_global_timer( + state: Rc, + _resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { let args: GlobalTimerArgs = serde_json::from_value(args)?; let val = args.timeout; let deadline = Instant::now() + Duration::from_millis(val); - let f = state + let timer_fut = state .global_timer .borrow_mut() .new_timeout(deadline) - .then(move |_| futures::future::ok(json!({}))); - - Ok(JsonOp::Async(f.boxed_local())) + .boxed_local(); + let _ = timer_fut.await; + Ok(json!({})) } // Returns a milliseconds and nanoseconds subsec @@ -55,10 +65,11 @@ fn op_global_timer( // If the High precision flag is not set, the // nanoseconds are rounded on 2ms. fn op_now( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let seconds = state.start_time.elapsed().as_secs(); let mut subsec_nanos = state.start_time.elapsed().subsec_nanos(); let reduced_time_precision = 2_000_000; // 2ms in nanoseconds @@ -70,8 +81,8 @@ fn op_now( subsec_nanos -= subsec_nanos % reduced_time_precision; } - Ok(JsonOp::Sync(json!({ + Ok(json!({ "seconds": seconds, "subsecNanos": subsec_nanos, - }))) + })) } diff --git a/cli/ops/tls.rs b/cli/ops/tls.rs index 2d47d8ebee..4a7b9613e7 100644 --- a/cli/ops/tls.rs +++ b/cli/ops/tls.rs @@ -1,14 +1,15 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use super::io::{StreamResource, StreamResourceHolder}; use crate::resolve_addr::resolve_addr; use crate::state::State; +use deno_core::BufVec; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use futures::future::poll_fn; -use futures::future::FutureExt; +use std::cell::RefCell; use std::convert::From; use std::fs::File; use std::io::BufReader; @@ -31,10 +32,15 @@ use tokio_rustls::{ use webpki::DNSNameRef; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_start_tls", s.stateful_json_op2(op_start_tls)); - i.register_op("op_connect_tls", s.stateful_json_op2(op_connect_tls)); - i.register_op("op_listen_tls", s.stateful_json_op2(op_listen_tls)); - i.register_op("op_accept_tls", s.stateful_json_op2(op_accept_tls)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_start_tls", s.stateful_json_op_async(t, op_start_tls)); + i.register_op( + "op_connect_tls", + s.stateful_json_op_async(t, op_connect_tls), + ); + i.register_op("op_listen_tls", s.stateful_json_op_sync(t, op_listen_tls)); + i.register_op("op_accept_tls", s.stateful_json_op_async(t, op_accept_tls)); } #[derive(Deserialize)] @@ -54,17 +60,16 @@ struct StartTLSArgs { hostname: String, } -pub fn op_start_tls( - isolate_state: &mut CoreIsolateState, - state: &Rc, +async fn op_start_tls( + state: Rc, + resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { 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(); - let resource_table = isolate_state.resource_table.clone(); let mut domain = args.hostname; if domain.is_empty() { @@ -76,85 +81,18 @@ pub fn op_start_tls( state.check_read(Path::new(&path))?; } - let op = async move { - let mut resource_holder = { - let mut resource_table_ = resource_table.borrow_mut(); - match resource_table_.remove::(rid) { - Some(resource) => *resource, - None => return Err(ErrBox::bad_resource_id()), - } - }; - - if let StreamResource::TcpStream(ref mut tcp_stream) = - resource_holder.resource - { - let tcp_stream = tcp_stream.take().unwrap(); - let local_addr = tcp_stream.local_addr()?; - let remote_addr = tcp_stream.peer_addr()?; - let mut config = ClientConfig::new(); - config - .root_store - .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); - if let Some(path) = cert_file { - let key_file = File::open(path)?; - let reader = &mut BufReader::new(key_file); - config.root_store.add_pem_file(reader).unwrap(); - } - - let tls_connector = TlsConnector::from(Arc::new(config)); - 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_ = resource_table.borrow_mut(); - let rid = resource_table_.add( - "clientTlsStream", - Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream( - Box::new(tls_stream), - ))), - ); - Ok(json!({ - "rid": rid, - "localAddr": { - "hostname": local_addr.ip().to_string(), - "port": local_addr.port(), - "transport": "tcp", - }, - "remoteAddr": { - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port(), - "transport": "tcp", - } - })) - } else { - Err(ErrBox::bad_resource_id()) + let mut resource_holder = { + let mut resource_table_ = resource_table.borrow_mut(); + match resource_table_.remove::(rid) { + Some(resource) => *resource, + None => return Err(ErrBox::bad_resource_id()), } }; - Ok(JsonOp::Async(op.boxed_local())) -} -pub fn op_connect_tls( - isolate_state: &mut CoreIsolateState, - state: &Rc, - args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { - let args: ConnectTLSArgs = serde_json::from_value(args)?; - let cert_file = args.cert_file.clone(); - let resource_table = isolate_state.resource_table.clone(); - state.check_net(&args.hostname, args.port)?; - if let Some(path) = cert_file.clone() { - state.check_read(Path::new(&path))?; - } - - let mut domain = args.hostname.clone(); - if domain.is_empty() { - domain.push_str("localhost"); - } - - let op = async move { - let addr = resolve_addr(&args.hostname, args.port)?; - let tcp_stream = TcpStream::connect(&addr).await?; + if let StreamResource::TcpStream(ref mut tcp_stream) = + resource_holder.resource + { + let tcp_stream = tcp_stream.take().unwrap(); let local_addr = tcp_stream.local_addr()?; let remote_addr = tcp_stream.peer_addr()?; let mut config = ClientConfig::new(); @@ -166,10 +104,12 @@ pub fn op_connect_tls( let reader = &mut BufReader::new(key_file); config.root_store.add_pem_file(reader).unwrap(); } + let tls_connector = TlsConnector::from(Arc::new(config)); 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_ = resource_table.borrow_mut(); let rid = resource_table_.add( "clientTlsStream", @@ -182,17 +122,74 @@ pub fn op_connect_tls( "localAddr": { "hostname": local_addr.ip().to_string(), "port": local_addr.port(), - "transport": args.transport, + "transport": "tcp", }, "remoteAddr": { "hostname": remote_addr.ip().to_string(), "port": remote_addr.port(), - "transport": args.transport, + "transport": "tcp", } })) - }; + } else { + Err(ErrBox::bad_resource_id()) + } +} - Ok(JsonOp::Async(op.boxed_local())) +async fn op_connect_tls( + state: Rc, + resource_table: Rc>, + args: Value, + _zero_copy: BufVec, +) -> Result { + 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 mut domain = args.hostname.clone(); + if domain.is_empty() { + domain.push_str("localhost"); + } + + 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 mut config = ClientConfig::new(); + config + .root_store + .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); + if let Some(path) = cert_file { + let key_file = File::open(path)?; + let reader = &mut BufReader::new(key_file); + config.root_store.add_pem_file(reader).unwrap(); + } + let tls_connector = TlsConnector::from(Arc::new(config)); + 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_ = resource_table.borrow_mut(); + let rid = resource_table_.add( + "clientTlsStream", + Box::new(StreamResourceHolder::new(StreamResource::ClientTlsStream( + Box::new(tls_stream), + ))), + ); + Ok(json!({ + "rid": rid, + "localAddr": { + "hostname": local_addr.ip().to_string(), + "port": local_addr.port(), + "transport": args.transport, + }, + "remoteAddr": { + "hostname": remote_addr.ip().to_string(), + "port": remote_addr.port(), + "transport": args.transport, + } + })) } fn load_certs(path: &str) -> Result, ErrBox> { @@ -308,11 +305,11 @@ struct ListenTlsArgs { } fn op_listen_tls( - isolate_state: &mut CoreIsolateState, - state: &Rc, + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: ListenTlsArgs = serde_json::from_value(args)?; assert_eq!(args.transport, "tcp"); @@ -339,17 +336,16 @@ fn op_listen_tls( local_addr, }; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let rid = resource_table.add("tlsListener", Box::new(tls_listener_resource)); - Ok(JsonOp::Sync(json!({ + Ok(json!({ "rid": rid, "localAddr": { "hostname": local_addr.ip().to_string(), "port": local_addr.port(), "transport": args.transport, }, - }))) + })) } #[derive(Deserialize)] @@ -357,72 +353,67 @@ struct AcceptTlsArgs { rid: i32, } -fn op_accept_tls( - isolate_state: &mut CoreIsolateState, - _state: &Rc, +async fn op_accept_tls( + _state: Rc, + resource_table: Rc>, args: Value, - _zero_copy: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { let args: AcceptTlsArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - let resource_table = isolate_state.resource_table.clone(); - let op = async move { - let accept_fut = poll_fn(|cx| { - let mut resource_table = resource_table.borrow_mut(); - let listener_resource = resource_table - .get_mut::(rid) - .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?; - let listener = &mut listener_resource.listener; - match listener.poll_accept(cx).map_err(ErrBox::from) { - Poll::Ready(Ok((stream, addr))) => { - listener_resource.untrack_task(); - Poll::Ready(Ok((stream, addr))) - } - Poll::Pending => { - listener_resource.track_task(cx)?; - Poll::Pending - } - Poll::Ready(Err(e)) => { - listener_resource.untrack_task(); - Poll::Ready(Err(e)) - } + let accept_fut = poll_fn(|cx| { + let mut resource_table = resource_table.borrow_mut(); + let listener_resource = resource_table + .get_mut::(rid) + .ok_or_else(|| ErrBox::bad_resource("Listener has been closed"))?; + let listener = &mut listener_resource.listener; + match listener.poll_accept(cx).map_err(ErrBox::from) { + Poll::Ready(Ok((stream, addr))) => { + listener_resource.untrack_task(); + Poll::Ready(Ok((stream, addr))) } - }); - let (tcp_stream, _socket_addr) = accept_fut.await?; - let local_addr = tcp_stream.local_addr()?; - let remote_addr = tcp_stream.peer_addr()?; - let tls_acceptor = { - let resource_table = resource_table.borrow(); - let resource = resource_table - .get::(rid) - .ok_or_else(ErrBox::bad_resource_id) - .expect("Can't find tls listener"); - resource.tls_acceptor.clone() - }; - let tls_stream = tls_acceptor.accept(tcp_stream).await?; - let rid = { - let mut resource_table = resource_table.borrow_mut(); - resource_table.add( - "serverTlsStream", - Box::new(StreamResourceHolder::new(StreamResource::ServerTlsStream( - Box::new(tls_stream), - ))), - ) - }; - Ok(json!({ - "rid": rid, - "localAddr": { - "transport": "tcp", - "hostname": local_addr.ip().to_string(), - "port": local_addr.port() - }, - "remoteAddr": { - "transport": "tcp", - "hostname": remote_addr.ip().to_string(), - "port": remote_addr.port() + Poll::Pending => { + listener_resource.track_task(cx)?; + Poll::Pending } - })) + Poll::Ready(Err(e)) => { + listener_resource.untrack_task(); + Poll::Ready(Err(e)) + } + } + }); + let (tcp_stream, _socket_addr) = accept_fut.await?; + let local_addr = tcp_stream.local_addr()?; + let remote_addr = tcp_stream.peer_addr()?; + let tls_acceptor = { + let resource_table = resource_table.borrow(); + let resource = resource_table + .get::(rid) + .ok_or_else(ErrBox::bad_resource_id) + .expect("Can't find tls listener"); + resource.tls_acceptor.clone() }; - - Ok(JsonOp::Async(op.boxed_local())) + let tls_stream = tls_acceptor.accept(tcp_stream).await?; + let rid = { + let mut resource_table = resource_table.borrow_mut(); + resource_table.add( + "serverTlsStream", + Box::new(StreamResourceHolder::new(StreamResource::ServerTlsStream( + Box::new(tls_stream), + ))), + ) + }; + Ok(json!({ + "rid": rid, + "localAddr": { + "transport": "tcp", + "hostname": local_addr.ip().to_string(), + "port": local_addr.port() + }, + "remoteAddr": { + "transport": "tcp", + "hostname": remote_addr.ip().to_string(), + "port": remote_addr.port() + } + })) } diff --git a/cli/ops/tty.rs b/cli/ops/tty.rs index b62b727c38..bb8ad8714b 100644 --- a/cli/ops/tty.rs +++ b/cli/ops/tty.rs @@ -1,10 +1,10 @@ -use super::dispatch_json::JsonOp; +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use super::io::std_file_resource; use super::io::{StreamResource, StreamResourceHolder}; use crate::state::State; use deno_core::CoreIsolate; -use deno_core::CoreIsolateState; use deno_core::ErrBox; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; #[cfg(unix)] use nix::sys::termios; @@ -37,9 +37,14 @@ fn get_windows_handle( } pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_set_raw", s.stateful_json_op2(op_set_raw)); - i.register_op("op_isatty", s.stateful_json_op2(op_isatty)); - i.register_op("op_console_size", s.stateful_json_op2(op_console_size)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op("op_set_raw", s.stateful_json_op_sync(t, op_set_raw)); + i.register_op("op_isatty", s.stateful_json_op_sync(t, op_isatty)); + i.register_op( + "op_console_size", + s.stateful_json_op_sync(t, op_console_size), + ); } #[derive(Deserialize)] @@ -48,12 +53,12 @@ struct SetRawArgs { mode: bool, } -pub fn op_set_raw( - isolate_state: &mut CoreIsolateState, - state: &Rc, +fn op_set_raw( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.setRaw"); let args: SetRawArgs = serde_json::from_value(args)?; let rid = args.rid; @@ -70,7 +75,6 @@ pub fn op_set_raw( use winapi::shared::minwindef::FALSE; use winapi::um::{consoleapi, handleapi}; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let resource_holder = resource_table.get_mut::(rid); if resource_holder.is_none() { return Err(ErrBox::bad_resource_id()); @@ -130,13 +134,12 @@ pub fn op_set_raw( return Err(ErrBox::last_os_error()); } - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } #[cfg(unix)] { use std::os::unix::io::AsRawFd; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let resource_holder = resource_table.get_mut::(rid); if resource_holder.is_none() { return Err(ErrBox::bad_resource_id()); @@ -161,7 +164,7 @@ pub fn op_set_raw( if maybe_tty_mode.is_some() { // Already raw. Skip. - return Ok(JsonOp::Sync(json!({}))); + return Ok(json!({})); } let original_mode = termios::tcgetattr(raw_fd)?; @@ -184,7 +187,7 @@ pub fn op_set_raw( raw.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1; raw.control_chars[termios::SpecialCharacterIndices::VTIME as usize] = 0; termios::tcsetattr(raw_fd, termios::SetArg::TCSADRAIN, &raw)?; - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } else { // Try restore saved mode. let (raw_fd, maybe_tty_mode) = @@ -207,7 +210,7 @@ pub fn op_set_raw( termios::tcsetattr(raw_fd, termios::SetArg::TCSADRAIN, &mode)?; } - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } } } @@ -217,18 +220,17 @@ struct IsattyArgs { rid: u32, } -pub fn op_isatty( - isolate_state: &mut CoreIsolateState, - _state: &Rc, +fn op_isatty( + _state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: IsattyArgs = serde_json::from_value(args)?; let rid = args.rid; - let mut resource_table = isolate_state.resource_table.borrow_mut(); let isatty: bool = - std_file_resource(&mut resource_table, rid as u32, move |r| match r { + std_file_resource(resource_table, rid as u32, move |r| match r { Ok(std_file) => { #[cfg(windows)] { @@ -250,7 +252,7 @@ pub fn op_isatty( Err(StreamResource::Stdin(..)) => Ok(atty::is(atty::Stream::Stdin)), _ => Ok(false), })?; - Ok(JsonOp::Sync(json!(isatty))) + Ok(json!(isatty)) } #[derive(Deserialize)] @@ -264,65 +266,63 @@ struct ConsoleSize { rows: u32, } -pub fn op_console_size( - isolate_state: &mut CoreIsolateState, - state: &Rc, +fn op_console_size( + state: &State, + resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { state.check_unstable("Deno.consoleSize"); let args: ConsoleSizeArgs = serde_json::from_value(args)?; let rid = args.rid; - let mut resource_table = isolate_state.resource_table.borrow_mut(); - let size = - std_file_resource(&mut resource_table, rid as u32, move |r| match r { - Ok(std_file) => { - #[cfg(windows)] - { - use std::os::windows::io::AsRawHandle; - let handle = std_file.as_raw_handle(); + let size = std_file_resource(resource_table, rid as u32, move |r| match r { + Ok(std_file) => { + #[cfg(windows)] + { + use std::os::windows::io::AsRawHandle; + let handle = std_file.as_raw_handle(); - unsafe { - let mut bufinfo: winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO = - std::mem::zeroed(); + unsafe { + let mut bufinfo: winapi::um::wincon::CONSOLE_SCREEN_BUFFER_INFO = + std::mem::zeroed(); - if winapi::um::wincon::GetConsoleScreenBufferInfo( - handle, - &mut bufinfo, - ) == 0 - { - return Err(ErrBox::last_os_error()); - } - - Ok(ConsoleSize { - columns: bufinfo.dwSize.X as u32, - rows: bufinfo.dwSize.Y as u32, - }) + if winapi::um::wincon::GetConsoleScreenBufferInfo( + handle, + &mut bufinfo, + ) == 0 + { + return Err(ErrBox::last_os_error()); } - } - #[cfg(unix)] - { - use std::os::unix::io::AsRawFd; - - let fd = std_file.as_raw_fd(); - unsafe { - let mut size: libc::winsize = std::mem::zeroed(); - if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) != 0 { - return Err(ErrBox::last_os_error()); - } - - // TODO (caspervonb) return a tuple instead - Ok(ConsoleSize { - columns: size.ws_col as u32, - rows: size.ws_row as u32, - }) - } + Ok(ConsoleSize { + columns: bufinfo.dwSize.X as u32, + rows: bufinfo.dwSize.Y as u32, + }) } } - Err(_) => Err(ErrBox::bad_resource_id()), - })?; - Ok(JsonOp::Sync(json!(size))) + #[cfg(unix)] + { + use std::os::unix::io::AsRawFd; + + let fd = std_file.as_raw_fd(); + unsafe { + let mut size: libc::winsize = std::mem::zeroed(); + if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) != 0 { + return Err(ErrBox::last_os_error()); + } + + // TODO (caspervonb) return a tuple instead + Ok(ConsoleSize { + columns: size.ws_col as u32, + rows: size.ws_row as u32, + }) + } + } + } + Err(_) => Err(ErrBox::bad_resource_id()), + })?; + + Ok(json!(size)) } diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs index 4cd55fef1a..35ec11223c 100644 --- a/cli/ops/worker_host.rs +++ b/cli/ops/worker_host.rs @@ -1,5 +1,5 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use super::dispatch_json::{Deserialize, JsonOp, Value}; +use super::dispatch_json::{Deserialize, Value}; use crate::fmt_errors::JSError; use crate::global_state::GlobalState; use crate::ops::io::get_stdio; @@ -10,29 +10,37 @@ use crate::tokio_util::create_basic_runtime; use crate::web_worker::WebWorker; use crate::web_worker::WebWorkerHandle; use crate::worker::WorkerEvent; +use deno_core::BufVec; use deno_core::CoreIsolate; use deno_core::ErrBox; use deno_core::ModuleSpecifier; +use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use futures::future::FutureExt; +use std::cell::RefCell; use std::convert::From; use std::rc::Rc; use std::sync::Arc; use std::thread::JoinHandle; pub fn init(i: &mut CoreIsolate, s: &Rc) { - i.register_op("op_create_worker", s.stateful_json_op(op_create_worker)); + let t = &CoreIsolate::state(i).borrow().resource_table.clone(); + + i.register_op( + "op_create_worker", + s.stateful_json_op_sync(t, op_create_worker), + ); i.register_op( "op_host_terminate_worker", - s.stateful_json_op(op_host_terminate_worker), + s.stateful_json_op_sync(t, op_host_terminate_worker), ); i.register_op( "op_host_post_message", - s.stateful_json_op(op_host_post_message), + s.stateful_json_op_sync(t, op_host_post_message), ); i.register_op( "op_host_get_message", - s.stateful_json_op(op_host_get_message), + s.stateful_json_op_async(t, op_host_get_message), ); } @@ -180,10 +188,11 @@ struct CreateWorkerArgs { /// Create worker as the host fn op_create_worker( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _data: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: CreateWorkerArgs = serde_json::from_value(args)?; let specifier = args.specifier.clone(); @@ -197,7 +206,6 @@ fn op_create_worker( if use_deno_namespace { state.check_unstable("Worker.deno"); } - let parent_state = state.clone(); let global_state = state.global_state.clone(); let permissions = state.permissions.borrow().clone(); let worker_id = state.next_worker_id.get(); @@ -217,12 +225,12 @@ fn op_create_worker( )?; // At this point all interactions with worker happen using thread // safe handler returned from previous function call - parent_state + state .workers .borrow_mut() .insert(worker_id, (join_handle, worker_handle)); - Ok(JsonOp::Sync(json!({ "id": worker_id }))) + Ok(json!({ "id": worker_id })) } #[derive(Deserialize)] @@ -231,10 +239,11 @@ struct WorkerArgs { } fn op_host_terminate_worker( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, _data: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { let args: WorkerArgs = serde_json::from_value(args)?; let id = args.id as u32; let (join_handle, worker_handle) = state @@ -244,7 +253,7 @@ fn op_host_terminate_worker( .expect("No worker handle found"); worker_handle.terminate(); join_handle.join().expect("Panic in worker thread"); - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } fn serialize_worker_event(event: WorkerEvent) -> Value { @@ -298,52 +307,61 @@ fn serialize_worker_event(event: WorkerEvent) -> Value { } /// Get message from guest worker as host -fn op_host_get_message( - state: &Rc, +async fn op_host_get_message( + state: Rc, + _resource_table: Rc>, args: Value, - _data: &mut [ZeroCopyBuf], -) -> Result { + _zero_copy: BufVec, +) -> Result { let args: WorkerArgs = serde_json::from_value(args)?; let id = args.id as u32; let state = state.clone(); - let worker_handle = state.workers.borrow()[&id].1.clone(); - let op = async move { - 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) - { - 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(); - // 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) { + + 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" })); + }; + 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) + { worker_handle.sender.close_channel(); join_handle.join().expect("Worker thread panicked"); } - json!({ "type": "close" }) } - }; - Ok(response) + serialize_worker_event(event) + } + None => { + // Worker shuts down + let mut workers = 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) { + worker_handle.sender.close_channel(); + join_handle.join().expect("Worker thread panicked"); + } + json!({ "type": "close" }) + } }; - Ok(JsonOp::Async(op.boxed_local())) + Ok(response) } /// Post message to guest worker as host fn op_host_post_message( - state: &Rc, + state: &State, + _resource_table: &mut ResourceTable, args: Value, data: &mut [ZeroCopyBuf], -) -> Result { +) -> Result { assert_eq!(data.len(), 1, "Invalid number of arguments"); let args: WorkerArgs = serde_json::from_value(args)?; let id = args.id as u32; @@ -353,5 +371,5 @@ fn op_host_post_message( let workers = state.workers.borrow(); let worker_handle = workers[&id].1.clone(); worker_handle.post_message(msg)?; - Ok(JsonOp::Sync(json!({}))) + Ok(json!({})) } diff --git a/cli/rt/30_files.js b/cli/rt/30_files.js index fe44727c28..c0a2bbbb6f 100644 --- a/cli/rt/30_files.js +++ b/cli/rt/30_files.js @@ -11,7 +11,7 @@ offset, whence, ) { - return sendSync("op_seek", { rid, offset, whence }); + return sendSync("op_seek_sync", { rid, offset, whence }); } function seek( @@ -19,7 +19,7 @@ offset, whence, ) { - return sendAsync("op_seek", { rid, offset, whence }); + return sendAsync("op_seek_async", { rid, offset, whence }); } function openSync( diff --git a/cli/rt/30_fs.js b/cli/rt/30_fs.js index 163c006041..d8171bdaca 100644 --- a/cli/rt/30_fs.js +++ b/cli/rt/30_fs.js @@ -6,11 +6,11 @@ const build = window.__bootstrap.build.build; function chmodSync(path, mode) { - sendSync("op_chmod", { path: pathFromURL(path), mode }); + sendSync("op_chmod_sync", { path: pathFromURL(path), mode }); } async function chmod(path, mode) { - await sendAsync("op_chmod", { path: pathFromURL(path), mode }); + await sendAsync("op_chmod_async", { path: pathFromURL(path), mode }); } function chownSync( @@ -18,7 +18,7 @@ uid, gid, ) { - sendSync("op_chown", { path: pathFromURL(path), uid, gid }); + sendSync("op_chown_sync", { path: pathFromURL(path), uid, gid }); } async function chown( @@ -26,14 +26,14 @@ uid, gid, ) { - await sendAsync("op_chown", { path: pathFromURL(path), uid, gid }); + await sendAsync("op_chown_async", { path: pathFromURL(path), uid, gid }); } function copyFileSync( fromPath, toPath, ) { - sendSync("op_copy_file", { + sendSync("op_copy_file_sync", { from: pathFromURL(fromPath), to: pathFromURL(toPath), }); @@ -43,7 +43,7 @@ fromPath, toPath, ) { - await sendAsync("op_copy_file", { + await sendAsync("op_copy_file_async", { from: pathFromURL(fromPath), to: pathFromURL(toPath), }); @@ -58,19 +58,19 @@ } function makeTempDirSync(options = {}) { - return sendSync("op_make_temp_dir", options); + return sendSync("op_make_temp_dir_sync", options); } function makeTempDir(options = {}) { - return sendAsync("op_make_temp_dir", options); + return sendAsync("op_make_temp_dir_async", options); } function makeTempFileSync(options = {}) { - return sendSync("op_make_temp_file", options); + return sendSync("op_make_temp_file_sync", options); } function makeTempFile(options = {}) { - return sendAsync("op_make_temp_file", options); + return sendAsync("op_make_temp_file_async", options); } function mkdirArgs(path, options) { @@ -87,14 +87,14 @@ } function mkdirSync(path, options) { - sendSync("op_mkdir", mkdirArgs(path, options)); + sendSync("op_mkdir_sync", mkdirArgs(path, options)); } async function mkdir( path, options, ) { - await sendAsync("op_mkdir", mkdirArgs(path, options)); + await sendAsync("op_mkdir_async", mkdirArgs(path, options)); } function res(response) { @@ -102,15 +102,16 @@ } function readDirSync(path) { - return res(sendSync("op_read_dir", { path: pathFromURL(path) }))[ + return res(sendSync("op_read_dir_sync", { path: pathFromURL(path) }))[ Symbol.iterator ](); } function readDir(path) { - const array = sendAsync("op_read_dir", { path: pathFromURL(path) }).then( - res, - ); + const array = sendAsync("op_read_dir_async", { path: pathFromURL(path) }) + .then( + res, + ); return { async *[Symbol.asyncIterator]() { yield* await array; @@ -119,26 +120,26 @@ } function readLinkSync(path) { - return sendSync("op_read_link", { path }); + return sendSync("op_read_link_sync", { path }); } function readLink(path) { - return sendAsync("op_read_link", { path }); + return sendAsync("op_read_link_async", { path }); } function realPathSync(path) { - return sendSync("op_realpath", { path }); + return sendSync("op_realpath_sync", { path }); } function realPath(path) { - return sendAsync("op_realpath", { path }); + return sendAsync("op_realpath_async", { path }); } function removeSync( path, options = {}, ) { - sendSync("op_remove", { + sendSync("op_remove_sync", { path: pathFromURL(path), recursive: !!options.recursive, }); @@ -148,18 +149,18 @@ path, options = {}, ) { - await sendAsync("op_remove", { + await sendAsync("op_remove_async", { path: pathFromURL(path), recursive: !!options.recursive, }); } function renameSync(oldpath, newpath) { - sendSync("op_rename", { oldpath, newpath }); + sendSync("op_rename_sync", { oldpath, newpath }); } async function rename(oldpath, newpath) { - await sendAsync("op_rename", { oldpath, newpath }); + await sendAsync("op_rename_async", { oldpath, newpath }); } function parseFileInfo(response) { @@ -188,15 +189,15 @@ } function fstatSync(rid) { - return parseFileInfo(sendSync("op_fstat", { rid })); + return parseFileInfo(sendSync("op_fstat_sync", { rid })); } async function fstat(rid) { - return parseFileInfo(await sendAsync("op_fstat", { rid })); + return parseFileInfo(await sendAsync("op_fstat_async", { rid })); } async function lstat(path) { - const res = await sendAsync("op_stat", { + const res = await sendAsync("op_stat_async", { path: pathFromURL(path), lstat: true, }); @@ -204,7 +205,7 @@ } function lstatSync(path) { - const res = sendSync("op_stat", { + const res = sendSync("op_stat_sync", { path: pathFromURL(path), lstat: true, }); @@ -212,7 +213,7 @@ } async function stat(path) { - const res = await sendAsync("op_stat", { + const res = await sendAsync("op_stat_async", { path: pathFromURL(path), lstat: false, }); @@ -220,7 +221,7 @@ } function statSync(path) { - const res = sendSync("op_stat", { + const res = sendSync("op_stat_sync", { path: pathFromURL(path), lstat: false, }); @@ -236,19 +237,19 @@ } function ftruncateSync(rid, len) { - sendSync("op_ftruncate", { rid, len: coerceLen(len) }); + sendSync("op_ftruncate_sync", { rid, len: coerceLen(len) }); } async function ftruncate(rid, len) { - await sendAsync("op_ftruncate", { rid, len: coerceLen(len) }); + await sendAsync("op_ftruncate_async", { rid, len: coerceLen(len) }); } function truncateSync(path, len) { - sendSync("op_truncate", { path, len: coerceLen(len) }); + sendSync("op_truncate_sync", { path, len: coerceLen(len) }); } async function truncate(path, len) { - await sendAsync("op_truncate", { path, len: coerceLen(len) }); + await sendAsync("op_truncate_async", { path, len: coerceLen(len) }); } function umask(mask) { @@ -256,11 +257,11 @@ } function linkSync(oldpath, newpath) { - sendSync("op_link", { oldpath, newpath }); + sendSync("op_link_sync", { oldpath, newpath }); } async function link(oldpath, newpath) { - await sendAsync("op_link", { oldpath, newpath }); + await sendAsync("op_link_async", { oldpath, newpath }); } function toSecondsFromEpoch(v) { @@ -272,7 +273,7 @@ atime, mtime, ) { - sendSync("op_utime", { + sendSync("op_utime_sync", { path, // TODO(ry) split atime, mtime into [seconds, nanoseconds] tuple atime: toSecondsFromEpoch(atime), @@ -285,7 +286,7 @@ atime, mtime, ) { - await sendAsync("op_utime", { + await sendAsync("op_utime_async", { path, // TODO(ry) split atime, mtime into [seconds, nanoseconds] tuple atime: toSecondsFromEpoch(atime), @@ -298,7 +299,7 @@ newpath, options, ) { - sendSync("op_symlink", { oldpath, newpath, options }); + sendSync("op_symlink_sync", { oldpath, newpath, options }); } async function symlink( @@ -306,23 +307,23 @@ newpath, options, ) { - await sendAsync("op_symlink", { oldpath, newpath, options }); + await sendAsync("op_symlink_async", { oldpath, newpath, options }); } function fdatasyncSync(rid) { - sendSync("op_fdatasync", { rid }); + sendSync("op_fdatasync_sync", { rid }); } async function fdatasync(rid) { - await sendAsync("op_fdatasync", { rid }); + await sendAsync("op_fdatasync_async", { rid }); } function fsyncSync(rid) { - sendSync("op_fsync", { rid }); + sendSync("op_fsync_sync", { rid }); } async function fsync(rid) { - await sendAsync("op_fsync", { rid }); + await sendAsync("op_fsync_async", { rid }); } window.__bootstrap.fs = { diff --git a/cli/state.rs b/cli/state.rs index 2ea75ace6c..9f225e522a 100644 --- a/cli/state.rs +++ b/cli/state.rs @@ -58,17 +58,6 @@ pub struct State { } impl State { - pub fn stateful_json_op( - self: &Rc, - dispatcher: D, - ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op - where - D: Fn(&Rc, Value, &mut [ZeroCopyBuf]) -> Result, - { - use crate::ops::json_op; - self.core_op(json_op(self.stateful_op(dispatcher))) - } - pub fn stateful_json_op_sync( self: &Rc, resource_table: &Rc>, @@ -85,7 +74,8 @@ impl State { let state = self.clone(); let resource_table = resource_table.clone(); - move |isolate_state: &mut CoreIsolateState, bufs: &mut [ZeroCopyBuf]| { + let f = move |isolate_state: &mut CoreIsolateState, + bufs: &mut [ZeroCopyBuf]| { let get_error_class_fn = isolate_state.get_error_class_fn; // The first buffer should contain JSON encoded op arguments; parse them. @@ -108,7 +98,8 @@ impl State { // Convert to Op. Op::Sync(serialize_result(None, result, get_error_class_fn)) - } + }; + self.core_op(f) } pub fn stateful_json_op_async( @@ -124,7 +115,8 @@ impl State { let state = self.clone(); let resource_table = resource_table.clone(); - move |isolate_state: &mut CoreIsolateState, bufs: &mut [ZeroCopyBuf]| { + let f = move |isolate_state: &mut CoreIsolateState, + bufs: &mut [ZeroCopyBuf]| { let get_error_class_fn = isolate_state.get_error_class_fn; // The first buffer should contain JSON encoded op arguments; parse them. @@ -163,9 +155,12 @@ impl State { } .boxed_local(), ) - } + }; + self.core_op(f) } + // TODO(bartlomieju): remove me - still used by `op_open_plugin` which + // needs access to isolate_state pub fn stateful_json_op2( self: &Rc, dispatcher: D, @@ -185,7 +180,7 @@ impl State { /// Wrap core `OpDispatcher` to collect metrics. // TODO(ry) this should be private. Is called by stateful_json_op or // stateful_minimal_op - pub fn core_op( + pub(crate) fn core_op( self: &Rc, dispatcher: D, ) -> impl Fn(&mut deno_core::CoreIsolateState, &mut [ZeroCopyBuf]) -> Op @@ -324,7 +319,7 @@ impl State { /// /// This is intentionally a non-recoverable check so that people cannot probe /// for unstable APIs from stable programs. - pub fn check_unstable(self: &Rc, api_name: &str) { + pub fn check_unstable(&self, api_name: &str) { // TODO(ry) Maybe use IsolateHandle::terminate_execution here to provide a // stack trace in JS. if !self.global_state.flags.unstable {