use std::collections::HashMap;
use std::sync::Arc;
use agent_client_protocol::Responder;
use agent_client_protocol::schema::v1::{
PermissionOptionId, RequestPermissionOutcome, RequestPermissionRequest,
RequestPermissionResponse, SelectedPermissionOutcome,
};
use serde::Serialize;
use tokio::sync::{Mutex, broadcast};
use uuid::Uuid;
#[derive(Clone, Debug, Serialize)]
pub struct PermissionRequestEvent {
pub id: String,
pub request: serde_json::Value,
}
struct PendingEntry {
responder: Responder<RequestPermissionResponse>,
request: serde_json::Value,
}
pub struct PermissionManager {
pending: Arc<Mutex<HashMap<String, PendingEntry>>>,
request_tx: broadcast::Sender<PermissionRequestEvent>,
resolved_tx: broadcast::Sender<String>,
}
impl PermissionManager {
pub fn new() -> Self {
let (request_tx, _) = broadcast::channel(16);
let (resolved_tx, _) = broadcast::channel(16);
Self { pending: Arc::new(Mutex::new(HashMap::new())), request_tx, resolved_tx }
}
pub fn subscribe(&self) -> broadcast::Receiver<PermissionRequestEvent> {
self.request_tx.subscribe()
}
pub fn resolved_subscribe(&self) -> broadcast::Receiver<String> {
self.resolved_tx.subscribe()
}
pub async fn pending_count(&self) -> usize {
self.pending.lock().await.len()
}
pub async fn handle_request(
&self,
request: RequestPermissionRequest,
responder: Responder<RequestPermissionResponse>,
) -> Result<(), agent_client_protocol::Error> {
let id = Uuid::new_v4().to_string();
let request = serde_json::to_value(&request).unwrap_or_default();
let event = PermissionRequestEvent { id: id.clone(), request: request.clone() };
self.pending.lock().await.insert(id, PendingEntry { responder, request });
let _ = self.request_tx.send(event);
Ok(())
}
pub async fn pending_events(&self) -> Vec<PermissionRequestEvent> {
self.pending
.lock()
.await
.iter()
.map(|(id, entry)| PermissionRequestEvent {
id: id.clone(),
request: entry.request.clone(),
})
.collect()
}
pub async fn cancel_all(&self) {
let mut map = self.pending.lock().await;
for (id, entry) in map.drain() {
let _ = entry
.responder
.respond(RequestPermissionResponse::new(RequestPermissionOutcome::Cancelled));
let _ = self.resolved_tx.send(id);
}
}
pub async fn resolve(&self, id: &str, option_id: &str) -> bool {
let mut map = self.pending.lock().await;
if let Some(entry) = map.remove(id) {
let _ = entry.responder.respond(RequestPermissionResponse::new(
RequestPermissionOutcome::Selected(SelectedPermissionOutcome::new(
PermissionOptionId::new(option_id),
)),
));
let _ = self.resolved_tx.send(id.to_string());
true
} else {
false
}
}
}