use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::{broadcast, RwLock};
use bamboo_agent_core::AgentEvent;
use super::event_forwarder::AccountFeedInbox;
use super::runner_state::AgentRunner;
pub const SESSION_EVENT_CHANNEL_CAPACITY: usize = 1000;
pub async fn get_or_create_event_sender(
senders: &Arc<RwLock<HashMap<String, broadcast::Sender<AgentEvent>>>>,
session_id: &str,
) -> broadcast::Sender<AgentEvent> {
{
let read = senders.read().await;
if let Some(sender) = read.get(session_id) {
return sender.clone();
}
}
let mut write = senders.write().await;
if let Some(sender) = write.get(session_id) {
return sender.clone();
}
let (sender, _) = broadcast::channel(SESSION_EVENT_CHANNEL_CAPACITY);
write.insert(session_id.to_string(), sender.clone());
sender
}
#[derive(Clone)]
pub(crate) struct ReplayableSessionEventPublisher {
runners: Arc<RwLock<HashMap<String, AgentRunner>>>,
senders: Arc<RwLock<HashMap<String, broadcast::Sender<AgentEvent>>>>,
account_feed_inbox: Option<AccountFeedInbox>,
}
impl ReplayableSessionEventPublisher {
pub(crate) fn new(
runners: Arc<RwLock<HashMap<String, AgentRunner>>>,
senders: Arc<RwLock<HashMap<String, broadcast::Sender<AgentEvent>>>>,
account_feed_inbox: Option<AccountFeedInbox>,
) -> Self {
Self {
runners,
senders,
account_feed_inbox,
}
}
pub(crate) async fn publish(&self, session_id: &str, event: AgentEvent) {
debug_assert!(event.is_replayable_session_state());
let sender = get_or_create_event_sender(&self.senders, session_id).await;
let mut runners = self.runners.write().await;
if let Some(runner) = runners.get_mut(session_id) {
runner.push_critical_event(event.clone());
}
if let Some(inbox) = &self.account_feed_inbox {
if event.is_durable_change() {
let route_session_id = event.session_id().unwrap_or(session_id);
let _ = inbox.try_send((Some(route_session_id.to_string()), event.clone()));
}
}
let _ = sender.send(event);
}
}