diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2019-08-21 20:42:48 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-21 20:42:48 -0400 |
commit | bdc97b3976786bb744a27e59b0f4f28554a682df (patch) | |
tree | bf4635ad903de542c10620e95adb72eee03d9204 /cli/ops/dispatch_flatbuffers.rs | |
parent | b764d1b8ffc4bf5e2ab89bdbd978d708a6da0f24 (diff) |
Organize dispatch a bit (#2796)
Just some clean up reorganization around flatbuffer/minimal dispatch
code. This is prep for adding a JSON dispatcher.
Diffstat (limited to 'cli/ops/dispatch_flatbuffers.rs')
-rw-r--r-- | cli/ops/dispatch_flatbuffers.rs | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/cli/ops/dispatch_flatbuffers.rs b/cli/ops/dispatch_flatbuffers.rs new file mode 100644 index 000000000..2b2e5050d --- /dev/null +++ b/cli/ops/dispatch_flatbuffers.rs @@ -0,0 +1,216 @@ +use super::utils::CliOpResult; +use crate::deno_error::GetErrorKind; +use crate::msg; +use crate::state::ThreadSafeState; +use deno::*; +use flatbuffers::FlatBufferBuilder; +use hyper::rt::Future; + +use super::compiler::{op_cache, op_fetch_source_file}; +use super::errors::{op_apply_source_map, op_format_error}; +use super::fetch::op_fetch; +use super::files::{op_close, op_open, op_read, op_seek, op_write}; +use super::fs::{ + op_chdir, op_chmod, op_chown, op_copy_file, op_cwd, op_link, + op_make_temp_dir, op_mkdir, op_read_dir, op_read_link, op_remove, op_rename, + op_stat, op_symlink, op_truncate, op_utime, +}; +use super::metrics::op_metrics; +use super::net::{op_accept, op_dial, op_listen, op_shutdown}; +use super::os::{ + op_env, op_exec_path, op_exit, op_home_dir, op_is_tty, op_set_env, op_start, +}; +use super::performance::op_now; +use super::permissions::{op_permissions, op_revoke_permission}; +use super::process::{op_kill, op_run, op_run_status}; +use super::random::op_get_random_values; +use super::repl::{op_repl_readline, op_repl_start}; +use super::resources::op_resources; +use super::timers::{op_global_timer, op_global_timer_stop}; +use super::workers::{ + op_create_worker, op_host_get_message, op_host_get_worker_closed, + op_host_post_message, op_worker_get_message, op_worker_post_message, +}; + +type CliDispatchFn = fn( + state: &ThreadSafeState, + base: &msg::Base<'_>, + data: Option<PinnedBuf>, +) -> CliOpResult; + +/// Processes raw messages from JavaScript. +/// This functions invoked every time Deno.core.dispatch() is called. +/// control corresponds to the first argument of Deno.core.dispatch(). +/// data corresponds to the second argument of Deno.core.dispatch(). +pub fn dispatch( + state: &ThreadSafeState, + control: &[u8], + zero_copy: Option<PinnedBuf>, +) -> CoreOp { + let base = msg::get_root_as_base(&control); + let inner_type = base.inner_type(); + let is_sync = base.sync(); + let cmd_id = base.cmd_id(); + + debug!( + "msg_from_js {} sync {}", + msg::enum_name_any(inner_type), + is_sync + ); + + let op_func: CliDispatchFn = match op_selector_std(inner_type) { + Some(v) => v, + None => panic!("Unhandled message {}", msg::enum_name_any(inner_type)), + }; + + let op_result = op_func(state, &base, zero_copy); + + let state = state.clone(); + + match op_result { + Ok(Op::Sync(buf)) => { + state.metrics_op_completed(buf.len()); + Op::Sync(buf) + } + Ok(Op::Async(fut)) => { + let result_fut = Box::new( + fut + .or_else(move |err: ErrBox| -> Result<Buf, ()> { + debug!("op err {}", err); + // No matter whether we got an Err or Ok, we want a serialized message to + // send back. So transform the DenoError into a Buf. + let builder = &mut FlatBufferBuilder::new(); + let errmsg_offset = builder.create_string(&format!("{}", err)); + Ok(serialize_response( + cmd_id, + builder, + msg::BaseArgs { + error: Some(errmsg_offset), + error_kind: err.kind(), + ..Default::default() + }, + )) + }) + .and_then(move |buf: Buf| -> Result<Buf, ()> { + // Handle empty responses. For sync responses we just want + // to send null. For async we want to send a small message + // with the cmd_id. + let buf = if buf.len() > 0 { + buf + } else { + let builder = &mut FlatBufferBuilder::new(); + serialize_response( + cmd_id, + builder, + msg::BaseArgs { + ..Default::default() + }, + ) + }; + state.metrics_op_completed(buf.len()); + Ok(buf) + }) + .map_err(|err| panic!("unexpected error {:?}", err)), + ); + Op::Async(result_fut) + } + Err(err) => { + debug!("op err {}", err); + // No matter whether we got an Err or Ok, we want a serialized message to + // send back. So transform the DenoError into a Buf. + let builder = &mut FlatBufferBuilder::new(); + let errmsg_offset = builder.create_string(&format!("{}", err)); + let response_buf = serialize_response( + cmd_id, + builder, + msg::BaseArgs { + error: Some(errmsg_offset), + error_kind: err.kind(), + ..Default::default() + }, + ); + state.metrics_op_completed(response_buf.len()); + Op::Sync(response_buf) + } + } +} + +pub fn serialize_response( + cmd_id: u32, + builder: &mut FlatBufferBuilder<'_>, + mut args: msg::BaseArgs<'_>, +) -> Buf { + args.cmd_id = cmd_id; + let base = msg::Base::create(builder, &args); + msg::finish_base_buffer(builder, base); + let data = builder.finished_data(); + // println!("serialize_response {:x?}", data); + data.into() +} + +/// Standard ops set for most isolates +pub fn op_selector_std(inner_type: msg::Any) -> Option<CliDispatchFn> { + match inner_type { + msg::Any::Accept => Some(op_accept), + msg::Any::ApplySourceMap => Some(op_apply_source_map), + msg::Any::Cache => Some(op_cache), + msg::Any::Chdir => Some(op_chdir), + msg::Any::Chmod => Some(op_chmod), + msg::Any::Chown => Some(op_chown), + msg::Any::Close => Some(op_close), + msg::Any::CopyFile => Some(op_copy_file), + msg::Any::CreateWorker => Some(op_create_worker), + msg::Any::Cwd => Some(op_cwd), + msg::Any::Dial => Some(op_dial), + msg::Any::Environ => Some(op_env), + msg::Any::ExecPath => Some(op_exec_path), + msg::Any::Exit => Some(op_exit), + msg::Any::Fetch => Some(op_fetch), + msg::Any::FetchSourceFile => Some(op_fetch_source_file), + msg::Any::FormatError => Some(op_format_error), + msg::Any::GetRandomValues => Some(op_get_random_values), + msg::Any::GlobalTimer => Some(op_global_timer), + msg::Any::GlobalTimerStop => Some(op_global_timer_stop), + msg::Any::HostGetMessage => Some(op_host_get_message), + msg::Any::HostGetWorkerClosed => Some(op_host_get_worker_closed), + msg::Any::HostPostMessage => Some(op_host_post_message), + msg::Any::IsTTY => Some(op_is_tty), + msg::Any::Kill => Some(op_kill), + msg::Any::Link => Some(op_link), + msg::Any::Listen => Some(op_listen), + msg::Any::MakeTempDir => Some(op_make_temp_dir), + msg::Any::Metrics => Some(op_metrics), + msg::Any::Mkdir => Some(op_mkdir), + msg::Any::Now => Some(op_now), + msg::Any::Open => Some(op_open), + msg::Any::PermissionRevoke => Some(op_revoke_permission), + msg::Any::Permissions => Some(op_permissions), + msg::Any::Read => Some(op_read), + msg::Any::ReadDir => Some(op_read_dir), + msg::Any::Readlink => Some(op_read_link), + msg::Any::Remove => Some(op_remove), + msg::Any::Rename => Some(op_rename), + msg::Any::ReplReadline => Some(op_repl_readline), + msg::Any::ReplStart => Some(op_repl_start), + msg::Any::Resources => Some(op_resources), + msg::Any::Run => Some(op_run), + msg::Any::RunStatus => Some(op_run_status), + msg::Any::Seek => Some(op_seek), + msg::Any::SetEnv => Some(op_set_env), + msg::Any::Shutdown => Some(op_shutdown), + msg::Any::Start => Some(op_start), + msg::Any::Stat => Some(op_stat), + msg::Any::Symlink => Some(op_symlink), + msg::Any::Truncate => Some(op_truncate), + msg::Any::HomeDir => Some(op_home_dir), + msg::Any::Utime => Some(op_utime), + msg::Any::Write => Some(op_write), + + // TODO(ry) split these out so that only the appropriate Workers can access + // them. + msg::Any::WorkerGetMessage => Some(op_worker_get_message), + msg::Any::WorkerPostMessage => Some(op_worker_post_message), + + _ => None, + } +} |