diff options
| author | Elias Sjögreen <eliassjogreen1@gmail.com> | 2021-05-07 15:45:07 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-07 09:45:07 -0400 |
| commit | 4ed1428c3401c9e6dc4d737bd7c9a50840054696 (patch) | |
| tree | 62888871bee247f35d0f663b784ab072becfc164 /runtime/ops | |
| parent | c709f5df363887647915f7dd67e1c3bb8df6c526 (diff) | |
fix: align plugin api with Extension (#10427)
Diffstat (limited to 'runtime/ops')
| -rw-r--r-- | runtime/ops/plugin.rs | 133 |
1 files changed, 33 insertions, 100 deletions
diff --git a/runtime/ops/plugin.rs b/runtime/ops/plugin.rs index 17d39405f..a4ec0eece 100644 --- a/runtime/ops/plugin.rs +++ b/runtime/ops/plugin.rs @@ -1,15 +1,8 @@ // Copyright 2018-2021 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::op_sync; -use deno_core::plugin_api; use deno_core::Extension; -use deno_core::Op; -use deno_core::OpAsyncFuture; -use deno_core::OpFn; -use deno_core::OpId; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; @@ -17,11 +10,18 @@ use deno_core::ZeroCopyBuf; use dlopen::symbor::Library; use log::debug; use std::borrow::Cow; +use std::mem; use std::path::PathBuf; -use std::pin::Pin; use std::rc::Rc; -use std::task::Context; -use std::task::Poll; + +/// A default `init` function for plugins which mimics the way the internal +/// extensions are initalized. Plugins currently do not support all extension +/// features and are most likely not going to in the future. Currently only +/// `init_state` and `init_ops` are supported while `init_middleware` and `init_js` +/// are not. Currently the `PluginResource` does not support being closed due to +/// certain risks in unloading the dynamic library without unloading dependent +/// functions and resources. +pub type InitFn = fn() -> Extension; pub fn init() -> Extension { Extension::builder() @@ -44,111 +44,44 @@ pub fn op_open_plugin( 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_resource); - deno_plugin_init = *unsafe { - state - .resource_table - .get::<PluginResource>(rid) - .unwrap() - .lib - .symbol::<plugin_api::InitFn>("deno_plugin_init") - .unwrap() - }; - } - - let mut interface = PluginInterface::new(state, &plugin_lib); - deno_plugin_init(&mut interface); + // Forgets the plugin_lib value to prevent segfaults when the process exits + mem::forget(plugin_lib); - Ok(rid) -} - -struct PluginResource { - lib: Rc<Library>, -} + let init = *unsafe { plugin_resource.0.symbol::<InitFn>("init") }?; + let rid = state.resource_table.add(plugin_resource); + let mut extension = init(); -impl Resource for PluginResource { - fn name(&self) -> Cow<str> { - "plugin".into() + if !extension.init_js().is_empty() { + panic!("Plugins do not support loading js"); } -} -impl PluginResource { - fn new(lib: &Rc<Library>) -> Self { - Self { lib: lib.clone() } + if extension.init_middleware().is_some() { + panic!("Plugins do not support middleware"); } -} - -struct PluginInterface<'a> { - state: &'a mut OpState, - plugin_lib: &'a Rc<Library>, -} -impl<'a> PluginInterface<'a> { - fn new(state: &'a mut OpState, plugin_lib: &'a Rc<Library>) -> Self { - Self { state, plugin_lib } + extension.init_state(state)?; + let ops = extension.init_ops().unwrap_or_default(); + for (name, opfn) in ops { + state.op_table.register_op(name, opfn); } -} -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: Box<OpFn> = Box::new(move |state_rc, payload| { - let mut state = state_rc.borrow_mut(); - let mut interface = PluginInterface::new(&mut state, &plugin_lib); - let (_, buf): ((), Option<ZeroCopyBuf>) = payload.deserialize().unwrap(); - let op = dispatch_op_fn(&mut interface, buf); - 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::leak(Box::new(name.to_string())), plugin_op_fn), - ) - } + Ok(rid) } -struct PluginOpAsyncFuture { - fut: Option<OpAsyncFuture>, - _plugin_lib: Rc<Library>, -} +struct PluginResource(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 Resource for PluginResource { + fn name(&self) -> Cow<str> { + "plugin".into() } -} -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) + fn close(self: Rc<Self>) { + unimplemented!(); } } -impl Drop for PluginOpAsyncFuture { - fn drop(&mut self) { - self.fut.take(); +impl PluginResource { + fn new(lib: &Rc<Library>) -> Self { + Self(lib.clone()) } } |
