use crate::sync::{build_s3_client, SyncConfig};
use anyhow::{anyhow, Context, Result};
use aws_sdk_s3::presigning::PresigningConfig;
use aws_sdk_s3::primitives::ByteStream;
use std::time::Duration;
pub struct UploadResult {
pub bucket: String,
pub key: String,
pub presigned_url: String,
pub expires_in: Duration,
}
pub async fn upload_with_presigned_url(
cfg: &SyncConfig,
key: &str,
body: Vec<u8>,
content_type: &str,
expires_in: Duration,
) -> Result<UploadResult> {
if cfg.bucket.is_empty() {
return Err(anyhow!(
"no bucket configured. Set [cloud] bucket in ~/.i-self/config.toml \
or ISELF_SYNC_BUCKET env var."
));
}
if expires_in.as_secs() == 0 || expires_in.as_secs() > 7 * 24 * 60 * 60 {
return Err(anyhow!(
"expires_in must be between 1 second and 7 days (got {} seconds)",
expires_in.as_secs()
));
}
let client = build_s3_client(cfg).await?;
client
.put_object()
.bucket(&cfg.bucket)
.key(key)
.content_type(content_type)
.body(ByteStream::from(body))
.send()
.await
.with_context(|| format!("PutObject {}/{}", cfg.bucket, key))?;
let presigning_config = PresigningConfig::builder()
.expires_in(expires_in)
.build()
.context("PresigningConfig::build")?;
let presigned = client
.get_object()
.bucket(&cfg.bucket)
.key(key)
.presigned(presigning_config)
.await
.with_context(|| format!("presign GetObject {}/{}", cfg.bucket, key))?;
Ok(UploadResult {
bucket: cfg.bucket.clone(),
key: key.to_string(),
presigned_url: presigned.uri().to_string(),
expires_in,
})
}