diff options
author | Aaron O'Mullan <aaron.omullan@gmail.com> | 2021-04-28 18:41:50 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-28 18:41:50 +0200 |
commit | 0260b488fbba9a43c64641428d3603b8761067a4 (patch) | |
tree | 66ce487f9241a3b91942dd048c7e43cb192bf9e8 /core/runtime.rs | |
parent | b28f9445aae85dbf86033300cfcb55e404529a23 (diff) |
core: introduce extensions (#9800)
Extensions allow declarative extensions to "JsRuntime" (ops, state, JS or middleware).
This allows for:
- `op_crates` to be plug-and-play & self-contained, reducing complexity leaked to consumers
- op middleware (like metrics_op) to be opt-in and for new middleware (unstable, tracing,...)
- `MainWorker` and `WebWorker` to be composable, allowing users to extend workers with their ops whilst benefiting from the other infrastructure (inspector, etc...)
In short extensions improve deno's modularity, reducing complexity and leaky abstractions for embedders and the internal codebase.
Diffstat (limited to 'core/runtime.rs')
-rw-r--r-- | core/runtime.rs | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/core/runtime.rs b/core/runtime.rs index 1981df5f3..51b231eb0 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -20,6 +20,8 @@ use crate::modules::NoopModuleLoader; use crate::modules::PrepareLoadFuture; use crate::modules::RecursiveModuleLoad; use crate::ops::*; +use crate::Extension; +use crate::OpMiddlewareFn; use crate::OpPayload; use crate::OpResponse; use crate::OpState; @@ -84,6 +86,7 @@ pub struct JsRuntime { snapshot_creator: Option<v8::SnapshotCreator>, has_snapshotted: bool, allocations: IsolateAllocations, + extensions: Vec<Extension>, } struct DynImportModEvaluate { @@ -189,6 +192,10 @@ pub struct RuntimeOptions { /// executed tries to load modules. pub module_loader: Option<Rc<dyn ModuleLoader>>, + /// JsRuntime extensions, not to be confused with ES modules + /// these are sets of ops and other JS code to be initialized. + pub extensions: Vec<Extension>, + /// V8 snapshot that should be loaded on startup. /// /// Currently can't be used with `will_snapshot`. @@ -303,6 +310,7 @@ impl JsRuntime { snapshot_creator: maybe_snapshot_creator, has_snapshotted: false, allocations: IsolateAllocations::default(), + extensions: options.extensions, }; if !has_startup_snapshot { @@ -357,6 +365,57 @@ impl JsRuntime { .unwrap(); } + /// Initializes JS of provided Extensions + // NOTE: this will probably change when streamlining snapshot flow + pub fn init_extension_js(&mut self) -> Result<(), AnyError> { + // Take extensions to avoid double-borrow + let mut extensions: Vec<Extension> = std::mem::take(&mut self.extensions); + for m in extensions.iter_mut() { + let js_files = m.init_js(); + for (filename, source) in js_files { + // TODO(@AaronO): use JsRuntime::execute_static() here to move src off heap + self.execute(filename, source)?; + } + } + // Restore extensions + self.extensions = extensions; + + Ok(()) + } + + /// Initializes ops of provided Extensions + // NOTE: this will probably change when streamlining snapshot flow + pub fn init_extension_ops(&mut self) -> Result<(), AnyError> { + let op_state = self.op_state(); + // Take extensions to avoid double-borrow + let mut extensions: Vec<Extension> = std::mem::take(&mut self.extensions); + + // Middleware + let middleware: Vec<Box<OpMiddlewareFn>> = extensions + .iter_mut() + .filter_map(|e| e.init_middleware()) + .collect(); + // macroware wraps an opfn in all the middleware + let macroware = + move |name, opfn| middleware.iter().fold(opfn, |opfn, m| m(name, opfn)); + + // Register ops + for e in extensions.iter_mut() { + e.init_state(&mut op_state.borrow_mut())?; + // Register each op after middlewaring it + let mut ops = e.init_ops().unwrap_or_default(); + for (name, opfn) in ops { + self.register_op(name, macroware(name, opfn)); + } + } + // Sync ops cache + self.sync_ops_cache(); + // Restore extensions + self.extensions = extensions; + + Ok(()) + } + /// Grabs a reference to core.js' handleAsyncMsgFromRust fn init_recv_cb(&mut self) { let scope = &mut self.handle_scope(); |