1#![deny(missing_docs)]
5#![deny(unsafe_code)]
6#![warn(clippy::all, clippy::pedantic)]
7
8use crate::error::*;
9
10pub mod http;
11pub mod config;
12pub mod error;
13pub mod types;
14
15#[cfg(feature = "websocket")]
16pub mod ws;
17
18#[derive(Clone, Debug)]
20pub struct Client {
21 http: std::sync::Arc<http::HttpClient>,
22
23 #[cfg(feature = "websocket")]
24 ws_client: std::sync::Arc<tokio::sync::RwLock<Option<ws::WebsocketClient>>>,
25
26 #[cfg(feature = "websocket")]
27 ws_config: Option<config::WebsocketConfig>
28}
29impl Client {
30
31 pub fn new(config: config::ClientConfig) -> ClientResult<Self> {
33 let http = http::HttpClient::new(config.http)?;
34 Ok(Self {
35 http: std::sync::Arc::new(http),
36
37 #[cfg(feature = "websocket")]
38 ws_client: std::sync::Arc::new(tokio::sync::RwLock::new(None)),
39
40 #[cfg(feature = "websocket")]
41 ws_config: config.websocket
42 })
43 }
44
45 pub fn http(&self) -> &http::HttpClient {
47 &self.http
48 }
49
50 pub fn http_arc(&self) -> std::sync::Arc<http::HttpClient> {
52 std::sync::Arc::clone(&self.http)
53 }
54
55 #[cfg(feature = "websocket")]
58 pub async fn on_message<F>(&self, callback: F) -> ClientResult<()>
59 where
60 F: Fn(ws::types::WebsocketMessage, std::sync::Arc<Self>) + Send + Sync + 'static,
61 {
62 let mut ws_guard = self.create_or_get_ws_client().await?;
63 if let Some(ws_client) = ws_guard.as_mut() {
64 let client = std::sync::Arc::new(self.clone());
65 ws_client.on_message(move |msg| {
66 callback(msg, std::sync::Arc::clone(&client));
67 });
68 }
69 Ok(())
70 }
71
72 #[cfg(feature = "websocket")]
75 pub async fn on_message_simple<F>(&self, callback: F) -> ClientResult<()>
76 where
77 F: Fn(ws::types::WebsocketMessage) + Send + Sync + 'static,
78 {
79 let mut ws_guard = self.create_or_get_ws_client().await?;
80 if let Some(ws_client) = ws_guard.as_mut() {
81 ws_client.on_message(callback);
82 }
83 Ok(())
84 }
85
86 #[cfg(feature = "websocket")]
88 pub async fn start_background_websocket(&self) -> ClientResult<()> {
89 let mut ws_guard = self.create_or_get_ws_client().await?;
90 if let Some(ws_client) = ws_guard.as_mut() {
91 ws_client.start_background().await?;
92 }
93 Ok(())
94 }
95
96 #[cfg(feature = "websocket")]
98 pub async fn start_blocking_websocket(&self) -> ClientResult<()> {
99 let mut ws_guard = self.create_or_get_ws_client().await?;
100 if let Some(ws_client) = ws_guard.as_mut() {
101 ws_client.start_blocking().await?;
102 }
103 Ok(())
104 }
105
106 #[cfg(feature = "websocket")]
108 pub async fn stop_background_websocket(&self) -> ClientResult<()> {
109 let mut ws_guard = self.ws_client.write().await;
110
111 if let Some(ws_client) = ws_guard.as_mut() {
112 ws_client.stop_background().await?;
113 }
114
115 Ok(())
116 }
117
118 #[cfg(feature = "websocket")]
120 pub async fn is_websocket_connected(&self) -> bool {
121 let ws_guard = self.ws_client.read().await;
122
123 if let Some(ws_client) = ws_guard.as_ref() {
124 ws_client.is_connected().await
125 } else {
126 false
127 }
128 }
129
130 #[cfg(feature = "websocket")]
132 pub async fn reconnect_websocket(&self) -> ClientResult<()> {
133 let ws_guard = self.ws_client.read().await;
134
135 if let Some(ws_client) = ws_guard.as_ref() {
136 ws_client.reconnect().await?;
137 Ok(())
138 } else {
139 Err(ClientError::NoWebsocketClient)
140 }
141 }
142
143 #[cfg(feature = "websocket")]
145 async fn create_or_get_ws_client(&self) -> ClientResult<tokio::sync::RwLockWriteGuard<'_, Option<ws::WebsocketClient>>> {
146 let mut ws_guard = self.ws_client.write().await;
147 if ws_guard.is_none() {
148 let config = match self.ws_config.clone() {
149 Some(config) => config,
150 None => return Err(ClientError::MissingConfiguration("WebsocketConfig"))
151 };
152
153 let ws_client = ws::WebsocketClient::new(config);
154 *ws_guard = Some(ws_client);
155 }
156
157 Ok(ws_guard)
158 }
159}
160impl Drop for Client {
161 fn drop(&mut self) {
162 }
165}