polyte_clob/ws/mod.rs
1//! WebSocket client for real-time Polymarket CLOB updates.
2//!
3//! This module provides WebSocket connectivity to Polymarket's real-time data streams,
4//! including market data (order book updates, price changes) and user-specific updates
5//! (orders, trades).
6//!
7//! # Channels
8//!
9//! Two channels are available:
10//!
11//! - **Market Channel**: Public channel for order book and price updates. Subscribe with
12//! asset IDs (token IDs) to receive [`BookMessage`], [`PriceChangeMessage`],
13//! [`TickSizeChangeMessage`], and [`LastTradePriceMessage`] updates.
14//!
15//! - **User Channel**: Authenticated channel for user order and trade updates. Subscribe
16//! with market condition IDs and API credentials to receive [`OrderMessage`] and
17//! [`TradeMessage`] updates.
18//!
19//! # Basic Example
20//!
21//! ```no_run
22//! use polyte_clob::ws::{WebSocket, Channel, MarketMessage};
23//! use futures_util::StreamExt;
24//!
25//! #[tokio::main]
26//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
27//! // Connect to market channel (no auth required)
28//! let mut ws = WebSocket::connect_market(vec![
29//! "asset_id_1".to_string(),
30//! "asset_id_2".to_string(),
31//! ]).await?;
32//!
33//! // Process incoming messages
34//! while let Some(msg) = ws.next().await {
35//! match msg? {
36//! Channel::Market(MarketMessage::Book(book)) => {
37//! println!("Order book: {} bids, {} asks", book.bids.len(), book.asks.len());
38//! }
39//! Channel::Market(MarketMessage::PriceChange(pc)) => {
40//! println!("Price change: {:?}", pc.price_changes);
41//! }
42//! _ => {}
43//! }
44//! }
45//!
46//! Ok(())
47//! }
48//! ```
49//!
50//! # Authenticated User Channel
51//!
52//! ```no_run
53//! use polyte_clob::ws::{ApiCredentials, WebSocket, Channel, UserMessage};
54//! use futures_util::StreamExt;
55//!
56//! #[tokio::main]
57//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
58//! let credentials = ApiCredentials::from_env()?;
59//!
60//! let mut ws = WebSocket::connect_user(
61//! vec!["condition_id".to_string()],
62//! credentials,
63//! ).await?;
64//!
65//! while let Some(msg) = ws.next().await {
66//! match msg? {
67//! Channel::User(UserMessage::Order(order)) => {
68//! println!("Order update: {} {:?}", order.id, order.order_type);
69//! }
70//! Channel::User(UserMessage::Trade(trade)) => {
71//! println!("Trade: {} @ {}", trade.size, trade.price);
72//! }
73//! _ => {}
74//! }
75//! }
76//!
77//! Ok(())
78//! }
79//! ```
80//!
81//! # Auto-Ping with WebSocketBuilder
82//!
83//! For long-running connections, use [`WebSocketBuilder`] to automatically send
84//! keep-alive pings:
85//!
86//! ```no_run
87//! use polyte_clob::ws::{WebSocketBuilder, Channel};
88//! use std::time::Duration;
89//!
90//! #[tokio::main]
91//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
92//! let ws = WebSocketBuilder::new()
93//! .ping_interval(Duration::from_secs(10))
94//! .connect_market(vec!["asset_id".to_string()])
95//! .await?;
96//!
97//! ws.run(|msg| async move {
98//! println!("Received: {:?}", msg);
99//! Ok(())
100//! }).await?;
101//!
102//! Ok(())
103//! }
104//! ```
105
106mod auth;
107mod client;
108mod error;
109mod market;
110mod subscription;
111mod user;
112
113pub use auth::ApiCredentials;
114pub use client::{WebSocket, WebSocketBuilder, WebSocketWithPing};
115pub use error::WebSocketError;
116pub use market::{
117 BookMessage, LastTradePriceMessage, MarketMessage, OrderSummary, PriceChange,
118 PriceChangeMessage, TickSizeChangeMessage,
119};
120pub use subscription::ChannelType;
121pub use user::{MakerOrder, OrderEventType, OrderMessage, TradeMessage, TradeStatus, UserMessage};
122
123/// All possible WebSocket channel messages
124#[derive(Debug, Clone)]
125pub enum Channel {
126 /// Market channel message
127 Market(MarketMessage),
128 /// User channel message
129 User(UserMessage),
130}