use tokio::sync::RwLock;
use std::collections::HashMap;
use std::sync::Arc;
use crate::method::{InvokeResult, MethodInfo};
use crate::slot::SlotInfo;
use arora_types::value::Value;
pub trait RegistryMethodHandler: Send + Sync {
fn invoke(&self, args: HashMap<String, Value>) -> InvokeResult;
}
impl<F> RegistryMethodHandler for F
where
F: Fn(HashMap<String, Value>) -> InvokeResult + Send + Sync,
{
fn invoke(&self, args: HashMap<String, Value>) -> InvokeResult {
self(args)
}
}
pub struct Registry {
slots: RwLock<Vec<SlotInfo>>,
methods: RwLock<HashMap<String, MethodInfo>>,
handlers: RwLock<HashMap<String, Arc<dyn RegistryMethodHandler>>>,
}
impl Default for Registry {
fn default() -> Self {
Self::new()
}
}
impl Registry {
pub fn new() -> Self {
Self {
slots: RwLock::new(Vec::new()),
methods: RwLock::new(HashMap::new()),
handlers: RwLock::new(HashMap::new()),
}
}
pub async fn set_slots(&self, slots: Vec<SlotInfo>) {
*self.slots.write().await = slots;
}
pub async fn get_slots(&self) -> Vec<SlotInfo> {
self.slots.read().await.clone()
}
pub async fn get_slots_filtered(&self, prefix: Option<&str>) -> Vec<SlotInfo> {
let slots = self.slots.read().await;
match prefix {
Some(prefix) => {
let prefix = prefix.trim_end_matches('/');
slots
.iter()
.filter(|n| {
n.path.starts_with(prefix) || n.path.starts_with(&format!("{}/", prefix))
})
.cloned()
.collect()
}
None => slots.clone(),
}
}
pub async fn get_input_paths(&self) -> Vec<String> {
self.slots
.read()
.await
.iter()
.filter(|n| n.kind.as_deref() == Some("input"))
.map(|n| n.path.clone())
.collect()
}
pub async fn register_method<H>(&self, info: MethodInfo, handler: H)
where
H: RegistryMethodHandler + 'static,
{
let path = info.path.clone();
self.methods.write().await.insert(path.clone(), info);
self.handlers.write().await.insert(path, Arc::new(handler));
}
pub async fn register_method_fn<F>(&self, info: MethodInfo, handler: F)
where
F: Fn(HashMap<String, Value>) -> InvokeResult + Send + Sync + 'static,
{
self.register_method(info, handler).await;
}
pub async fn get_methods(&self) -> Vec<MethodInfo> {
self.methods.read().await.values().cloned().collect()
}
pub async fn get_methods_filtered(&self, prefix: Option<&str>) -> Vec<MethodInfo> {
let methods = self.methods.read().await;
match prefix {
Some(prefix) => {
let prefix = prefix.trim_end_matches('/');
methods
.values()
.filter(|m| {
m.path.starts_with(prefix) || m.path.starts_with(&format!("{}/", prefix))
})
.cloned()
.collect()
}
None => methods.values().cloned().collect(),
}
}
pub async fn invoke_method(&self, path: &str, args: HashMap<String, Value>) -> InvokeResult {
let handlers = self.handlers.read().await;
match handlers.get(path) {
Some(handler) => {
let handler = handler.clone();
drop(handlers); handler.invoke(args)
}
None => InvokeResult::err(format!("Method not found: {}", path)),
}
}
pub async fn has_method(&self, path: &str) -> bool {
self.handlers.read().await.contains_key(path)
}
}