pub use ramqp_core::txn::{
Declare, Declared, Discharge, TransactionalState, TxnId, capabilities, transactional_state,
};
use ramqp_core::txn::{control_message, declared_txn_id};
use crate::api::producer::Producer;
use crate::error::{ErrorKind, SendError};
use crate::types::messaging::DeliveryState;
#[derive(Debug)]
pub struct TransactionController {
control: Producer,
}
impl TransactionController {
pub fn new(control: Producer) -> Self {
TransactionController { control }
}
pub async fn declare(&self) -> Result<TxnId, SendError> {
let body = control_message(&Declare { global_id: None });
let outcome = self.control.send_bytes(body, false).await?;
declared_txn_id(&outcome).ok_or_else(|| {
SendError::msg(
ErrorKind::ProtocolViolation,
"coordinator did not return a declared outcome",
)
})
}
pub async fn discharge(&self, txn_id: TxnId, fail: bool) -> Result<(), SendError> {
let body = control_message(&Discharge { txn_id, fail });
let outcome = self.control.send_bytes(body, false).await?;
match outcome {
DeliveryState::Accepted(_) => Ok(()),
DeliveryState::Rejected(r) => {
let mut msg = String::from("transaction discharge was rejected");
if let Some(e) = &r.error {
msg.push_str(": ");
msg.push_str(&e.to_string());
}
Err(SendError::msg(ErrorKind::ProtocolViolation, msg))
}
other => Err(SendError::msg(
ErrorKind::ProtocolViolation,
format!("unexpected discharge outcome: {other:?}"),
)),
}
}
pub async fn commit(&self, txn_id: TxnId) -> Result<(), SendError> {
self.discharge(txn_id, false).await
}
pub async fn rollback(&self, txn_id: TxnId) -> Result<(), SendError> {
self.discharge(txn_id, true).await
}
}