use std::{collections::HashMap, sync::Arc};
use futures_util::future::BoxFuture;
use serde_json::Value;
use crate::{
Frame, FuncRegistryBuilder,
func_registry::{CallFunctionError, dyn_wrapper::DynFunctionType},
query::QueryCallback,
};
#[derive(Default, Clone)]
pub struct FuncRegistry {
pub(crate) functions: Arc<HashMap<String, Box<dyn DynFunctionType>>>,
pub(crate) spawner: Option<Arc<dyn Fn(BoxFuture<'static, ()>) + Send + Sync>>,
}
impl FuncRegistry {
#[inline]
pub fn builder() -> FuncRegistryBuilder {
FuncRegistryBuilder::default()
}
pub(crate) fn call(&self, frame: Frame, name: &str, args: Vec<Value>, callback: QueryCallback) {
let Some(func) = self.functions.get(name) else {
callback.result(Err(CallFunctionError::NotFound(name.to_string())));
return;
};
func.call(self.spawner.as_deref(), frame, args, callback)
}
pub(crate) fn javascript(&self) -> String {
let mut code = include_str!("inject.js").to_string();
for (name, func) in &*self.functions {
let args = (0..func.num_arguments())
.map(|i| format!("arg{}", i))
.collect::<Vec<_>>()
.join(",");
code += &format!(
r#"window.jsBridge.{name} = function({args}) {{
return window.jsBridge.__internal.call("{name}", [{args}]);
}};"#,
name = name,
args = args
);
}
code
}
}