mod connection;
mod protocol;
mod standard;
mod streams;
mod types;
pub use types::{
CloseInfo, ControlEvent, LoginConfirmation, MarketUpdate, QuoteUpdate, TradeUpdate,
WebSocketCluster, WebSocketConfig, WebSocketError, WebSocketEvent,
};
use crate::plan::Subscription;
use connection::{Connection, Socket};
use protocol::{TickerCommand, TickerData, normalize_symbols, validate_connection};
use url::Url;
pub use standard::StandardWebSocketClient;
pub use streams::{
AuthenticationStatus, Heartbeat, MarketStream, StreamConfig, StreamEntitlements, StreamQuote,
};
#[derive(Debug)]
pub struct WebSocketClient {
connection: Connection,
cluster: WebSocketCluster,
}
impl WebSocketClient {
pub async fn connect(
api_key: &str,
subscription: &Subscription,
cluster: WebSocketCluster,
config: WebSocketConfig,
) -> Result<Self, WebSocketError> {
let endpoint =
Url::parse(cluster.endpoint()).map_err(|error| WebSocketError::Configuration {
reason: format!("invalid documented cluster URL: {error}"),
})?;
Self::connect_to(api_key, subscription, cluster, endpoint, config).await
}
pub async fn connect_to(
api_key: &str,
subscription: &Subscription,
cluster: WebSocketCluster,
endpoint: Url,
config: WebSocketConfig,
) -> Result<Self, WebSocketError> {
validate_connection(api_key, subscription, cluster, &endpoint)?;
Ok(Self {
connection: Connection::connect(api_key, endpoint, config).await?,
cluster,
})
}
pub const fn cluster(&self) -> WebSocketCluster {
self.cluster
}
pub async fn subscribe(&mut self, symbols: &[&str]) -> Result<(), WebSocketError> {
let command = TickerCommand {
event: "subscribe",
data: TickerData {
ticker: normalize_symbols(symbols)?,
},
};
let json = serde_json::to_string(&command).map_err(|error| {
self.connection
.protocol_error(&error.to_string(), "subscribe serialization")
})?;
self.connection.send_text(json, "subscribe").await
}
pub async fn unsubscribe(&mut self, symbols: &[&str]) -> Result<(), WebSocketError> {
let command = TickerCommand {
event: "unsubscribe",
data: TickerData {
ticker: normalize_symbols(symbols)?,
},
};
let json = serde_json::to_string(&command).map_err(|error| {
self.connection
.protocol_error(&error.to_string(), "unsubscribe serialization")
})?;
self.connection.send_text(json, "unsubscribe").await
}
pub async fn next_event(&mut self) -> Result<WebSocketEvent, WebSocketError> {
self.connection.next_event().await
}
pub async fn close(self) -> Result<(), WebSocketError> {
self.connection.close().await
}
}