b453d5d
use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct S3Config {
pub bucket: Option<String>,
pub region: Option<String>,
pub endpoint: Option<String>,
/// Endpoint used when signing URLs handed to clients (browser downloads,
/// avatar links, LFS transfers). Presigned URLs embed the endpoint host in
/// their signature, so signing with an in-cluster address produces links
/// no client can resolve. Defaults to `endpoint` when unset.
pub public_endpoint: Option<String>,
pub access_key_id: Option<String>,
pub secret_access_key: Option<String>,
pub path_style: Option<bool>,
pub request_timeout_secs: Option<u64>,
}
impl S3Config {
pub fn new(
bucket: impl Into<String>,
region: impl Into<String>,
endpoint: Option<String>,
) -> Self {
Self {
bucket: Some(bucket.into()),
region: Some(region.into()),
endpoint,
..Self::default()
}
}
pub fn bucket_name(&self) -> &str {
self.bucket.as_deref().unwrap_or("")
}
pub fn region(&self) -> &str {
self.region.as_deref().unwrap_or("us-east-1")
}
/// Endpoint presigned URLs must be addressed to, falling back to the
/// internal endpoint when no public one is configured.
pub fn presign_endpoint(&self) -> Option<&str> {
self.public_endpoint
.as_deref()
.filter(|s| !s.is_empty())
.or_else(|| self.endpoint.as_deref().filter(|s| !s.is_empty()))
}
pub fn use_path_style(&self) -> bool {
self.path_style.unwrap_or(false)
}
pub fn request_timeout(&self) -> Option<Duration> {
self.request_timeout_secs.map(Duration::from_secs)
}
pub fn validate(&self) -> Result<(&str, &str), String> {
let bucket = self
.bucket
.as_deref()
.filter(|s| !s.is_empty())
.ok_or_else(|| "s3.bucket must be set".to_string())?;
let region = self
.region
.as_deref()
.filter(|s| !s.is_empty())
.ok_or_else(|| "s3.region must be set".to_string())?;
Ok((bucket, region))
}
}