LoginSignup
1
0

More than 1 year has passed since last update.

[業務deRust]CSVを作ってS3からダウンロードするURLを作る

Posted at

目的

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ファイルにするライブラリを書きました。」を参考にしてください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0