use serde_json::Value;
use tokio::sync::oneshot;
use agent_block_types::error::BlockError;
pub type AckResult = Result<Value, BlockError>;
pub type AckSender = oneshot::Sender<AckResult>;
#[allow(dead_code)]
pub type AckReceiver = oneshot::Receiver<AckResult>;
#[derive(Debug)]
pub struct Event {
pub kind: String,
pub id: String,
pub payload: Value,
pub meta: Value,
pub ack_tx: Option<AckSender>,
}
impl Event {
#[allow(dead_code)]
pub fn fire_and_forget(kind: impl Into<String>, id: impl Into<String>, payload: Value) -> Self {
Self {
kind: kind.into(),
id: id.into(),
payload,
meta: Value::Null,
ack_tx: None,
}
}
#[allow(dead_code)]
pub fn with_ack(
kind: impl Into<String>,
id: impl Into<String>,
payload: Value,
meta: Value,
) -> (Self, AckReceiver) {
let (tx, rx) = oneshot::channel();
let evt = Self {
kind: kind.into(),
id: id.into(),
payload,
meta,
ack_tx: Some(tx),
};
(evt, rx)
}
pub fn deliver_ack(&mut self, result: AckResult) -> Result<(), BlockError> {
let Some(tx) = self.ack_tx.take() else {
return Ok(());
};
if let Err(dropped) = tx.send(result) {
tracing::warn!(
kind = %self.kind,
id = %self.id,
"ack receiver dropped; handler result discarded: {:?}",
dropped.as_ref().map(|_| "ok").unwrap_or_else(|e| match e {
BlockError::Bus(_) => "bus-err",
_ => "other-err",
})
);
return Err(BlockError::Bus(format!(
"ack receiver dropped (kind={}, id={})",
self.kind, self.id
)));
}
Ok(())
}
}