Skip to main content

zai_rs/realtime/
client.rs

1//! [`RealtimeClient`] — entry point for the realtime API.
2
3use std::sync::Arc;
4
5use super::session::SessionBuilder;
6use crate::client::endpoints::{ApiBase, EndpointConfig};
7
8/// Authentication mode for the realtime WebSocket handshake.
9#[derive(Debug, Clone)]
10pub enum AuthMode {
11    /// Server-side Bearer auth: `Authorization: Bearer {API_KEY}` (default).
12    Bearer,
13    /// Client-side JWT auth: a short-lived token signed from the API key's
14    /// secret, so the secret never leaves the server. Used when the WebSocket
15    /// is opened directly from a browser/device.
16    Jwt {
17        /// Token validity in seconds.
18        ttl_seconds: i64,
19    },
20}
21
22/// Entry point for the realtime API.
23///
24/// Construct with [`RealtimeClient::new`], optionally switch to JWT auth via
25/// [`RealtimeClient::with_jwt`], then start a session with
26/// [`RealtimeClient::session`].
27///
28/// ```rust,no_run
29/// use zai_rs::{model::GLM4_voice, realtime::RealtimeClient};
30///
31/// # async fn go(key: String) -> zai_rs::ZaiResult<()> {
32/// let session = RealtimeClient::new(key)
33///     .session(GLM4_voice {})
34///     .build()
35///     .await?;
36/// # Ok(())
37/// # }
38/// ```
39#[derive(Clone)]
40pub struct RealtimeClient {
41    api_key: Arc<String>,
42    auth: AuthMode,
43    endpoint_config: EndpointConfig,
44}
45
46impl RealtimeClient {
47    /// Create a realtime client using Bearer auth and the default endpoints.
48    pub fn new(api_key: impl Into<String>) -> Self {
49        Self {
50            api_key: Arc::new(api_key.into()),
51            auth: AuthMode::Bearer,
52            endpoint_config: EndpointConfig::default(),
53        }
54    }
55
56    /// Switch to client-side JWT auth, signing tokens valid for `ttl_seconds`.
57    pub fn with_jwt(mut self, ttl_seconds: i64) -> Self {
58        self.auth = AuthMode::Jwt { ttl_seconds };
59        self
60    }
61
62    /// Switch (back) to server-side Bearer auth.
63    pub fn with_bearer(mut self) -> Self {
64        self.auth = AuthMode::Bearer;
65        self
66    }
67
68    /// Override the full endpoint config (base URLs).
69    pub fn with_endpoint_config(mut self, config: EndpointConfig) -> Self {
70        self.endpoint_config = config;
71        self
72    }
73
74    /// Override only the realtime base URL (`wss://...`).
75    pub fn with_realtime_base(mut self, base: impl Into<String>) -> Self {
76        self.endpoint_config = self.endpoint_config.with_realtime_base(base);
77        self
78    }
79
80    /// Begin building a realtime session for `model`.
81    ///
82    /// The model bound is checked at compile time via [`super::RealtimeModel`].
83    pub fn session<M: super::RealtimeModel>(&self, model: M) -> SessionBuilder {
84        let realtime_url = self.realtime_url();
85        let model_name: String = model.into();
86        SessionBuilder::new(
87            Arc::clone(&self.api_key),
88            self.auth.clone(),
89            realtime_url,
90            model_name,
91        )
92    }
93
94    /// The resolved realtime WebSocket URL.
95    pub fn realtime_url(&self) -> String {
96        self.endpoint_config.url(&ApiBase::Realtime, "")
97    }
98
99    /// Current auth mode.
100    pub fn auth(&self) -> &AuthMode {
101        &self.auth
102    }
103
104    /// A reference to the configured API key.
105    pub fn api_key(&self) -> &str {
106        &self.api_key
107    }
108}