use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
#[derive(Clone)]
pub struct InterruptSignal {
flag: Arc<AtomicBool>,
notify: Arc<tokio::sync::Notify>,
}
impl InterruptSignal {
pub fn new() -> Self {
Self {
flag: Arc::new(AtomicBool::new(false)),
notify: Arc::new(tokio::sync::Notify::new()),
}
}
pub fn fire(&self) {
self.flag.store(true, Ordering::SeqCst);
self.notify.notify_waiters();
}
pub fn is_set(&self) -> bool {
self.flag.load(Ordering::SeqCst)
}
pub fn reset(&self) {
self.flag.store(false, Ordering::SeqCst);
}
pub async fn notified(&self) {
self.notify.notified().await;
}
}
impl Default for InterruptSignal {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub enum InterruptSource {
User,
System,
SubAgent { task_id: String },
External { channel: String },
Goal { goal_id: String },
Schedule { task_id: String },
}
#[derive(Debug, Clone)]
pub struct SoftInterruptMessage {
pub content: String,
pub urgent: bool,
pub source: InterruptSource,
}
#[derive(Clone, Default)]
pub struct SoftInterruptQueue {
inner: Arc<std::sync::Mutex<Vec<SoftInterruptMessage>>>,
}
impl SoftInterruptQueue {
pub fn new() -> Self {
Self {
inner: Arc::new(std::sync::Mutex::new(Vec::new())),
}
}
pub fn push(&self, msg: SoftInterruptMessage) {
self.inner
.lock()
.expect("interrupt queue lock poisoned")
.push(msg);
}
pub fn drain(&self) -> Vec<SoftInterruptMessage> {
std::mem::take(
&mut self
.inner
.lock()
.expect("interrupt queue lock poisoned"),
)
}
pub fn is_empty(&self) -> bool {
self.inner
.lock()
.expect("interrupt queue lock poisoned")
.is_empty()
}
}