Skip to main content

tuwunel_service/storage/provider/
s3.rs

1use 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	// Fail successfully if this provider is disabled by the configuration..
21	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}