tuwunel_service/storage/provider/
s3.rs1use std::{sync::Arc, time::Duration};
2
3pub use object_store::{GetResult, GetResultPayload, PutPayload, PutResult};
4use object_store::{aws::AmazonS3Builder, client::ClientOptions};
5use tuwunel_core::{
6 Result,
7 config::{StorageProvider, StorageProviderS3},
8 debug, debug_info, error, trace,
9 version::user_agent,
10};
11
12use super::Provider;
13
14#[tracing::instrument(name = "new", level = "info", skip_all, err)]
15pub(in super::super) fn new(
16 args: &crate::Args<'_>,
17 name: &str,
18 config: &StorageProviderS3,
19) -> Result<Option<(String, Arc<Provider>)>> {
20 if config.url.is_none() && config.bucket.is_none() {
22 debug!(?name, "s3_provider.bucket not set. This configuration will be skipped");
23 return Ok(None);
24 }
25
26 let mut builder = AmazonS3Builder::from_env().with_client_options(
27 ClientOptions::new()
28 .with_user_agent(user_agent().try_into()?)
29 .with_pool_max_idle_per_host(args.server.config.request_idle_per_host.into())
30 .with_pool_idle_timeout(Duration::from_secs(args.server.config.request_idle_timeout)),
31 );
32
33 if let Some(url) = config.url.clone() {
34 builder = builder.with_url(url);
35 }
36
37 if let Some(region) = config.region.clone() {
38 builder = builder.with_region(region);
39 }
40
41 if let Some(bucket) = config.bucket.clone() {
42 builder = builder.with_bucket_name(bucket);
43 }
44
45 if let Some(key) = config.key.clone() {
46 builder = builder.with_access_key_id(key);
47 }
48
49 if let Some(secret) = config.secret.clone() {
50 builder = builder.with_secret_access_key(secret);
51 }
52
53 if let Some(kms) = config.kms.clone() {
54 builder = builder.with_ssec_encryption(kms);
55 }
56
57 if let Some(token) = config.token.clone() {
58 builder = builder.with_token(token);
59 }
60
61 if let Some(endpoint) = config.endpoint.clone() {
62 builder = builder.with_endpoint(endpoint);
63 }
64
65 if let Some(use_bucket_key) = config.use_bucket_key {
66 builder = builder.with_bucket_key(use_bucket_key);
67 }
68
69 if let Some(use_https) = config.use_https {
70 builder = builder.with_allow_http(!use_https);
71 }
72
73 if let Some(use_signatures) = config.use_signatures {
74 builder = builder.with_skip_signature(!use_signatures);
75 }
76
77 if let Some(use_payload_signatures) = config.use_payload_signatures {
78 builder = builder.with_unsigned_payload(!use_payload_signatures);
79 }
80
81 if let Some(use_vhost_request) = config.use_vhost_request {
82 builder = builder.with_virtual_hosted_style_request(use_vhost_request);
83 }
84
85 trace!(?name, ?config, "Initializing S3...");
86
87 let provider = builder
88 .build()
89 .map(Box::from)
90 .inspect_err(|e| error!("Failed to configure S3 storage client: {e}"))?;
91
92 debug_info!(
93 credentials = ?provider.credentials(),
94 "Started S3 storage client."
95 );
96
97 let provider = Provider {
98 name: name.to_owned(),
99 base_path: config.base_path.clone().map(Into::into),
100 config: StorageProvider::s3(Box::new(config.clone())),
101 startup_check: config.startup_check,
102 services: args.services.clone(),
103 provider,
104 };
105
106 Ok(Some((name.to_owned(), Arc::new(provider))))
107}