use crate::{
CapabilityError, CapabilityRequest, CapabilityResponse, CapabilityResult,
LocalCapabilityHandler,
};
use appcore_core::{CapabilityDescriptor, CapabilityName};
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Clone)]
pub struct LocalCapabilityProvider {
descriptor: CapabilityDescriptor,
handler: Arc<dyn LocalCapabilityHandler>,
}
impl std::fmt::Debug for LocalCapabilityProvider {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LocalCapabilityProvider")
.field("descriptor", &self.descriptor)
.finish_non_exhaustive()
}
}
impl LocalCapabilityProvider {
pub(crate) fn new(
descriptor: CapabilityDescriptor,
handler: Arc<dyn LocalCapabilityHandler>,
) -> Self {
Self {
descriptor,
handler,
}
}
pub fn descriptor(&self) -> &CapabilityDescriptor {
&self.descriptor
}
pub fn is_healthy(&self) -> bool {
self.handler.is_healthy()
}
pub fn handle(&self, request: &CapabilityRequest) -> CapabilityResult<CapabilityResponse> {
self.handler.handle(request)
}
}
#[derive(Debug, Clone, Default)]
pub struct CapabilityRegistry {
local: HashMap<CapabilityName, LocalCapabilityProvider>,
}
impl CapabilityRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register_handler<H>(&mut self, handler: H) -> CapabilityResult<()>
where
H: LocalCapabilityHandler + 'static,
{
self.register_shared_handler(Arc::new(handler))
}
pub fn register_shared_handler(
&mut self,
handler: Arc<dyn LocalCapabilityHandler>,
) -> CapabilityResult<()> {
let descriptor = handler.descriptor();
if descriptor.version.is_empty() || descriptor.version.len() > 256 {
return Err(CapabilityError::HandlerRejected(
"invalid_descriptor_version_length".into(),
));
}
if self.local.contains_key(&descriptor.name) {
return Err(CapabilityError::HandlerAlreadyRegistered(
descriptor.name.clone(),
));
}
if self.local.len() >= 4096 {
return Err(CapabilityError::HandlerRejected(
"local_registry_capacity_exceeded".into(),
));
}
self.local.insert(
descriptor.name.clone(),
LocalCapabilityProvider::new(descriptor, handler),
);
Ok(())
}
pub fn get(&self, capability: &CapabilityName) -> Option<&LocalCapabilityProvider> {
self.local.get(capability)
}
pub fn descriptors(&self) -> Vec<CapabilityDescriptor> {
self.local
.values()
.map(|provider| provider.descriptor.clone())
.collect()
}
pub fn iter_descriptors(&self) -> impl ExactSizeIterator<Item = &CapabilityDescriptor> {
self.local.values().map(LocalCapabilityProvider::descriptor)
}
}