Skip to main content

wme_client/
client.rs

1use std::sync::Arc;
2
3use crate::{
4    auth::AuthConfig, BaseUrls, HttpTransport, MetadataClient, OnDemandClient, RealtimeClient,
5    ReqwestTransport, Result, RetryConfig, RetryTransport, SnapshotClient, TokenManager,
6};
7
8/// Client configuration.
9#[derive(Debug, Clone)]
10pub struct ClientConfig {
11    /// Base URLs for API endpoints
12    pub base_urls: BaseUrls,
13    /// Authentication configuration (optional for unauthenticated requests)
14    pub auth: Option<AuthConfig>,
15    /// Retry configuration
16    pub retry: RetryConfig,
17    /// Request timeout
18    pub timeout: std::time::Duration,
19    /// Whether to enable retry logic
20    pub enable_retry: bool,
21}
22
23impl Default for ClientConfig {
24    fn default() -> Self {
25        Self {
26            base_urls: BaseUrls::default(),
27            auth: None,
28            retry: RetryConfig::default(),
29            timeout: std::time::Duration::from_secs(60),
30            enable_retry: true,
31        }
32    }
33}
34
35/// Main Wikimedia Enterprise API client.
36pub struct WmeClient {
37    transport: Arc<dyn HttpTransport>,
38    token_manager: Option<TokenManager>,
39    base_urls: BaseUrls,
40}
41
42impl WmeClient {
43    /// Create a new client with the given configuration.
44    pub async fn new(config: ClientConfig) -> Result<Self> {
45        let base_transport = Arc::new(ReqwestTransport::new()?);
46
47        // Wrap with retry transport if enabled
48        let transport: Arc<dyn HttpTransport> = if config.enable_retry {
49            Arc::new(RetryTransport::new(base_transport, config.retry))
50        } else {
51            base_transport
52        };
53
54        let token_manager = config
55            .auth
56            .map(|auth| TokenManager::new(transport.clone(), auth));
57
58        Ok(Self {
59            transport,
60            token_manager,
61            base_urls: config.base_urls,
62        })
63    }
64
65    /// Create a client builder.
66    pub fn builder() -> WmeClientBuilder {
67        WmeClientBuilder::new()
68    }
69
70    /// Get the metadata client.
71    pub fn metadata(&self) -> MetadataClient<'_> {
72        MetadataClient::new(self)
73    }
74
75    /// Get the snapshot client.
76    pub fn snapshot(&self) -> SnapshotClient<'_> {
77        SnapshotClient::new(self)
78    }
79
80    /// Get the on-demand client.
81    pub fn on_demand(&self) -> OnDemandClient<'_> {
82        OnDemandClient::new(self)
83    }
84
85    /// Get the realtime client.
86    pub fn realtime(&self) -> RealtimeClient<'_> {
87        RealtimeClient::new(self)
88    }
89
90    /// Get the HTTP transport.
91    pub(crate) fn transport(&self) -> &Arc<dyn HttpTransport> {
92        &self.transport
93    }
94
95    /// Get the base URLs.
96    pub(crate) fn base_urls(&self) -> &BaseUrls {
97        &self.base_urls
98    }
99
100    /// Get authentication headers if available.
101    pub(crate) async fn auth_headers(
102        &self,
103    ) -> Result<Option<std::collections::HashMap<String, String>>> {
104        if let Some(token_manager) = &self.token_manager {
105            let token = token_manager.get_access_token().await?;
106            let mut headers = std::collections::HashMap::new();
107            headers.insert("Authorization".to_string(), format!("Bearer {}", token));
108            Ok(Some(headers))
109        } else {
110            Ok(None)
111        }
112    }
113
114    /// Get the token manager if available.
115    ///
116    /// Returns `Some(&TokenManager)` if the client was built with credentials,
117    /// or `None` if the client was built without authentication.
118    ///
119    /// This allows CLI applications to retrieve tokens after login for storage,
120    /// or to set tokens from a previous session.
121    pub fn token_manager(&self) -> Option<&TokenManager> {
122        self.token_manager.as_ref()
123    }
124}
125
126/// Builder for WmeClient.
127pub struct WmeClientBuilder {
128    config: ClientConfig,
129}
130
131impl WmeClientBuilder {
132    /// Create a new client builder.
133    pub fn new() -> Self {
134        Self {
135            config: ClientConfig::default(),
136        }
137    }
138
139    /// Set the base API URL.
140    pub fn api_url(mut self, url: impl Into<String>) -> Self {
141        self.config.base_urls.api = url.into();
142        self
143    }
144
145    /// Set the authentication URL.
146    pub fn auth_url(mut self, url: impl Into<String>) -> Self {
147        self.config.base_urls.auth = url.into();
148        self
149    }
150
151    /// Set the realtime API URL.
152    pub fn realtime_url(mut self, url: impl Into<String>) -> Self {
153        self.config.base_urls.realtime = url.into();
154        self
155    }
156
157    /// Set credentials for authentication.
158    pub fn credentials(mut self, username: impl Into<String>, password: impl Into<String>) -> Self {
159        self.config.auth = Some(AuthConfig {
160            username: username.into(),
161            password: password.into(),
162            auth_url: self.config.base_urls.auth.clone(),
163        });
164        self
165    }
166
167    /// Set retry configuration.
168    pub fn retry(mut self, retry: RetryConfig) -> Self {
169        self.config.retry = retry;
170        self
171    }
172
173    /// Disable retry logic.
174    pub fn disable_retry(mut self) -> Self {
175        self.config.enable_retry = false;
176        self
177    }
178
179    /// Set request timeout.
180    pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
181        self.config.timeout = timeout;
182        self
183    }
184
185    /// Build the client.
186    pub async fn build(self) -> Result<WmeClient> {
187        WmeClient::new(self.config).await
188    }
189}
190
191impl Default for WmeClientBuilder {
192    fn default() -> Self {
193        Self::new()
194    }
195}