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