Skip to main content

binance_api_client/api/
userstream.rs

1//! User data stream API endpoints.
2//!
3//! This module provides endpoints for managing user data streams,
4//! which allow real-time account updates via WebSocket.
5
6use serde_json::Value;
7
8use crate::Result;
9use crate::client::Client;
10use crate::models::ListenKey;
11
12// API endpoints
13const API_V3_USER_DATA_STREAM: &str = "/api/v3/userDataStream";
14
15/// User data stream API client.
16///
17/// Provides endpoints for managing user data streams. A listen key is required
18/// to connect to the user data WebSocket stream for real-time account updates.
19///
20/// # Listen Key Lifecycle
21///
22/// 1. Start a stream with `start()` to get a listen key
23/// 2. Send keepalive every 30 minutes with `keepalive()` to prevent expiration
24/// 3. Close the stream with `close()` when done
25///
26/// Listen keys expire after 60 minutes without a keepalive.
27#[derive(Clone)]
28pub struct UserStream {
29    client: Client,
30}
31
32impl UserStream {
33    /// Create a new UserStream API client.
34    pub(crate) fn new(client: Client) -> Self {
35        Self { client }
36    }
37
38    /// Start a new user data stream.
39    ///
40    /// Returns a listen key that can be used to connect to the user data
41    /// WebSocket stream.
42    ///
43    /// # Example
44    ///
45    /// ```rust,ignore
46    /// let client = Binance::new("api_key", "secret_key")?;
47    /// let listen_key = client.user_stream().start().await?;
48    /// println!("Listen key: {}", listen_key);
49    ///
50    /// // Connect to WebSocket using: wss://stream.binance.com:9443/ws/{listen_key}
51    /// ```
52    pub async fn start(&self) -> Result<String> {
53        let response: ListenKey = self
54            .client
55            .post_with_key(API_V3_USER_DATA_STREAM, &[])
56            .await?;
57        Ok(response.listen_key)
58    }
59
60    /// Send a keepalive for a user data stream.
61    ///
62    /// This should be called every 30 minutes to prevent the listen key from
63    /// expiring. Listen keys expire after 60 minutes without a keepalive.
64    ///
65    /// # Arguments
66    ///
67    /// * `listen_key` - The listen key to keep alive
68    ///
69    /// # Example
70    ///
71    /// ```rust,ignore
72    /// let client = Binance::new("api_key", "secret_key")?;
73    /// let listen_key = client.user_stream().start().await?;
74    ///
75    /// // Every 30 minutes:
76    /// client.user_stream().keepalive(&listen_key).await?;
77    /// ```
78    pub async fn keepalive(&self, listen_key: &str) -> Result<()> {
79        let params = [("listenKey", listen_key)];
80        let _: Value = self
81            .client
82            .put_with_key(API_V3_USER_DATA_STREAM, &params)
83            .await?;
84        Ok(())
85    }
86
87    /// Close a user data stream.
88    ///
89    /// This invalidates the listen key and closes any WebSocket connections
90    /// using it.
91    ///
92    /// # Arguments
93    ///
94    /// * `listen_key` - The listen key to close
95    ///
96    /// # Example
97    ///
98    /// ```rust,ignore
99    /// let client = Binance::new("api_key", "secret_key")?;
100    /// let listen_key = client.user_stream().start().await?;
101    ///
102    /// // When done:
103    /// client.user_stream().close(&listen_key).await?;
104    /// ```
105    pub async fn close(&self, listen_key: &str) -> Result<()> {
106        let params = [("listenKey", listen_key)];
107        let _: Value = self
108            .client
109            .delete_with_key(API_V3_USER_DATA_STREAM, &params)
110            .await?;
111        Ok(())
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_api_endpoint() {
121        assert_eq!(API_V3_USER_DATA_STREAM, "/api/v3/userDataStream");
122    }
123}