1#![deny(missing_docs)]
5#![deny(unsafe_code)]
6#![warn(clippy::all, clippy::pedantic)]
7#![allow(clippy::missing_errors_doc)]
8
9pub use sms_types as types;
10use crate::error::{ClientError, ClientResult};
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")]
103 pub async fn on_message<F>(&self, callback: F) -> ClientResult<()>
104 where
105 F: Fn(sms_types::events::Event, std::sync::Arc<Self>) + Send + Sync + 'static,
106 {
107 let ws_client = self
108 .ws_client
109 .as_ref()
110 .ok_or(ClientError::ConfigError("WebSocketClient"))?;
111
112 let mut ws_guard = ws_client.lock().await;
113 let client_arc = std::sync::Arc::new(self.clone());
114
115 ws_guard.on_message(move |msg| callback(msg, std::sync::Arc::clone(&client_arc)));
116
117 Ok(())
118 }
119
120 #[cfg(feature = "websocket")]
142 pub async fn on_message_simple<F>(&self, callback: F) -> ClientResult<()>
143 where
144 F: Fn(sms_types::events::Event) + Send + Sync + 'static,
145 {
146 let ws_client = self
147 .ws_client
148 .as_ref()
149 .ok_or(ClientError::ConfigError("WebSocketClient"))?;
150
151 let mut ws_guard = ws_client.lock().await;
152 ws_guard.on_message(callback);
153
154 Ok(())
155 }
156
157 #[cfg(feature = "websocket")]
159 pub async fn start_background_websocket(&self) -> ClientResult<()> {
160 let ws_client = self
161 .ws_client
162 .as_ref()
163 .ok_or(ClientError::ConfigError("WebsocketConfig"))?;
164
165 let mut ws_guard = ws_client.lock().await;
166 ws_guard.start_background().await?;
167
168 Ok(())
169 }
170
171 #[cfg(feature = "websocket")]
173 pub async fn start_blocking_websocket(&self) -> ClientResult<()> {
174 let ws_client = self
175 .ws_client
176 .as_ref()
177 .ok_or(ClientError::ConfigError("WebsocketConfig"))?;
178
179 let mut ws_guard = ws_client.lock().await;
180 ws_guard.start_blocking().await?;
181
182 Ok(())
183 }
184
185 #[cfg(feature = "websocket")]
187 pub async fn stop_background_websocket(&self) -> ClientResult<()> {
188 let ws_client = self
189 .ws_client
190 .as_ref()
191 .ok_or(ClientError::ConfigError("WebsocketConfig"))?;
192
193 let mut ws_guard = ws_client.lock().await;
194 ws_guard.stop_background().await?;
195
196 Ok(())
197 }
198
199 #[cfg(feature = "websocket")]
201 pub async fn is_websocket_connected(&self) -> bool {
202 let Some(ws_client) = &self.ws_client else {
203 return false;
204 };
205
206 let ws_guard = ws_client.lock().await;
207 ws_guard.is_connected().await
208 }
209
210 #[cfg(feature = "websocket")]
212 pub async fn reconnect_websocket(&self) -> ClientResult<()> {
213 let ws_client = self
214 .ws_client
215 .as_ref()
216 .ok_or(ClientError::NoWebsocketClient)?;
217
218 let ws_guard = ws_client.lock().await;
219 ws_guard.reconnect().await.map_err(ClientError::from)
220 }
221}
222impl Drop for Client {
223 fn drop(&mut self) {
224 }
227}