From 2e74f164b6dcf0ecbf8dd38fba9fae550d784bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Sun, 13 Dec 2020 19:45:53 +0100 Subject: refactor: deno_runtime crate (#8640) This commit moves Deno JS runtime, ops, permissions and inspector implementation to new "deno_runtime" crate located in "runtime/" directory. Details in "runtime/README.md". Co-authored-by: Ryan Dahl --- runtime/ops/plugin.rs | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 runtime/ops/plugin.rs (limited to 'runtime/ops/plugin.rs') diff --git a/runtime/ops/plugin.rs b/runtime/ops/plugin.rs new file mode 100644 index 000000000..1f3669b6f --- /dev/null +++ b/runtime/ops/plugin.rs @@ -0,0 +1,156 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +use crate::metrics::metrics_op; +use crate::permissions::Permissions; +use deno_core::error::AnyError; +use deno_core::futures::prelude::*; +use deno_core::plugin_api; +use deno_core::serde_json; +use deno_core::serde_json::json; +use deno_core::serde_json::Value; +use deno_core::BufVec; +use deno_core::JsRuntime; +use deno_core::Op; +use deno_core::OpAsyncFuture; +use deno_core::OpId; +use deno_core::OpState; +use deno_core::ZeroCopyBuf; +use dlopen::symbor::Library; +use serde::Deserialize; +use std::cell::RefCell; +use std::path::PathBuf; +use std::pin::Pin; +use std::rc::Rc; +use std::task::Context; +use std::task::Poll; + +pub fn init(rt: &mut JsRuntime) { + super::reg_json_sync(rt, "op_open_plugin", op_open_plugin); +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct OpenPluginArgs { + filename: String, +} + +pub fn op_open_plugin( + state: &mut OpState, + args: Value, + _zero_copy: &mut [ZeroCopyBuf], +) -> Result { + let args: OpenPluginArgs = serde_json::from_value(args)?; + let filename = PathBuf::from(&args.filename); + + super::check_unstable(state, "Deno.openPlugin"); + let permissions = state.borrow::(); + permissions.check_plugin(&filename)?; + + debug!("Loading Plugin: {:#?}", filename); + let plugin_lib = Library::open(filename).map(Rc::new)?; + let plugin_resource = PluginResource::new(&plugin_lib); + + let rid; + let deno_plugin_init; + { + rid = state + .resource_table + .add("plugin", Box::new(plugin_resource)); + deno_plugin_init = *unsafe { + state + .resource_table + .get::(rid) + .unwrap() + .lib + .symbol::("deno_plugin_init") + .unwrap() + }; + } + + let mut interface = PluginInterface::new(state, &plugin_lib); + deno_plugin_init(&mut interface); + + Ok(json!(rid)) +} + +struct PluginResource { + lib: Rc, +} + +impl PluginResource { + fn new(lib: &Rc) -> Self { + Self { lib: lib.clone() } + } +} + +struct PluginInterface<'a> { + state: &'a mut OpState, + plugin_lib: &'a Rc, +} + +impl<'a> PluginInterface<'a> { + fn new(state: &'a mut OpState, plugin_lib: &'a Rc) -> Self { + Self { state, 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(); + let plugin_op_fn = move |state_rc: Rc>, + mut zero_copy: BufVec| { + let mut state = state_rc.borrow_mut(); + let mut interface = PluginInterface::new(&mut state, &plugin_lib); + let op = dispatch_op_fn(&mut interface, &mut zero_copy); + match op { + sync_op @ Op::Sync(..) => sync_op, + Op::Async(fut) => Op::Async(PluginOpAsyncFuture::new(&plugin_lib, fut)), + Op::AsyncUnref(fut) => { + Op::AsyncUnref(PluginOpAsyncFuture::new(&plugin_lib, fut)) + } + _ => unreachable!(), + } + }; + self + .state + .op_table + .register_op(name, metrics_op(Box::new(plugin_op_fn))) + } +} + +struct PluginOpAsyncFuture { + fut: Option, + _plugin_lib: Rc, +} + +impl PluginOpAsyncFuture { + fn new(plugin_lib: &Rc, fut: OpAsyncFuture) -> Pin> { + let wrapped_fut = Self { + fut: Some(fut), + _plugin_lib: plugin_lib.clone(), + }; + Box::pin(wrapped_fut) + } +} + +impl Future for PluginOpAsyncFuture { + type Output = ::Output; + fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll { + self.fut.as_mut().unwrap().poll_unpin(ctx) + } +} + +impl Drop for PluginOpAsyncFuture { + fn drop(&mut self) { + self.fut.take(); + } +} -- cgit v1.2.3