summaryrefslogtreecommitdiff
path: root/runtime/ops/plugin.rs
blob: cc3bf93d5cac0c7ec9c9ad9a6a02ad002953927d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use crate::permissions::Permissions;
use deno_core::error::AnyError;
use deno_core::op_sync;
use deno_core::Extension;
use deno_core::OpState;
use deno_core::Resource;
use deno_core::ResourceId;
use dlopen::symbor::Library;
use log::debug;
use std::borrow::Cow;
use std::mem;
use std::path::PathBuf;
use std::rc::Rc;

/// 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()
    .ops(vec![("op_open_plugin", op_sync(op_open_plugin))])
    .build()
}

pub fn op_open_plugin(
  state: &mut OpState,
  filename: String,
  _: (),
) -> Result<ResourceId, AnyError> {
  let filename = PathBuf::from(&filename);

  super::check_unstable(state, "Deno.openPlugin");
  let permissions = state.borrow_mut::<Permissions>();
  permissions.plugin.check()?;

  debug!("Loading Plugin: {:#?}", filename);
  let plugin_lib = Library::open(filename).map(Rc::new)?;
  let plugin_resource = PluginResource::new(&plugin_lib);

  // Forgets the plugin_lib value to prevent segfaults when the process exits
  mem::forget(plugin_lib);

  let init = *unsafe { plugin_resource.0.symbol::<InitFn>("init") }?;
  let rid = state.resource_table.add(plugin_resource);
  let mut extension = init();

  if !extension.init_js().is_empty() {
    panic!("Plugins do not support loading js");
  }

  if extension.init_middleware().is_some() {
    panic!("Plugins do not support middleware");
  }

  extension.init_state(state)?;
  let ops = extension.init_ops().unwrap_or_default();
  for (name, opfn) in ops {
    state.op_table.register_op(name, opfn);
  }

  Ok(rid)
}

struct PluginResource(Rc<Library>);

impl Resource for PluginResource {
  fn name(&self) -> Cow<str> {
    "plugin".into()
  }

  fn close(self: Rc<Self>) {
    unimplemented!();
  }
}

impl PluginResource {
  fn new(lib: &Rc<Library>) -> Self {
    Self(lib.clone())
  }
}