1#![deny(missing_docs)]
5#![deny(unsafe_code)]
6#![warn(clippy::all, clippy::pedantic)]
7
8use crate::error::*;
9
10pub mod config;
11pub mod error;
12pub mod types;
13
14#[cfg(feature = "http")]
15pub mod http;
16
17#[cfg(feature = "websocket")]
18pub mod ws;
19
20#[derive(Clone, Debug)]
22pub struct Client {
23
24 #[cfg(feature = "http")]
25 http: Option<std::sync::Arc<http::HttpClient>>,
26
27 #[cfg(feature = "websocket")]
28 ws_client: std::sync::Arc<tokio::sync::RwLock<Option<ws::WebSocketClient>>>,
29
30 #[cfg(feature = "websocket")]
31 ws_config: (Option<config::WebSocketConfig>, Option<config::TLSConfig>)
32}
33impl Client {
34
35 pub fn new(config: config::ClientConfig) -> ClientResult<Self> {
37 let tls = config.tls;
38
39 #[cfg(feature = "websocket-tls-rustls")]
40 let _ = rustls::crypto::CryptoProvider::install_default(
41 rustls::crypto::aws_lc_rs::default_provider()
42 );
43
44 Ok(Self {
45
46 #[cfg(feature = "http")]
47 http: config.http.map(|config| http::HttpClient::new(config, &tls).map(std::sync::Arc::new)).transpose()?,
48
49 #[cfg(feature = "websocket")]
50 ws_client: std::sync::Arc::new(tokio::sync::RwLock::new(None)),
51
52 #[cfg(feature = "websocket")]
53 ws_config: (config.websocket, tls)
54 })
55 }
56
57 #[cfg(feature = "http")]
59 pub fn http(&self) -> ClientResult<&http::HttpClient> {
60 match &self.http {
61 Some(http) => Ok(http),
62 None => Err(ClientError::ConfigError("HttpClient"))
63 }
64 }
65
66 #[cfg(feature = "http")]
68 pub fn http_arc(&self) -> ClientResult<std::sync::Arc<http::HttpClient>> {
69 match &self.http {
70 Some(http) => Ok(http.clone()),
71 None => Err(ClientError::ConfigError("HttpClient"))
72 }
73 }
74
75 #[cfg(feature = "websocket")]
101 pub async fn on_message<F>(&self, callback: F) -> ClientResult<()>
102 where
103 F: Fn(ws::types::WebsocketMessage, std::sync::Arc<Self>) + Send + Sync + 'static,
104 {
105 let mut ws_guard = self.create_or_get_ws_client().await?;
106 if let Some(ws_client) = ws_guard.as_mut() {
107 let client = std::sync::Arc::new(self.clone());
108 ws_client.on_message(move |msg| {
109 callback(msg, std::sync::Arc::clone(&client));
110 });
111 }
112 Ok(())
113 }
114
115 #[cfg(feature = "websocket")]
137 pub async fn on_message_simple<F>(&self, callback: F) -> ClientResult<()>
138 where
139 F: Fn(ws::types::WebsocketMessage) + Send + Sync + 'static,
140 {
141 let mut ws_guard = self.create_or_get_ws_client().await?;
142 if let Some(ws_client) = ws_guard.as_mut() {
143 ws_client.on_message(callback);
144 }
145 Ok(())
146 }
147
148 #[cfg(feature = "websocket")]
150 pub async fn start_background_websocket(&self) -> ClientResult<()> {
151 let mut ws_guard = self.create_or_get_ws_client().await?;
152 if let Some(ws_client) = ws_guard.as_mut() {
153 ws_client.start_background().await?;
154 }
155 Ok(())
156 }
157
158 #[cfg(feature = "websocket")]
160 pub async fn start_blocking_websocket(&self) -> ClientResult<()> {
161 let mut ws_guard = self.create_or_get_ws_client().await?;
162 if let Some(ws_client) = ws_guard.as_mut() {
163 ws_client.start_blocking().await?;
164 }
165 Ok(())
166 }
167
168 #[cfg(feature = "websocket")]
170 pub async fn stop_background_websocket(&self) -> ClientResult<()> {
171 let mut ws_guard = self.ws_client.write().await;
172
173 if let Some(ws_client) = ws_guard.as_mut() {
174 ws_client.stop_background().await?;
175 }
176
177 Ok(())
178 }
179
180 #[cfg(feature = "websocket")]
182 pub async fn is_websocket_connected(&self) -> bool {
183 let ws_guard = self.ws_client.read().await;
184
185 if let Some(ws_client) = ws_guard.as_ref() {
186 ws_client.is_connected().await
187 } else {
188 false
189 }
190 }
191
192 #[cfg(feature = "websocket")]
194 pub async fn reconnect_websocket(&self) -> ClientResult<()> {
195 let ws_guard = self.ws_client.read().await;
196
197 if let Some(ws_client) = ws_guard.as_ref() {
198 ws_client.reconnect().await?;
199 Ok(())
200 } else {
201 Err(ClientError::NoWebsocketClient)
202 }
203 }
204
205 #[cfg(feature = "websocket")]
207 async fn create_or_get_ws_client(&self) -> ClientResult<tokio::sync::RwLockWriteGuard<'_, Option<ws::WebSocketClient>>> {
208 let mut ws_guard = self.ws_client.write().await;
209 if ws_guard.is_none() {
210 let (ws_config, tls_config) = match self.ws_config.clone() {
211 (Some(config), tls) => (config, tls),
212 _ => return Err(ClientError::ConfigError("WebsocketConfig"))
213 };
214
215 let ws_client = ws::WebSocketClient::new(ws_config, tls_config);
216 *ws_guard = Some(ws_client);
217 }
218
219 Ok(ws_guard)
220 }
221}
222impl Drop for Client {
223 fn drop(&mut self) {
224 }
227}