use std::collections::VecDeque;
use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;
pub struct PendingAgentPerm {
pub agent_name: String,
pub tool_name: String,
#[allow(dead_code)]
pub arguments: String,
pub confirm_msg: String,
decision: Arc<(Mutex<Option<bool>>, Condvar)>,
}
impl PendingAgentPerm {
pub fn new(
agent_name: String,
tool_name: String,
arguments: String,
confirm_msg: String,
) -> Arc<Self> {
Arc::new(Self {
agent_name,
tool_name,
arguments,
confirm_msg,
decision: Arc::new((Mutex::new(None), Condvar::new())),
})
}
pub fn wait_for_decision(&self, timeout_secs: u64) -> bool {
let (lock, cvar) = &*self.decision;
let guard = lock.lock().unwrap();
let (guard, _timed_out) = cvar
.wait_timeout_while(guard, Duration::from_secs(timeout_secs), |d| d.is_none())
.unwrap();
guard.unwrap_or(false)
}
pub fn resolve(&self, approved: bool) {
let (lock, cvar) = &*self.decision;
let mut d = lock.lock().unwrap();
*d = Some(approved);
cvar.notify_one();
}
#[allow(dead_code)]
pub fn is_decided(&self) -> bool {
self.decision.0.lock().unwrap().is_some()
}
}
pub struct PermissionQueue {
pending: Mutex<VecDeque<Arc<PendingAgentPerm>>>,
}
impl Default for PermissionQueue {
fn default() -> Self {
Self::new()
}
}
impl PermissionQueue {
pub fn new() -> Self {
Self {
pending: Mutex::new(VecDeque::new()),
}
}
pub fn request_blocking(&self, req: Arc<PendingAgentPerm>) -> bool {
{
let mut q = self.pending.lock().unwrap();
q.push_back(Arc::clone(&req));
}
req.wait_for_decision(60)
}
pub fn pop_pending(&self) -> Option<Arc<PendingAgentPerm>> {
self.pending.lock().unwrap().pop_front()
}
pub fn deny_all(&self) {
let mut q = self.pending.lock().unwrap();
for req in q.drain(..) {
req.resolve(false);
}
}
}