use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use super::server::McpServer;
use crate::AcbResult;
#[cfg(feature = "sse")]
type MutexType<T> = tokio::sync::Mutex<T>;
#[cfg(not(feature = "sse"))]
type MutexType<T> = std::sync::Mutex<T>;
pub struct TenantRegistry {
data_dir: PathBuf,
servers: HashMap<String, Arc<MutexType<McpServer>>>,
}
impl TenantRegistry {
pub fn new(data_dir: &Path) -> Self {
Self {
data_dir: data_dir.to_path_buf(),
servers: HashMap::new(),
}
}
pub fn get_or_create(&mut self, user_id: &str) -> AcbResult<Arc<MutexType<McpServer>>> {
if let Some(server) = self.servers.get(user_id) {
return Ok(server.clone());
}
std::fs::create_dir_all(&self.data_dir).map_err(|e| {
crate::AcbError::Io(std::io::Error::other(format!(
"Failed to create data dir {}: {e}",
self.data_dir.display()
)))
})?;
let graph_path = self.data_dir.join(format!("{user_id}.acb"));
tracing::info!(
"Opening graph for user '{user_id}': {}",
graph_path.display()
);
let mut server = McpServer::new();
if graph_path.is_file() {
match crate::AcbReader::read_from_file(&graph_path) {
Ok(graph) => {
server.load_graph(user_id.to_string(), graph);
}
Err(e) => {
tracing::warn!(
"Failed to load graph for user '{user_id}': {e} — starting empty"
);
}
}
}
let server = Arc::new(MutexType::new(server));
self.servers.insert(user_id.to_string(), server.clone());
Ok(server)
}
pub fn count(&self) -> usize {
self.servers.len()
}
}