1#![deny(missing_docs)]
5#![deny(unsafe_code)]
6#![warn(clippy::all, clippy::pedantic)]
7#![allow(clippy::missing_errors_doc)]
8
9use crate::error::{ClientError, ClientResult};
10pub use sms_types as types;
11
12pub mod config;
13pub mod error;
14
15#[cfg(feature = "http")]
16pub mod http;
17
18#[cfg(feature = "websocket")]
19pub mod ws;
20
21#[derive(Clone, Debug)]
23pub struct Client {
24 #[cfg(feature = "http")]
25 http_client: Option<std::sync::Arc<http::HttpClient>>,
26
27 #[cfg(feature = "websocket")]
28 ws_client: Option<std::sync::Arc<tokio::sync::Mutex<ws::WebSocketClient>>>,
29}
30impl Client {
31 pub fn new(config: config::ClientConfig) -> ClientResult<Self> {
33 let tls = config.tls;
34
35 #[cfg(feature = "http")]
36 let http_client = if let Some(http_config) = config.http {
37 Some(std::sync::Arc::new(http::HttpClient::new(
38 http_config,
39 tls.as_ref(),
40 )?))
41 } else {
42 None
43 };
44
45 #[cfg(feature = "websocket")]
46 let ws_client = config.websocket.map(|ws_config| {
47 std::sync::Arc::new(tokio::sync::Mutex::new(ws::WebSocketClient::new(
48 ws_config, tls,
49 )))
50 });
51
52 Ok(Self {
53 #[cfg(feature = "http")]
54 http_client,
55
56 #[cfg(feature = "websocket")]
57 ws_client,
58 })
59 }
60
61 #[cfg(feature = "http")]
63 pub fn http(&self) -> ClientResult<&http::HttpClient> {
64 self.http_client
65 .as_ref()
66 .map(std::convert::AsRef::as_ref)
67 .ok_or(ClientError::ConfigError("HttpClient"))
68 }
69
70 #[cfg(feature = "http")]
72 pub fn http_arc(&self) -> ClientResult<std::sync::Arc<http::HttpClient>> {
73 self.http_client
74 .clone()
75 .ok_or(ClientError::ConfigError("HttpClient"))
76 }
77
78 #[cfg(feature = "websocket")]
107 pub async fn on_message<F>(&self, callback: F) -> ClientResult<()>
108 where
109 F: Fn(ws::events::WebsocketEvent, std::sync::Arc<Self>) + Send + Sync + 'static,
110 {
111 let ws_client = self
112 .ws_client
113 .as_ref()
114 .ok_or(ClientError::ConfigError("WebSocketClient"))?;
115
116 let mut ws_guard = ws_client.lock().await;
117 let client_arc = std::sync::Arc::new(self.clone());
118
119 ws_guard.on_message(move |msg| callback(msg, std::sync::Arc::clone(&client_arc)));
120
121 Ok(())
122 }
123
124 #[cfg(feature = "websocket")]
147 pub async fn on_message_simple<F>(&self, callback: F) -> ClientResult<()>
148 where
149 F: Fn(ws::events::WebsocketEvent) + Send + Sync + 'static,
150 {
151 let ws_client = self
152 .ws_client
153 .as_ref()
154 .ok_or(ClientError::ConfigError("WebSocketClient"))?;
155
156 let mut ws_guard = ws_client.lock().await;
157 ws_guard.on_message(callback);
158
159 Ok(())
160 }
161
162 #[cfg(feature = "websocket")]
164 pub async fn start_background_websocket(&self) -> ClientResult<()> {
165 let ws_client = self
166 .ws_client
167 .as_ref()
168 .ok_or(ClientError::ConfigError("WebsocketConfig"))?;
169
170 let mut ws_guard = ws_client.lock().await;
171 ws_guard.start_background().await?;
172
173 Ok(())
174 }
175
176 #[cfg(feature = "websocket")]
178 pub async fn start_blocking_websocket(&self) -> ClientResult<()> {
179 let ws_client = self
180 .ws_client
181 .as_ref()
182 .ok_or(ClientError::ConfigError("WebsocketConfig"))?;
183
184 let mut ws_guard = ws_client.lock().await;
185 ws_guard.start_blocking().await?;
186
187 Ok(())
188 }
189
190 #[cfg(feature = "websocket")]
192 pub async fn stop_background_websocket(&self) -> ClientResult<()> {
193 let ws_client = self
194 .ws_client
195 .as_ref()
196 .ok_or(ClientError::ConfigError("WebsocketConfig"))?;
197
198 let mut ws_guard = ws_client.lock().await;
199 ws_guard.stop_background().await?;
200
201 Ok(())
202 }
203
204 #[cfg(feature = "websocket")]
206 pub async fn is_websocket_connected(&self) -> bool {
207 let Some(ws_client) = &self.ws_client else {
208 return false;
209 };
210
211 let ws_guard = ws_client.lock().await;
212 ws_guard.is_connected().await
213 }
214
215 #[cfg(feature = "websocket")]
217 pub async fn reconnect_websocket(&self) -> ClientResult<()> {
218 let ws_client = self
219 .ws_client
220 .as_ref()
221 .ok_or(ClientError::NoWebsocketClient)?;
222
223 let ws_guard = ws_client.lock().await;
224 ws_guard.reconnect().await.map_err(ClientError::from)
225 }
226}
227impl Drop for Client {
228 fn drop(&mut self) {
229 }
232}