use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::{broadcast, Mutex};
use crate::acp::client::AcpClient;
#[derive(Clone, Debug)]
pub struct AcpProcessEvent {
pub session_id: String,
pub alive: bool,
}
#[derive(Clone)]
pub struct AcpSupervisor {
clients: Arc<Mutex<HashMap<String, Arc<AcpClient>>>>,
events: broadcast::Sender<AcpProcessEvent>,
}
impl Default for AcpSupervisor {
fn default() -> Self {
let (events, _) = broadcast::channel(64);
Self {
clients: Arc::new(Mutex::new(HashMap::new())),
events,
}
}
}
impl AcpSupervisor {
pub async fn insert(&self, session_id: String, client: Arc<AcpClient>) {
self.clients.lock().await.insert(session_id.clone(), client);
let _ = self
.events
.send(AcpProcessEvent { session_id, alive: true });
}
pub async fn get(&self, session_id: &str) -> Option<Arc<AcpClient>> {
self.clients.lock().await.get(session_id).cloned()
}
pub async fn snapshot(&self) -> Vec<(String, Arc<AcpClient>)> {
self.clients
.lock()
.await
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect()
}
pub async fn dispose(&self, session_id: &str) -> Option<Arc<AcpClient>> {
let removed = self.clients.lock().await.remove(session_id);
if removed.is_some() {
let _ = self.events.send(AcpProcessEvent {
session_id: session_id.to_string(),
alive: false,
});
}
removed
}
pub fn process_event_subscribe(&self) -> broadcast::Receiver<AcpProcessEvent> {
self.events.subscribe()
}
pub async fn shutdown_all(&self) {
let mut map = self.clients.lock().await;
for (_, client) in map.drain() {
let c = Arc::try_unwrap(client).ok();
if let Some(c) = c {
c.disconnect().await;
}
}
}
}