spiffe_rs/workloadapi/
option.rs

1use crate::logger;
2use crate::workloadapi::{backoff, client::Client, LoggerRef};
3use std::sync::Arc;
4
5/// An option for configuring a Workload API client.
6pub trait ClientOption: Send + Sync {
7    fn configure_client(&self, config: &mut ClientConfig);
8}
9
10/// An option for configuring a source (X.509, JWT, or bundle).
11pub trait SourceOption: Send + Sync {
12    fn configure_x509_source(&self, config: &mut X509SourceConfig);
13    fn configure_jwt_source(&self, config: &mut JWTSourceConfig);
14    fn configure_bundle_source(&self, config: &mut BundleSourceConfig);
15}
16
17/// An option for configuring an X.509 source.
18pub trait X509SourceOption: Send + Sync {
19    fn configure_x509_source(&self, config: &mut X509SourceConfig);
20}
21
22/// An option for configuring a JWT source.
23pub trait JWTSourceOption: Send + Sync {
24    fn configure_jwt_source(&self, config: &mut JWTSourceConfig);
25}
26
27/// An option for configuring a bundle source.
28pub trait BundleSourceOption: Send + Sync {
29    fn configure_bundle_source(&self, config: &mut BundleSourceConfig);
30}
31
32/// An option for configuring the gRPC channel.
33pub trait DialOption: Send + Sync {
34    fn apply(&self, endpoint: tonic::transport::Endpoint) -> tonic::transport::Endpoint;
35}
36
37/// Sets the address of the Workload API endpoint.
38pub fn with_addr(addr: impl Into<String>) -> Arc<dyn ClientOption> {
39    Arc::new(WithAddr {
40        addr: addr.into(),
41    })
42}
43
44/// Sets the gRPC dial options.
45pub fn with_dial_options(options: Vec<Arc<dyn DialOption>>) -> Arc<dyn ClientOption> {
46    Arc::new(WithDialOptions { options })
47}
48
49/// Sets the logger for the client.
50pub fn with_logger(log: LoggerRef) -> Arc<dyn ClientOption> {
51    Arc::new(WithLogger { log })
52}
53
54/// Sets the backoff strategy for retrying failed connections.
55pub fn with_backoff_strategy(strategy: Arc<dyn backoff::BackoffStrategy>) -> Arc<dyn ClientOption> {
56    Arc::new(WithBackoffStrategy { strategy })
57}
58
59/// Sets an existing Workload API client to be used by the source.
60pub fn with_client(client: Arc<Client>) -> Arc<dyn SourceOption> {
61    Arc::new(WithClient { client })
62}
63
64/// Sets the options for the Workload API client created by the source.
65pub fn with_client_options(options: Vec<Arc<dyn ClientOption>>) -> Arc<dyn SourceOption> {
66    Arc::new(WithClientOptions { options })
67}
68
69/// Sets a custom picker for X.509 SVIDs.
70pub fn with_default_x509_svid_picker(
71    picker: Arc<dyn Fn(&[crate::svid::x509svid::SVID]) -> crate::svid::x509svid::SVID + Send + Sync>,
72) -> Arc<dyn X509SourceOption> {
73    Arc::new(WithDefaultX509SVIDPicker { picker })
74}
75
76/// Sets a custom picker for JWT SVIDs.
77pub fn with_default_jwt_svid_picker(
78    picker: Arc<dyn Fn(&[crate::svid::jwtsvid::SVID]) -> crate::svid::jwtsvid::SVID + Send + Sync>,
79) -> Arc<dyn JWTSourceOption> {
80    Arc::new(WithDefaultJWTSVIDPicker { picker })
81}
82
83#[derive(Clone)]
84pub struct ClientConfig {
85    pub address: Option<String>,
86    pub dial_options: Vec<Arc<dyn DialOption>>,
87    pub log: LoggerRef,
88    pub backoff_strategy: Arc<dyn backoff::BackoffStrategy>,
89}
90
91impl Default for ClientConfig {
92    fn default() -> Self {
93        Self {
94            address: None,
95            dial_options: Vec::new(),
96            log: Arc::new(logger::null_logger()),
97            backoff_strategy: Arc::new(backoff::LinearBackoffStrategy::default()),
98        }
99    }
100}
101
102pub struct WatcherConfig {
103    pub client: Option<Arc<Client>>,
104    pub client_options: Vec<Arc<dyn ClientOption>>,
105}
106
107impl Default for WatcherConfig {
108    fn default() -> Self {
109        Self {
110            client: None,
111            client_options: Vec::new(),
112        }
113    }
114}
115
116pub struct X509SourceConfig {
117    pub watcher: WatcherConfig,
118    pub picker: Option<
119        Arc<dyn Fn(&[crate::svid::x509svid::SVID]) -> crate::svid::x509svid::SVID + Send + Sync>,
120    >,
121}
122
123impl Default for X509SourceConfig {
124    fn default() -> Self {
125        Self {
126            watcher: WatcherConfig::default(),
127            picker: None,
128        }
129    }
130}
131
132pub struct JWTSourceConfig {
133    pub watcher: WatcherConfig,
134    pub picker:
135        Option<Arc<dyn Fn(&[crate::svid::jwtsvid::SVID]) -> crate::svid::jwtsvid::SVID + Send + Sync>>,
136}
137
138impl Default for JWTSourceConfig {
139    fn default() -> Self {
140        Self {
141            watcher: WatcherConfig::default(),
142            picker: None,
143        }
144    }
145}
146
147pub struct BundleSourceConfig {
148    pub watcher: WatcherConfig,
149}
150
151impl Default for BundleSourceConfig {
152    fn default() -> Self {
153        Self {
154            watcher: WatcherConfig::default(),
155        }
156    }
157}
158
159struct WithAddr {
160    addr: String,
161}
162
163impl ClientOption for WithAddr {
164    fn configure_client(&self, config: &mut ClientConfig) {
165        config.address = Some(self.addr.clone());
166    }
167}
168
169struct WithDialOptions {
170    options: Vec<Arc<dyn DialOption>>,
171}
172
173impl ClientOption for WithDialOptions {
174    fn configure_client(&self, config: &mut ClientConfig) {
175        config.dial_options.extend(self.options.iter().cloned());
176    }
177}
178
179struct WithLogger {
180    log: LoggerRef,
181}
182
183impl ClientOption for WithLogger {
184    fn configure_client(&self, config: &mut ClientConfig) {
185        config.log = self.log.clone();
186    }
187}
188
189struct WithBackoffStrategy {
190    strategy: Arc<dyn backoff::BackoffStrategy>,
191}
192
193impl ClientOption for WithBackoffStrategy {
194    fn configure_client(&self, config: &mut ClientConfig) {
195        config.backoff_strategy = self.strategy.clone();
196    }
197}
198
199struct WithClient {
200    client: Arc<Client>,
201}
202
203impl SourceOption for WithClient {
204    fn configure_x509_source(&self, config: &mut X509SourceConfig) {
205        config.watcher.client = Some(self.client.clone());
206    }
207
208    fn configure_jwt_source(&self, config: &mut JWTSourceConfig) {
209        config.watcher.client = Some(self.client.clone());
210    }
211
212    fn configure_bundle_source(&self, config: &mut BundleSourceConfig) {
213        config.watcher.client = Some(self.client.clone());
214    }
215}
216
217struct WithClientOptions {
218    options: Vec<Arc<dyn ClientOption>>,
219}
220
221impl SourceOption for WithClientOptions {
222    fn configure_x509_source(&self, config: &mut X509SourceConfig) {
223        config.watcher.client_options = self.options.clone();
224    }
225
226    fn configure_jwt_source(&self, config: &mut JWTSourceConfig) {
227        config.watcher.client_options = self.options.clone();
228    }
229
230    fn configure_bundle_source(&self, config: &mut BundleSourceConfig) {
231        config.watcher.client_options = self.options.clone();
232    }
233}
234
235struct WithDefaultX509SVIDPicker {
236    picker: Arc<dyn Fn(&[crate::svid::x509svid::SVID]) -> crate::svid::x509svid::SVID + Send + Sync>,
237}
238
239impl X509SourceOption for WithDefaultX509SVIDPicker {
240    fn configure_x509_source(&self, config: &mut X509SourceConfig) {
241        config.picker = Some(self.picker.clone());
242    }
243}
244
245impl SourceOption for WithDefaultX509SVIDPicker {
246    fn configure_x509_source(&self, config: &mut X509SourceConfig) {
247        X509SourceOption::configure_x509_source(self, config);
248    }
249
250    fn configure_jwt_source(&self, _config: &mut JWTSourceConfig) {}
251
252    fn configure_bundle_source(&self, _config: &mut BundleSourceConfig) {}
253}
254
255struct WithDefaultJWTSVIDPicker {
256    picker: Arc<dyn Fn(&[crate::svid::jwtsvid::SVID]) -> crate::svid::jwtsvid::SVID + Send + Sync>,
257}
258
259impl JWTSourceOption for WithDefaultJWTSVIDPicker {
260    fn configure_jwt_source(&self, config: &mut JWTSourceConfig) {
261        config.picker = Some(self.picker.clone());
262    }
263}
264
265impl SourceOption for WithDefaultJWTSVIDPicker {
266    fn configure_x509_source(&self, _config: &mut X509SourceConfig) {}
267
268    fn configure_jwt_source(&self, config: &mut JWTSourceConfig) {
269        JWTSourceOption::configure_jwt_source(self, config);
270    }
271
272    fn configure_bundle_source(&self, _config: &mut BundleSourceConfig) {}
273}