diff options
Diffstat (limited to 'cli/ops')
-rw-r--r-- | cli/ops/mod.rs | 2 | ||||
-rw-r--r-- | cli/ops/plugin.rs | 153 | ||||
-rw-r--r-- | cli/ops/plugins.rs | 66 |
3 files changed, 154 insertions, 67 deletions
diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index b91a61c3a..a53e5ac16 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -19,7 +19,7 @@ pub mod net; mod net_unix; pub mod os; pub mod permissions; -pub mod plugins; +pub mod plugin; pub mod process; pub mod random; pub mod repl; diff --git a/cli/ops/plugin.rs b/cli/ops/plugin.rs new file mode 100644 index 000000000..cabb3329d --- /dev/null +++ b/cli/ops/plugin.rs @@ -0,0 +1,153 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use crate::fs::resolve_from_cwd; +use crate::op_error::OpError; +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; +use deno_core::Op; +use deno_core::OpAsyncFuture; +use deno_core::OpId; +use deno_core::ZeroCopyBuf; +use dlopen::symbor::Library; +use futures::prelude::*; +use std::path::Path; +use std::pin::Pin; +use std::rc::Rc; +use std::task::Context; +use std::task::Poll; + +pub fn init(i: &mut CoreIsolate, s: &State) { + i.register_op( + "op_open_plugin", + s.core_op(json_op(s.stateful_op2(op_open_plugin))), + ); +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct OpenPluginArgs { + filename: String, +} + +pub fn op_open_plugin( + isolate: &mut CoreIsolate, + state: &State, + args: Value, + _zero_copy: Option<ZeroCopyBuf>, +) -> Result<JsonOp, OpError> { + state.check_unstable("Deno.openPlugin"); + let args: OpenPluginArgs = serde_json::from_value(args).unwrap(); + let filename = resolve_from_cwd(Path::new(&args.filename))?; + + state.check_plugin(&filename)?; + + debug!("Loading Plugin: {:#?}", filename); + let plugin_lib = Library::open(filename) + .map(Rc::new) + .map_err(OpError::from)?; + let plugin_resource = PluginResource::new(&plugin_lib); + + let mut resource_table = isolate.resource_table.borrow_mut(); + let rid = resource_table.add("plugin", Box::new(plugin_resource)); + let plugin_resource = resource_table.get::<PluginResource>(rid).unwrap(); + + let deno_plugin_init = *unsafe { + plugin_resource + .lib + .symbol::<plugin_api::InitFn>("deno_plugin_init") + } + .unwrap(); + drop(resource_table); + + let mut interface = PluginInterface::new(isolate, &plugin_lib); + deno_plugin_init(&mut interface); + + Ok(JsonOp::Sync(json!(rid))) +} + +struct PluginResource { + lib: Rc<Library>, +} + +impl PluginResource { + fn new(lib: &Rc<Library>) -> Self { + Self { lib: lib.clone() } + } +} + +struct PluginInterface<'a> { + isolate: &'a mut CoreIsolate, + plugin_lib: &'a Rc<Library>, +} + +impl<'a> PluginInterface<'a> { + fn new(isolate: &'a mut CoreIsolate, plugin_lib: &'a Rc<Library>) -> Self { + Self { + isolate, + plugin_lib, + } + } +} + +impl<'a> plugin_api::Interface for PluginInterface<'a> { + /// Does the same as `core::Isolate::register_op()`, but additionally makes + /// the registered op dispatcher, as well as the op futures created by it, + /// keep reference to the plugin `Library` object, so that the plugin doesn't + /// get unloaded before all its op registrations and the futures created by + /// them are dropped. + fn register_op( + &mut self, + name: &str, + dispatch_op_fn: plugin_api::DispatchOpFn, + ) -> OpId { + let plugin_lib = self.plugin_lib.clone(); + self.isolate.op_registry.register( + name, + move |isolate, control, zero_copy| { + let mut interface = PluginInterface::new(isolate, &plugin_lib); + let op = dispatch_op_fn(&mut interface, control, zero_copy); + match op { + sync_op @ Op::Sync(..) => sync_op, + Op::Async(fut) => { + Op::Async(PluginOpAsyncFuture::new(&plugin_lib, fut)) + } + Op::AsyncUnref(fut) => { + Op::AsyncUnref(PluginOpAsyncFuture::new(&plugin_lib, fut)) + } + } + }, + ) + } +} + +struct PluginOpAsyncFuture { + fut: Option<OpAsyncFuture>, + _plugin_lib: Rc<Library>, +} + +impl PluginOpAsyncFuture { + fn new(plugin_lib: &Rc<Library>, fut: OpAsyncFuture) -> Pin<Box<Self>> { + let wrapped_fut = Self { + fut: Some(fut), + _plugin_lib: plugin_lib.clone(), + }; + Box::pin(wrapped_fut) + } +} + +impl Future for PluginOpAsyncFuture { + type Output = <OpAsyncFuture as Future>::Output; + fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> { + self.fut.as_mut().unwrap().poll_unpin(ctx) + } +} + +impl Drop for PluginOpAsyncFuture { + fn drop(&mut self) { + self.fut.take(); + } +} diff --git a/cli/ops/plugins.rs b/cli/ops/plugins.rs deleted file mode 100644 index f4212f579..000000000 --- a/cli/ops/plugins.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::dispatch_json::{Deserialize, JsonOp, Value}; -use crate::fs as deno_fs; -use crate::op_error::OpError; -use crate::ops::json_op; -use crate::state::State; -use deno_core::CoreIsolate; -use deno_core::ZeroCopyBuf; -use dlopen::symbor::Library; -use std::ffi::OsStr; -use std::path::Path; - -pub type PluginInitFn = fn(isolate: &mut CoreIsolate); - -pub fn init(i: &mut CoreIsolate, s: &State) { - i.register_op( - "op_open_plugin", - s.core_op(json_op(s.stateful_op2(op_open_plugin))), - ); -} - -fn open_plugin<P: AsRef<OsStr>>(lib_path: P) -> Result<Library, OpError> { - debug!("Loading Plugin: {:#?}", lib_path.as_ref()); - Library::open(lib_path).map_err(OpError::from) -} - -struct PluginResource { - lib: Library, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -struct OpenPluginArgs { - filename: String, -} - -pub fn op_open_plugin( - isolate: &mut CoreIsolate, - state: &State, - args: Value, - _zero_copy: Option<ZeroCopyBuf>, -) -> Result<JsonOp, OpError> { - state.check_unstable("Deno.openPlugin"); - let args: OpenPluginArgs = serde_json::from_value(args).unwrap(); - let filename = deno_fs::resolve_from_cwd(Path::new(&args.filename))?; - - state.check_plugin(&filename)?; - - let lib = open_plugin(filename).unwrap(); - let plugin_resource = PluginResource { lib }; - - let mut resource_table = isolate.resource_table.borrow_mut(); - let rid = resource_table.add("plugin", Box::new(plugin_resource)); - let plugin_resource = resource_table.get::<PluginResource>(rid).unwrap(); - - let deno_plugin_init = *unsafe { - plugin_resource - .lib - .symbol::<PluginInitFn>("deno_plugin_init") - } - .unwrap(); - drop(resource_table); - - deno_plugin_init(isolate); - - Ok(JsonOp::Sync(json!(rid))) -} |