ironflow_sdk/builder.rs
1//! Builder pattern for [`IronflowClient`] with retry and rate-limit configuration.
2
3use std::time::Duration;
4
5use bytes::Bytes;
6
7use crate::client::{ClientConfig, IronflowClient};
8use crate::rate_limit::RateLimiter;
9use crate::retry::RetryConfig;
10
11/// Result of downloading an artifact.
12///
13/// # Examples
14///
15/// ```
16/// use ironflow_sdk::client::ArtifactDownload;
17/// use bytes::Bytes;
18///
19/// let download = ArtifactDownload {
20/// bytes: Bytes::from_static(b"hello"),
21/// content_type: "text/plain".to_string(),
22/// sha256: "abc123".to_string(),
23/// };
24/// assert_eq!(download.bytes.len(), 5);
25/// ```
26#[derive(Debug, Clone)]
27pub struct ArtifactDownload {
28 /// Raw artifact bytes.
29 pub bytes: Bytes,
30 /// MIME type recorded at upload time.
31 pub content_type: String,
32 /// SHA-256 digest of the artifact content (hex-encoded).
33 pub sha256: String,
34}
35
36/// Builder for [`IronflowClient`] with retry and rate-limit configuration.
37///
38/// # Examples
39///
40/// ```
41/// use ironflow_sdk::ClientBuilder;
42///
43/// let client = ClientBuilder::new("https://ironflow.example.com", "my-api-key")
44/// .with_max_retries(5)
45/// .with_rate_limit(false)
46/// .build();
47/// ```
48pub struct ClientBuilder {
49 config: ClientConfig,
50 retry: RetryConfig,
51 rate_limit_enabled: bool,
52}
53
54impl ClientBuilder {
55 /// Create a builder with defaults (3 retries, rate-limit enabled).
56 ///
57 /// # Examples
58 ///
59 /// ```
60 /// use ironflow_sdk::ClientBuilder;
61 ///
62 /// let builder = ClientBuilder::new("https://ironflow.example.com", "key");
63 /// ```
64 pub fn new(base_url: &str, api_key: &str) -> Self {
65 Self {
66 config: ClientConfig {
67 base_url: base_url.trim_end_matches('/').to_string(),
68 api_key: api_key.to_string(),
69 timeout: Duration::from_secs(30),
70 },
71 retry: RetryConfig::default(),
72 rate_limit_enabled: true,
73 }
74 }
75
76 /// Set the maximum number of retry attempts.
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use ironflow_sdk::ClientBuilder;
82 ///
83 /// let client = ClientBuilder::new("https://ironflow.example.com", "key")
84 /// .with_max_retries(5)
85 /// .build();
86 /// ```
87 pub fn with_max_retries(mut self, n: u32) -> Self {
88 self.retry.max_retries = n;
89 self
90 }
91
92 /// Set the HTTP request timeout.
93 ///
94 /// # Examples
95 ///
96 /// ```
97 /// use ironflow_sdk::ClientBuilder;
98 /// use std::time::Duration;
99 ///
100 /// let client = ClientBuilder::new("https://ironflow.example.com", "key")
101 /// .with_timeout(Duration::from_secs(60))
102 /// .build();
103 /// ```
104 pub fn with_timeout(mut self, timeout: Duration) -> Self {
105 self.config.timeout = timeout;
106 self
107 }
108
109 /// Enable or disable client-side rate limiting.
110 ///
111 /// When enabled (the default), the client waits for the `Retry-After`
112 /// window to expire before sending the next request after a 429.
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// use ironflow_sdk::ClientBuilder;
118 ///
119 /// let client = ClientBuilder::new("https://ironflow.example.com", "key")
120 /// .with_rate_limit(false)
121 /// .build();
122 /// ```
123 pub fn with_rate_limit(mut self, enabled: bool) -> Self {
124 self.rate_limit_enabled = enabled;
125 self
126 }
127
128 /// Build the [`IronflowClient`].
129 ///
130 /// # Panics
131 ///
132 /// Panics if the API key contains characters invalid for HTTP headers.
133 ///
134 /// # Examples
135 ///
136 /// ```
137 /// use ironflow_sdk::ClientBuilder;
138 ///
139 /// let client = ClientBuilder::new("https://ironflow.example.com", "key").build();
140 /// ```
141 pub fn build(self) -> IronflowClient {
142 let rate_limiter = if self.rate_limit_enabled {
143 RateLimiter::new()
144 } else {
145 RateLimiter::disabled()
146 };
147 IronflowClient::from_config_with_retry(self.config, self.retry, rate_limiter)
148 }
149}