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, ¶ms)
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, ¶ms)
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}