use std::rc::Rc;
use super::ContextFactoryHashMap;
use crate::abi::proxy_wasm;
use crate::abi::proxy_wasm::traits::{Context, RootContext};
use crate::extension::error::ConfigurationError;
use crate::extension::error::ErrorSink;
use crate::extension::{Error, Result};
use crate::host::StreamInfo;
pub(crate) struct ContextSelector<'a> {
factories: ContextFactoryHashMap,
stream_info: &'a dyn StreamInfo,
}
impl<'a> ContextSelector<'a> {
pub fn new(factories: ContextFactoryHashMap, stream_info: &'a dyn StreamInfo) -> Self {
ContextSelector {
factories,
stream_info,
}
}
pub fn with_default_ops(factories: ContextFactoryHashMap) -> Self {
Self::new(factories, StreamInfo::default())
}
fn new_root_context(&mut self, context_id: u32) -> Result<Box<dyn RootContext>> {
let name = match self.stream_info.plugin().root_id()? {
Some(value) => value,
None => String::default(),
};
if let Some(root_context_factory) = self.factories.get_mut(&name) {
return root_context_factory(context_id);
}
if name == "" && self.factories.keys().len() == 1 {
if let Some(root_context_factory) = self.factories.values_mut().next() {
return root_context_factory(context_id);
}
}
Err(ConfigurationError::UnknownExtension {
requested: name,
available: self.factories.keys().cloned().collect(),
}
.into())
}
}
impl ContextSelector<'static> {
pub fn install(mut self) {
proxy_wasm::set_root_context(move |context_id| {
self.new_root_context(context_id)
.unwrap_or_else(|e| Box::new(VoidRootContext::with_default_ops(e)))
});
}
}
struct VoidRootContext<'a> {
err: Error,
error_sink: &'a dyn ErrorSink,
}
impl<'a> VoidRootContext<'a> {
fn new(err: Error, error_sink: &'a dyn ErrorSink) -> Self {
VoidRootContext { err, error_sink }
}
fn with_default_ops(err: Error) -> Self {
Self::new(err, ErrorSink::default())
}
}
impl<'a> RootContext for VoidRootContext<'a> {
fn on_configure(&mut self, _plugin_configuration_size: usize) -> bool {
self.error_sink
.observe("failed to create Proxy Wasm Root Context", &self.err);
false }
}
impl<'a> Context for VoidRootContext<'a> {}
pub(crate) struct VoidContextSelector {
err: Error,
}
impl VoidContextSelector {
pub fn new(err: Error) -> Self {
VoidContextSelector { err }
}
pub fn install(self) {
let err = Rc::new(self.err);
proxy_wasm::set_root_context(move |_| {
Box::new(VoidVmContext::with_default_ops(Rc::clone(&err)))
});
}
}
struct VoidVmContext<'a> {
err: Rc<Error>,
error_sink: &'a dyn ErrorSink,
}
impl<'a> VoidVmContext<'a> {
fn new(err: Rc<Error>, error_sink: &'a dyn ErrorSink) -> Self {
VoidVmContext { err, error_sink }
}
fn with_default_ops(err: Rc<Error>) -> Self {
Self::new(err, ErrorSink::default())
}
}
impl<'a> RootContext for VoidVmContext<'a> {
fn on_vm_start(&mut self, _vm_configuration_size: usize) -> bool {
self.error_sink
.observe("failed to initialize WebAssembly module", &self.err);
false }
}
impl<'a> Context for VoidVmContext<'a> {}