Skip to main content

acta_maker_sdk/ws/maker/
quote.rs

1use crate::ws::managed::{
2    MakerWsEndpoint, ManagedMessageReceiver, ManagedWsConfig, ManagedWsError, ManagedWsEvent,
3    ManagedWsHandle, ManagedWsState, SendTicket, WaitUntilReadyError, spawn_managed_ws,
4};
5use crate::ws::types::{
6    AddChannelsData, AddMintsData, BatchQuotesMessage, CancelAllQuotesMessage, CancelQuoteData,
7    ClientMessage, IndicativePricesResponseMessage, QuoteMessage, RemoveChannelsData,
8    RemoveMintsData, ReplaceQuoteMessage, SubscribeData, UnsubscribeData,
9};
10use tokio::sync::broadcast;
11
12use super::MakerClientError;
13
14/// Maker quote-plane client.
15///
16/// `try_*` methods return immediately when the outbound queue is full. A
17/// successful [`SendTicket`] reports a socket write, not a server acknowledgement.
18#[derive(Clone)]
19pub struct MakerQuoteClient {
20    inner: ManagedWsHandle,
21}
22
23impl MakerQuoteClient {
24    pub fn spawn(config: ManagedWsConfig) -> Result<Self, MakerClientError> {
25        if config.endpoint != MakerWsEndpoint::Quote {
26            return Err(MakerClientError::WrongEndpoint {
27                client: "MakerQuoteClient",
28                required: MakerWsEndpoint::Quote,
29                actual: config.endpoint,
30            });
31        }
32        Ok(Self {
33            inner: spawn_managed_ws(config)?,
34        })
35    }
36
37    pub async fn quote(&self, payload: QuoteMessage) -> Result<(), ManagedWsError> {
38        self.inner.ensure_ready()?;
39        self.inner.send(ClientMessage::Quote(payload)).await
40    }
41
42    pub fn try_quote(&self, payload: QuoteMessage) -> Result<SendTicket, ManagedWsError> {
43        self.inner.ensure_ready()?;
44        self.inner.try_send(ClientMessage::Quote(payload))
45    }
46
47    pub async fn replace_quote(&self, payload: ReplaceQuoteMessage) -> Result<(), ManagedWsError> {
48        self.inner.ensure_ready()?;
49        self.inner.send(ClientMessage::ReplaceQuote(payload)).await
50    }
51
52    pub fn try_replace_quote(
53        &self,
54        payload: ReplaceQuoteMessage,
55    ) -> Result<SendTicket, ManagedWsError> {
56        self.inner.ensure_ready()?;
57        self.inner.try_send(ClientMessage::ReplaceQuote(payload))
58    }
59
60    pub async fn batch_quotes(&self, payload: BatchQuotesMessage) -> Result<(), ManagedWsError> {
61        self.inner.ensure_ready()?;
62        self.inner.send(ClientMessage::BatchQuotes(payload)).await
63    }
64
65    pub fn try_batch_quotes(
66        &self,
67        payload: BatchQuotesMessage,
68    ) -> Result<SendTicket, ManagedWsError> {
69        self.inner.ensure_ready()?;
70        self.inner.try_send(ClientMessage::BatchQuotes(payload))
71    }
72
73    pub async fn cancel_quote(&self, payload: CancelQuoteData) -> Result<(), ManagedWsError> {
74        self.inner.ensure_ready()?;
75        self.inner.send(ClientMessage::CancelQuote(payload)).await
76    }
77
78    pub fn try_cancel_quote(&self, payload: CancelQuoteData) -> Result<SendTicket, ManagedWsError> {
79        self.inner.ensure_ready()?;
80        self.inner.try_send(ClientMessage::CancelQuote(payload))
81    }
82
83    pub async fn cancel_all_quotes(
84        &self,
85        payload: CancelAllQuotesMessage,
86    ) -> Result<(), ManagedWsError> {
87        self.inner.ensure_ready()?;
88        self.inner
89            .send(ClientMessage::CancelAllQuotes(payload))
90            .await
91    }
92
93    pub fn try_cancel_all_quotes(
94        &self,
95        payload: CancelAllQuotesMessage,
96    ) -> Result<SendTicket, ManagedWsError> {
97        self.inner.ensure_ready()?;
98        self.inner.try_send(ClientMessage::CancelAllQuotes(payload))
99    }
100
101    pub async fn indicative_prices_response(
102        &self,
103        payload: IndicativePricesResponseMessage,
104    ) -> Result<(), ManagedWsError> {
105        self.inner.ensure_ready()?;
106        self.inner
107            .send(ClientMessage::IndicativePricesResponse(payload))
108            .await
109    }
110
111    pub fn try_indicative_prices_response(
112        &self,
113        payload: IndicativePricesResponseMessage,
114    ) -> Result<SendTicket, ManagedWsError> {
115        self.inner.ensure_ready()?;
116        self.inner
117            .try_send(ClientMessage::IndicativePricesResponse(payload))
118    }
119
120    pub async fn subscribe(&self, payload: SubscribeData) -> Result<(), ManagedWsError> {
121        self.inner.ensure_ready()?;
122        self.inner.send(ClientMessage::Subscribe(payload)).await
123    }
124
125    pub async fn unsubscribe(&self, payload: UnsubscribeData) -> Result<(), ManagedWsError> {
126        self.inner.ensure_ready()?;
127        self.inner.send(ClientMessage::Unsubscribe(payload)).await
128    }
129
130    pub async fn add_mints(&self, payload: AddMintsData) -> Result<(), ManagedWsError> {
131        self.inner.ensure_ready()?;
132        self.inner.send(ClientMessage::AddMints(payload)).await
133    }
134
135    pub async fn remove_mints(&self, payload: RemoveMintsData) -> Result<(), ManagedWsError> {
136        self.inner.ensure_ready()?;
137        self.inner.send(ClientMessage::RemoveMints(payload)).await
138    }
139
140    pub async fn add_channels(&self, payload: AddChannelsData) -> Result<(), ManagedWsError> {
141        self.inner.ensure_ready()?;
142        self.inner.send(ClientMessage::AddChannels(payload)).await
143    }
144
145    pub async fn remove_channels(&self, payload: RemoveChannelsData) -> Result<(), ManagedWsError> {
146        self.inner.ensure_ready()?;
147        self.inner
148            .send(ClientMessage::RemoveChannels(payload))
149            .await
150    }
151
152    pub fn subscribe_messages(&self) -> ManagedMessageReceiver {
153        self.inner.subscribe_messages()
154    }
155
156    pub fn subscribe_events(&self) -> broadcast::Receiver<ManagedWsEvent> {
157        self.inner.subscribe_events()
158    }
159
160    #[must_use]
161    pub fn state(&self) -> ManagedWsState {
162        self.inner.state()
163    }
164
165    pub async fn wait_until_ready(&self) -> Result<u64, WaitUntilReadyError> {
166        self.inner.wait_until_ready().await
167    }
168
169    #[must_use]
170    pub const fn raw(&self) -> &ManagedWsHandle {
171        &self.inner
172    }
173
174    #[must_use]
175    pub fn into_raw(self) -> ManagedWsHandle {
176        self.inner
177    }
178
179    pub async fn close(&self) -> Result<(), ManagedWsError> {
180        self.inner.close().await
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use std::sync::Arc;
187
188    use super::*;
189    use crate::ws::types::HelloData;
190
191    #[test]
192    fn quote_client_rejects_data_endpoint_before_spawning() {
193        let config = ManagedWsConfig::new(
194            "ws://localhost",
195            HelloData {
196                protocol_version: "1.0.0".to_string(),
197                features: Vec::new(),
198                client_name: None,
199                client_version: None,
200            },
201            Arc::new(crate::orders::BytesSigner::from_secret([1u8; 32])),
202        )
203        .with_endpoint(MakerWsEndpoint::Data);
204
205        assert!(matches!(
206            MakerQuoteClient::spawn(config),
207            Err(MakerClientError::WrongEndpoint {
208                required: MakerWsEndpoint::Quote,
209                actual: MakerWsEndpoint::Data,
210                ..
211            })
212        ));
213    }
214}