Skip to main content

proton_sdk/
config.rs

1//! Client configuration and defaults.
2
3use std::time::Duration;
4
5/// Default base URL for the Proton Drive API.
6pub const DEFAULT_BASE_URL: &str = "https://drive-api.proton.me/";
7
8/// Default redirect URI sent with token refresh requests.
9pub const DEFAULT_REFRESH_REDIRECT_URI: &str = "https://proton.me";
10
11/// Default per-request timeout, matching `ProtonApiDefaults.DefaultTimeoutSeconds`.
12pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
13
14/// Default number of automatic retries on a retryable failure (rate-limit,
15/// transient transport error). The original attempt is not counted, so the
16/// total request budget is `1 + max_retries`.
17pub const DEFAULT_MAX_RETRIES: u32 = 3;
18
19/// Default base delay for exponential backoff between retries.
20pub const DEFAULT_RETRY_BASE_DELAY: Duration = Duration::from_millis(500);
21
22/// Default upper bound for a single backoff sleep. A server-supplied
23/// `Retry-After` is honoured even if it exceeds this.
24pub const DEFAULT_RETRY_MAX_DELAY: Duration = Duration::from_secs(30);
25
26/// Controls automatic retries on retryable responses (HTTP 408/429/502/503/504)
27/// and transient transport errors (timeout, connect).
28///
29/// Mirrors the Polly-style retry pipeline in the C# SDK: a server-supplied
30/// `Retry-After` header wins; otherwise the delay is exponential backoff
31/// (`base_delay * 2^attempt`, capped at `max_delay`) with full jitter.
32#[derive(Debug, Clone)]
33pub struct RetryPolicy {
34    /// Maximum number of retries after the initial attempt. `0` disables retry.
35    pub max_retries: u32,
36    /// Base delay for exponential backoff.
37    pub base_delay: Duration,
38    /// Cap on a single computed backoff sleep.
39    pub max_delay: Duration,
40}
41
42impl Default for RetryPolicy {
43    fn default() -> Self {
44        Self {
45            max_retries: DEFAULT_MAX_RETRIES,
46            base_delay: DEFAULT_RETRY_BASE_DELAY,
47            max_delay: DEFAULT_RETRY_MAX_DELAY,
48        }
49    }
50}
51
52impl RetryPolicy {
53    /// A policy that performs no automatic retries.
54    pub fn disabled() -> Self {
55        Self {
56            max_retries: 0,
57            ..Self::default()
58        }
59    }
60}
61
62/// Content type used for the `Accept` header on API requests.
63pub const API_CONTENT_TYPE: &str = "application/vnd.protonmail.api+json";
64
65/// Configuration for a Proton client session.
66///
67/// `app_version` is mandatory and must honour the operational requirements in
68/// the SDK README (`external-drive-{name}@{semver}-{channel}`), sent as the
69/// `x-pm-appversion` header.
70#[derive(Debug, Clone)]
71pub struct ProtonClientConfiguration {
72    pub base_url: String,
73    pub app_version: String,
74    pub user_agent: String,
75    pub refresh_redirect_uri: String,
76    pub request_timeout: Duration,
77    pub retry_policy: RetryPolicy,
78}
79
80impl ProtonClientConfiguration {
81    /// Create a configuration with the given app version and otherwise defaults.
82    pub fn new(app_version: impl Into<String>) -> Self {
83        Self {
84            base_url: DEFAULT_BASE_URL.to_owned(),
85            app_version: app_version.into(),
86            user_agent: String::new(),
87            refresh_redirect_uri: DEFAULT_REFRESH_REDIRECT_URI.to_owned(),
88            request_timeout: DEFAULT_TIMEOUT,
89            retry_policy: RetryPolicy::default(),
90        }
91    }
92
93    pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
94        self.base_url = base_url.into();
95        self
96    }
97
98    pub fn with_user_agent(mut self, user_agent: impl Into<String>) -> Self {
99        self.user_agent = user_agent.into();
100        self
101    }
102
103    pub fn with_request_timeout(mut self, timeout: Duration) -> Self {
104        self.request_timeout = timeout;
105        self
106    }
107
108    pub fn with_retry_policy(mut self, retry_policy: RetryPolicy) -> Self {
109        self.retry_policy = retry_policy;
110        self
111    }
112}