summaryrefslogtreecommitdiff
path: root/runtime/ops
diff options
context:
space:
mode:
authorElias Sjögreen <eliassjogreen1@gmail.com>2021-05-07 15:45:07 +0200
committerGitHub <noreply@github.com>2021-05-07 09:45:07 -0400
commit4ed1428c3401c9e6dc4d737bd7c9a50840054696 (patch)
tree62888871bee247f35d0f663b784ab072becfc164 /runtime/ops
parentc709f5df363887647915f7dd67e1c3bb8df6c526 (diff)
fix: align plugin api with Extension (#10427)
Diffstat (limited to 'runtime/ops')
-rw-r--r--runtime/ops/plugin.rs133
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())
}
}