use std::sync::Arc;
use uuid::Uuid;
use super::DiscordState;
use crate::brain::agent::{MessageQueueCallback, QueuedUserMessage};
pub(crate) struct ActiveTurnGuard {
state: Arc<DiscordState>,
session_id: Uuid,
}
impl Drop for ActiveTurnGuard {
fn drop(&mut self) {
if let Ok(mut set) = self.state.active_turns.lock() {
set.remove(&self.session_id);
}
}
}
impl DiscordState {
pub(crate) fn try_begin_turn(self: &Arc<Self>, session_id: Uuid) -> Option<ActiveTurnGuard> {
let mut set = self.active_turns.lock().ok()?;
if !set.insert(session_id) {
return None;
}
Some(ActiveTurnGuard {
state: self.clone(),
session_id,
})
}
pub(crate) fn enqueue_followup(&self, session_id: Uuid, msg: QueuedUserMessage) {
crate::brain::agent::service::notify_queue::persist(session_id, &msg);
match self.pending_followups.lock() {
Ok(mut map) => map.entry(session_id).or_default().push_back(msg),
Err(e) => {
tracing::error!(
"Discord: could not queue a follow-up for session {session_id}, \
it is dropped: {e}"
);
}
}
}
pub(crate) fn drain_followups(&self, session_id: Uuid) -> Option<QueuedUserMessage> {
let mut map = self.pending_followups.lock().ok()?;
let queue = map.remove(&session_id)?;
for msg in &queue {
crate::brain::agent::service::notify_queue::clear_on_delivery(session_id, msg);
}
let msgs: Vec<QueuedUserMessage> = queue.into_iter().collect();
QueuedUserMessage::join(&msgs)
}
pub(crate) fn followup_queue_callback(self: &Arc<Self>) -> MessageQueueCallback {
let state = self.clone();
Arc::new(move |session_id: Uuid| {
let state = state.clone();
Box::pin(async move { state.drain_followups(session_id) })
})
}
}