1use crate::policies::{ExponentialRetryPolicy, FixedRetryPolicy, NoRetryPolicy, Policy};
2use crate::{http_client, TimeoutPolicy};
3use crate::{HttpClient, RetryPolicy};
4use std::fmt::Debug;
5use std::sync::Arc;
6use std::time::Duration;
7
8#[derive(Clone, Debug, Default)]
21pub struct ClientOptions {
22 pub(crate) per_call_policies: Vec<Arc<dyn Policy>>,
24 pub(crate) per_retry_policies: Vec<Arc<dyn Policy>>,
26 pub(crate) retry: RetryOptions,
28 pub(crate) telemetry: TelemetryOptions,
30 pub(crate) transport: TransportOptions,
32 pub timeout: TimeoutPolicy,
34}
35
36impl ClientOptions {
37 pub fn new(transport: TransportOptions) -> Self {
38 Self {
39 per_call_policies: Vec::new(),
40 per_retry_policies: Vec::new(),
41 retry: RetryOptions::default(),
42 telemetry: TelemetryOptions::default(),
43 transport,
44 timeout: TimeoutPolicy::default(),
45 }
46 }
47
48 pub fn per_call_policies_mut(&mut self) -> &mut Vec<Arc<dyn Policy>> {
50 &mut self.per_call_policies
51 }
52
53 pub fn per_retry_policies_mut(&mut self) -> &mut Vec<Arc<dyn Policy>> {
55 &mut self.per_retry_policies
56 }
57
58 setters! {
59 per_call_policies: Vec<Arc<dyn Policy>> => per_call_policies,
60 per_retry_policies: Vec<Arc<dyn Policy>> => per_retry_policies,
61 retry: RetryOptions => retry,
62 telemetry: TelemetryOptions => telemetry,
63 transport: TransportOptions => transport,
64 timeout: TimeoutPolicy => timeout,
65 }
66}
67
68#[derive(Clone)]
70enum RetryMode {
71 Exponential(ExponentialRetryOptions),
76
77 Fixed(FixedRetryOptions),
79
80 Custom(Arc<dyn Policy>),
82
83 None,
85}
86
87impl Debug for RetryMode {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 match self {
90 RetryMode::Exponential(o) => write!(f, "Exponetial({o:?})"),
91 RetryMode::Fixed(o) => write!(f, "Fixed({o:?})"),
92 RetryMode::Custom(_) => write!(f, "Custom"),
93 RetryMode::None => write!(f, "None"),
94 }
95 }
96}
97
98impl Default for RetryMode {
99 fn default() -> Self {
100 RetryMode::Exponential(ExponentialRetryOptions::default())
101 }
102}
103
104#[derive(Clone, Debug, Default)]
111pub struct RetryOptions {
112 mode: RetryMode,
114}
115
116impl RetryOptions {
117 pub fn exponential(options: ExponentialRetryOptions) -> Self {
119 Self {
120 mode: RetryMode::Exponential(options),
121 }
122 }
123
124 pub fn fixed(options: FixedRetryOptions) -> Self {
126 Self {
127 mode: RetryMode::Fixed(options),
128 }
129 }
130
131 pub fn custom<T: RetryPolicy + 'static>(policy: Arc<T>) -> Self {
133 Self {
134 mode: RetryMode::Custom(policy),
135 }
136 }
137
138 pub fn none() -> Self {
140 Self {
141 mode: RetryMode::None,
142 }
143 }
144
145 pub(crate) fn to_policy(&self) -> Arc<dyn Policy> {
146 match &self.mode {
147 RetryMode::Exponential(options) => Arc::new(ExponentialRetryPolicy::new(
148 options.initial_delay,
149 options.max_retries,
150 options.max_total_elapsed,
151 options.max_delay,
152 )),
153 RetryMode::Fixed(options) => Arc::new(FixedRetryPolicy::new(
154 options.delay,
155 options.max_retries,
156 options.max_total_elapsed,
157 )),
158 RetryMode::Custom(c) => c.clone(),
159 RetryMode::None => Arc::new(NoRetryPolicy::default()),
160 }
161 }
162}
163
164#[derive(Clone, Debug)]
178pub struct ExponentialRetryOptions {
179 pub initial_delay: Duration,
183
184 pub max_retries: u32,
188
189 pub max_total_elapsed: Duration,
193
194 pub max_delay: Duration,
198}
199
200impl ExponentialRetryOptions {
201 setters! {
202 initial_delay: Duration => initial_delay,
203 max_retries: u32 => max_retries,
204 max_total_elapsed: Duration => max_total_elapsed,
205 max_delay: Duration => max_delay,
206 }
207}
208
209impl Default for ExponentialRetryOptions {
210 fn default() -> Self {
211 Self {
212 initial_delay: Duration::from_millis(200),
213 max_retries: 8,
214 max_total_elapsed: Duration::from_secs(60),
215 max_delay: Duration::from_secs(30),
216 }
217 }
218}
219
220#[derive(Clone, Debug)]
233pub struct FixedRetryOptions {
234 pub delay: Duration,
238
239 pub max_retries: u32,
243
244 pub max_total_elapsed: Duration,
248}
249
250impl FixedRetryOptions {
251 setters! {
252 #[doc = "Set the delay between retry attempts."]
253 delay: Duration => delay,
254 #[doc = "Set the maximum number of retry attempts before giving up."]
255 max_retries: u32 => max_retries,
256 #[doc = "Set the maximum permissible elapsed time since starting to retry."]
257 max_total_elapsed: Duration => max_total_elapsed,
258 }
259}
260
261impl Default for FixedRetryOptions {
262 fn default() -> Self {
263 Self {
264 delay: Duration::from_millis(200),
265 max_retries: 8,
266 max_total_elapsed: Duration::from_secs(60),
267 }
268 }
269}
270
271#[derive(Clone, Debug, Default)]
273pub struct TelemetryOptions {
274 pub(crate) application_id: Option<String>,
276}
277
278impl TelemetryOptions {
279 setters! {
280 #[doc = "Set the application ID to telemetry."]
281 application_id: String => Some(application_id),
282 }
283}
284
285#[derive(Clone, Debug)]
287pub struct TransportOptions {
288 inner: TransportOptionsImpl,
289}
290
291#[derive(Clone, Debug)]
292enum TransportOptionsImpl {
293 Http {
294 http_client: Arc<dyn HttpClient>,
296 },
297 Custom(Arc<dyn Policy>),
298}
299
300impl TransportOptions {
301 pub fn new(http_client: Arc<dyn HttpClient>) -> Self {
303 let inner = TransportOptionsImpl::Http { http_client };
304 Self { inner }
305 }
306
307 pub fn new_custom_policy(policy: Arc<dyn Policy>) -> Self {
311 let inner = TransportOptionsImpl::Custom(policy);
312 Self { inner }
313 }
314
315 pub async fn send(
317 &self,
318 ctx: &crate::Context,
319 request: &mut crate::Request,
320 ) -> crate::Result<crate::Response> {
321 use TransportOptionsImpl as I;
322 match &self.inner {
323 I::Http { http_client } => http_client.execute_request(request).await,
324 I::Custom(s) => s.send(ctx, request, &[]).await,
325 }
326 }
327}
328
329impl Default for TransportOptions {
330 fn default() -> Self {
332 Self::new(http_client::new_http_client())
333 }
334}