#![deny(missing_docs)]
#![deny(unsafe_code)]
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]
use crate::error::{ClientError, ClientResult};
pub use sms_types as types;
pub mod config;
pub mod error;
#[cfg(feature = "http")]
pub mod http;
#[cfg(feature = "websocket")]
pub mod ws;
#[derive(Clone, Debug)]
pub struct Client {
#[cfg(feature = "http")]
http_client: Option<std::sync::Arc<http::HttpClient>>,
#[cfg(feature = "websocket")]
ws_client: Option<std::sync::Arc<tokio::sync::Mutex<ws::WebSocketClient>>>,
}
impl Client {
pub fn new(config: config::ClientConfig) -> ClientResult<Self> {
let tls = config.tls;
#[cfg(feature = "http")]
let http_client = if let Some(http_config) = config.http {
Some(std::sync::Arc::new(http::HttpClient::new(
http_config,
tls.as_ref(),
)?))
} else {
None
};
#[cfg(feature = "websocket")]
let ws_client = config.websocket.map(|ws_config| {
std::sync::Arc::new(tokio::sync::Mutex::new(ws::WebSocketClient::new(
ws_config, tls,
)))
});
Ok(Self {
#[cfg(feature = "http")]
http_client,
#[cfg(feature = "websocket")]
ws_client,
})
}
#[cfg(feature = "http")]
pub fn http(&self) -> ClientResult<&http::HttpClient> {
self.http_client
.as_ref()
.map(std::convert::AsRef::as_ref)
.ok_or(ClientError::ConfigError("HttpClient"))
}
#[cfg(feature = "http")]
pub fn http_arc(&self) -> ClientResult<std::sync::Arc<http::HttpClient>> {
self.http_client
.clone()
.ok_or(ClientError::ConfigError("HttpClient"))
}
#[cfg(feature = "websocket")]
pub async fn on_message<F>(&self, callback: F) -> ClientResult<()>
where
F: Fn(ws::events::WebsocketEvent, std::sync::Arc<Self>) + Send + Sync + 'static,
{
let ws_client = self
.ws_client
.as_ref()
.ok_or(ClientError::ConfigError("WebSocketClient"))?;
let mut ws_guard = ws_client.lock().await;
let client_arc = std::sync::Arc::new(self.clone());
ws_guard.on_message(move |msg| callback(msg, std::sync::Arc::clone(&client_arc)));
Ok(())
}
#[cfg(feature = "websocket")]
pub async fn on_message_simple<F>(&self, callback: F) -> ClientResult<()>
where
F: Fn(ws::events::WebsocketEvent) + Send + Sync + 'static,
{
let ws_client = self
.ws_client
.as_ref()
.ok_or(ClientError::ConfigError("WebSocketClient"))?;
let mut ws_guard = ws_client.lock().await;
ws_guard.on_message(callback);
Ok(())
}
#[cfg(feature = "websocket")]
pub async fn start_background_websocket(&self) -> ClientResult<()> {
let ws_client = self
.ws_client
.as_ref()
.ok_or(ClientError::ConfigError("WebsocketConfig"))?;
let mut ws_guard = ws_client.lock().await;
ws_guard.start_background().await?;
Ok(())
}
#[cfg(feature = "websocket")]
pub async fn start_blocking_websocket(&self) -> ClientResult<()> {
let ws_client = self
.ws_client
.as_ref()
.ok_or(ClientError::ConfigError("WebsocketConfig"))?;
let mut ws_guard = ws_client.lock().await;
ws_guard.start_blocking().await?;
Ok(())
}
#[cfg(feature = "websocket")]
pub async fn stop_background_websocket(&self) -> ClientResult<()> {
let ws_client = self
.ws_client
.as_ref()
.ok_or(ClientError::ConfigError("WebsocketConfig"))?;
let mut ws_guard = ws_client.lock().await;
ws_guard.stop_background().await?;
Ok(())
}
#[cfg(feature = "websocket")]
pub async fn is_websocket_connected(&self) -> bool {
let Some(ws_client) = &self.ws_client else {
return false;
};
let ws_guard = ws_client.lock().await;
ws_guard.is_connected().await
}
#[cfg(feature = "websocket")]
pub async fn reconnect_websocket(&self) -> ClientResult<()> {
let ws_client = self
.ws_client
.as_ref()
.ok_or(ClientError::NoWebsocketClient)?;
let ws_guard = ws_client.lock().await;
ws_guard.reconnect().await.map_err(ClientError::from)
}
}
impl Drop for Client {
fn drop(&mut self) {
}
}