Skip to main content

acta_maker_sdk/ws/managed/
outbound.rs

1use crate::ws::client::PreparedClientMessage;
2use crate::ws::types::ClientMessage;
3use tokio::sync::oneshot;
4
5use super::ManagedWsError;
6
7/// Receipt for a message queued with `try_send`.
8///
9/// Dropping before dequeue cancels the send. Retain the ticket until
10/// [`wait()`](Self::wait) reports the socket-write result, not a server ACK.
11#[must_use = "dropping a SendTicket cancels the send if it has not been written yet"]
12pub struct SendTicket {
13    pub(super) rx: oneshot::Receiver<Result<(), ManagedWsError>>,
14}
15
16impl SendTicket {
17    pub async fn wait(self) -> Result<(), ManagedWsError> {
18        match self.rx.await {
19            Ok(result) => result,
20            Err(_) => Err(ManagedWsError::Disconnected),
21        }
22    }
23}
24
25#[derive(Debug, thiserror::Error)]
26#[non_exhaustive]
27pub enum OutboundMessageError {
28    #[error("taker_buy_unsupported")]
29    TakerBuyUnsupported,
30    #[error("batch contains {actual} quotes, maximum is {limit}")]
31    BatchTooLarge { actual: usize, limit: usize },
32    #[error("serialized message is {actual} bytes, maximum is {limit}")]
33    MessageTooLarge { actual: usize, limit: usize },
34    #[error("message serialization failed: {0}")]
35    Serialization(#[from] serde_json::Error),
36}
37
38pub(super) fn prepare_outbound(
39    message: &ClientMessage,
40    max_batch_quotes: usize,
41    max_message_size: usize,
42) -> Result<PreparedClientMessage, OutboundMessageError> {
43    if has_unsupported_buy(message) {
44        return Err(OutboundMessageError::TakerBuyUnsupported);
45    }
46    if let ClientMessage::BatchQuotes(batch) = message
47        && batch.quotes.len() > max_batch_quotes
48    {
49        return Err(OutboundMessageError::BatchTooLarge {
50            actual: batch.quotes.len(),
51            limit: max_batch_quotes,
52        });
53    }
54    let prepared = PreparedClientMessage::new(message)?;
55    if prepared.len() > max_message_size {
56        return Err(OutboundMessageError::MessageTooLarge {
57            actual: prepared.len(),
58            limit: max_message_size,
59        });
60    }
61    Ok(prepared)
62}
63
64/// Vaults never request buys; makers quote them.
65fn has_unsupported_buy(message: &ClientMessage) -> bool {
66    matches!(message, ClientMessage::RfqRequest(request) if request.side.is_taker_buy())
67}