use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use cruxx_core::prelude::{Agent, CruxCtx, CruxErr};
use serde_json::Value;
use crate::handler_output::HandlerOutput;
use crate::metadata::HandlerMetadata;
pub type BoxHandler = Arc<
dyn Fn(Value) -> Pin<Box<dyn Future<Output = Result<HandlerOutput, CruxErr>> + Send>>
+ Send
+ Sync,
>;
pub type BoxAgentRunner = Arc<
dyn Fn(Value) -> Pin<Box<dyn Future<Output = Result<Value, CruxErr>> + Send>> + Send + Sync,
>;
pub struct HandlerRegistry {
handlers: HashMap<String, BoxHandler>,
agents: HashMap<String, BoxAgentRunner>,
metadata: HashMap<String, HandlerMetadata>,
}
impl HandlerRegistry {
pub fn new() -> Self {
Self {
handlers: HashMap::new(),
agents: HashMap::new(),
metadata: HashMap::new(),
}
}
pub fn register_metadata(&mut self, meta: HandlerMetadata) {
self.metadata.insert(meta.name.clone(), meta);
}
pub fn get_metadata(&self, name: &str) -> Option<&HandlerMetadata> {
self.metadata.get(name)
}
pub fn handler<F, Fut>(&mut self, name: impl Into<String>, f: F)
where
F: Fn(Value) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<HandlerOutput, CruxErr>> + Send + 'static,
{
let name = name.into();
self.handlers
.insert(name, Arc::new(move |v| Box::pin(f(v))));
}
pub fn handler_value<F, Fut>(&mut self, name: impl Into<String>, f: F)
where
F: Fn(Value) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Value, CruxErr>> + Send + 'static,
{
let name = name.into();
self.handlers.insert(
name,
Arc::new(move |v| {
let fut = f(v);
Box::pin(async move { fut.await.map(HandlerOutput::from) })
as Pin<Box<dyn Future<Output = Result<HandlerOutput, CruxErr>> + Send>>
}),
);
}
pub fn handler_value_with_metadata<F, Fut>(&mut self, meta: HandlerMetadata, f: F)
where
F: Fn(Value) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Value, CruxErr>> + Send + 'static,
{
let name = meta.name.clone();
self.metadata.insert(name.clone(), meta);
self.handlers.insert(
name,
Arc::new(move |v| {
let fut = f(v);
Box::pin(async move { fut.await.map(HandlerOutput::from) })
as Pin<Box<dyn Future<Output = Result<HandlerOutput, CruxErr>> + Send>>
}),
);
}
pub fn agent<A>(&mut self, name: impl Into<String>)
where
A: Agent<Input = Value, Output = Value>,
{
let name_str = name.into();
let agent_name = name_str.clone();
self.agents.insert(
name_str,
Arc::new(move |input: Value| {
let n = agent_name.clone();
Box::pin(async move {
let mut ctx = CruxCtx::new(&n);
A::run(&mut ctx, input).await
}) as Pin<Box<dyn Future<Output = Result<Value, CruxErr>> + Send>>
}),
);
}
pub fn agent_fn<F, Fut>(&mut self, name: impl Into<String>, f: F)
where
F: Fn(Value) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Value, CruxErr>> + Send + 'static,
{
let name = name.into();
self.agents.insert(name, Arc::new(move |v| Box::pin(f(v))));
}
pub fn get_handler(&self, name: &str) -> Option<&BoxHandler> {
self.handlers.get(name)
}
pub fn get_agent(&self, name: &str) -> Option<&BoxAgentRunner> {
self.agents.get(name)
}
}
impl Default for HandlerRegistry {
fn default() -> Self {
Self::new()
}
}