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