use std::collections::BTreeMap;
use std::path::PathBuf;
use std::sync::Arc;
use parking_lot::RwLock;
use crate::{Manifest, Pack, Safety, SkillError};
pub trait Provider: Send + Sync {
fn manifests(&self) -> Result<Vec<Manifest>, SkillError>;
}
pub trait Registry: Send + Sync {
fn register(&self, pack: Pack) -> Result<(), SkillError>;
fn get(&self, name: &str) -> Option<Pack>;
fn list(&self) -> Vec<Manifest>;
}
#[derive(Default)]
pub struct InMemoryRegistry {
packs: RwLock<BTreeMap<String, Arc<Pack>>>,
}
impl InMemoryRegistry {
pub fn new() -> Self {
Self::default()
}
}
impl Registry for InMemoryRegistry {
fn register(&self, pack: Pack) -> Result<(), SkillError> {
let name = pack.manifest.name.clone();
let mut packs = self.packs.write();
if packs.contains_key(&name) {
return Err(SkillError::AlreadyRegistered(name));
}
packs.insert(name, Arc::new(pack));
Ok(())
}
fn get(&self, name: &str) -> Option<Pack> {
self.packs.read().get(name).map(|pack| (**pack).clone())
}
fn list(&self) -> Vec<Manifest> {
self.packs
.read()
.values()
.map(|pack| pack.manifest.clone())
.collect()
}
}
pub fn register_provider(
provider: &dyn Provider,
registry: &dyn Registry,
) -> Result<(), SkillError> {
for manifest in provider.manifests()? {
let pack = Pack::new(PathBuf::new(), manifest);
registry.register(pack)?;
}
Ok(())
}
pub fn effective_safety(safeties: impl IntoIterator<Item = Safety>) -> Safety {
safeties.into_iter().max().unwrap_or(Safety::ReadOnly)
}
pub fn effective_envelope(
declared_scopes: &[String],
principal_grants: &[String],
operator_ceiling: &[String],
referenced: bool,
safety: Safety,
) -> EffectiveEnvelope {
if !referenced {
return EffectiveEnvelope {
scopes: Vec::new(),
safety: Safety::ReadOnly,
active: false,
};
}
let scopes = declared_scopes
.iter()
.filter(|scope| principal_grants.contains(scope) && operator_ceiling.contains(scope))
.cloned()
.collect();
EffectiveEnvelope {
scopes,
safety,
active: true,
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EffectiveEnvelope {
pub scopes: Vec<String>,
pub safety: Safety,
pub active: bool,
}