目的
CSVを作って帳票をダウンロードさせたい要件がありました。以下を実現します。
- CSVを作成してZIPファイルとして圧縮する
- S3にアップロードする(非公開)
- 一定期間有効なURLを発行する
コード
Cargo.toml
[package]
name = "upload_s3"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.69"
aws-config = "0.54.1"
aws-sdk-s3 = "0.24.0"
csv-zip-maker = "0.2.1"
tokio = { version = "1", features = ["full"] }
uuid = { version = "1.3", features = ["v4"] }
main.rs
use std::{path::PathBuf, time::Duration};
use aws_sdk_s3 as s3;
use s3::{presigning::config::PresigningConfig, types::ByteStream, input::GetObjectInput};
use uuid::Uuid;
const BUCKET_NAME: &str = "my-bucket";
use csv_zip_maker::{CsvZipMaker};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// CSVの作成
let mut maker = make_csv()?;
let path_buf = maker.make_zip_file()?;
// S3へアップロード
let config = aws_config::load_from_env().await;
let client = s3::Client::new(&config);
let key = format!("{}", Uuid::new_v4());
put_object(
&client,
&key,
"application/zip",
"Content-Disposition: attachment; filename=\"test.zip\"",
path_buf
)
.await?;
// URLの取得
let res = get_presigned(&client, &key, 60).await?;
println!("{}", res);
Ok(())
}
pub fn make_csv() -> anyhow::Result<CsvZipMaker> {
let mut maker = CsvZipMaker::new("test", "summary")?;
let mut csv_maker = maker.make_csv_maker_for_excel("summary1")?;
csv_maker.write(&vec!["aaa", "bbb"])?;
csv_maker.write(&vec!["ccc", "ddd"])?;
maker.add_csv(&mut csv_maker)?;
let mut csv_maker = maker.make_csv_maker("summary2")?;
csv_maker.write(&vec!["111", "222"])?;
csv_maker.write(&vec!["333", "444"])?;
maker.add_csv(&mut csv_maker)?;
Ok(maker)
}
pub async fn put_object(
client: &s3::Client,
key: &str,
content_type: &str,
content_disposition: &str,
path: &PathBuf,
) -> anyhow::Result<()> {
let body = ByteStream::from_path(path).await?;
let _ = client
.put_object()
.set_bucket(Some(BUCKET_NAME.to_owned()))
.set_key(Some(key.to_owned()))
.set_content_type(Some(content_type.to_owned()))
.set_content_disposition(Some(content_disposition.to_owned()))
.set_body(Some(body))
.send()
.await?;
Ok(())
}
pub async fn get_presigned(client: &s3::Client, key: &str, second_count: u64) -> anyhow::Result<String> {
let poi = GetObjectInput::builder()
.set_key(Some(key.to_owned()))
.set_bucket(Some(BUCKET_NAME.to_owned()))
.build()?;
let mut pc = PresigningConfig::builder();
pc.set_expires_in(Some(Duration::from_secs(second_count)));
let res = poi
.presigned(client.conf(), pc.build()?)
.await?;
Ok(res.uri().to_string())
}
まとめ
実際の業務ではWebフレームワークのaxumと組み合わせてユーザーがブラウザーからダウンロードできるようになっています。
S3にアップロードしたファイルはS3のライフサイクルマネジメントを使い一定期間後削除するようにしています。
CSVの生成は以前自分が書いた記事「RustでCSVを作成してZIPファイルにするライブラリを書きました。」を参考にしてください。