将 Cloud Storage 与 Rust 搭配使用

Cloud Storage 是一种用于存储非结构化数据的托管式服务。Cloud Client Libraries for Rust 中的 google-cloud-storage crate 提供了一个惯用的 Rust API,可恢复中断的上传和下载、验证数据完整性、重试暂时性元数据错误,以及轮询长时间运行的操作。

本文档介绍了如何创建 Cloud Storage 存储桶、向该存储桶写入对象、读回对象内容以及删除这两个资源。

准备工作

在运行本文档中的代码之前,请先完成以下前提条件:

依赖项

将 Cloud Storage 客户端库和支持 crate 添加到 Cargo.toml 文件中:

cargo add google-cloud-storage anyhow bytes
cargo add tokio --features macros,rt-multi-thread

创建存储桶

对存储桶和对象元数据的操作使用 StorageControl 客户端:

  1. 初始化 StorageControl 客户端:

    use google_cloud_storage as gcs;
    use google_cloud_storage::client::StorageControl;
    let control = StorageControl::builder().build().await?;

  2. 使用您的项目 ID 和全局唯一的存储桶 ID 配置 create_bucket 请求:

    let bucket = control
        .create_bucket()
        .set_parent("projects/_")
        .set_bucket_id(bucket_id)
        .set_bucket(
            gcs::model::Bucket::new()
                .set_project(format!("projects/{project_id}"))
        )

  3. 可选:配置存储桶属性,例如统一存储桶级访问权限:

    gcs::model::Bucket::new()
        .set_project(format!("projects/{project_id}"))
        .set_iam_config(
            gcs::model::bucket::IamConfig::new().set_uniform_bucket_level_access(
                gcs::model::bucket::iam_config::UniformBucketLevelAccess::new()
                    .set_enabled(true),
            ),
        ),

  4. 发送请求并等待创建的 Bucket 元数据:

        .send()
        .await?;
    println!("bucket successfully created {bucket:?}");

写入对象

读取或写入对象数据的操作使用 Storage 客户端:

  1. 初始化 Storage 客户端:

    use google_cloud_storage::client::Storage;
    let client = Storage::builder().build().await?;

  2. 使用 write_object 将名为 hello.txt 的对象写入存储桶:

    let object = client
        .write_object(&bucket.name, "hello.txt", "Hello World!")
        .send_buffered()
        .await?;
    println!("object successfully uploaded {object:?}");

读取对象

如需读取对象的内容,请调用 read_object 并收集流式传输的数据块:

let mut reader = client.read_object(&bucket.name, "hello.txt").send().await?;
let mut contents = Vec::new();
while let Some(chunk) = reader.next().await.transpose()? {
    contents.extend_from_slice(&chunk);
}
println!(
    "object contents successfully downloaded {:?}",
    bytes::Bytes::from_owner(contents)
);

执行此步骤后,系统会输出下载的字节数:

object contents successfully downloaded b"Hello World!"

删除对象和存储桶

当不再需要程序中的对象和存储桶时,请将其删除:

control
    .delete_object()
    .set_bucket(&bucket.name)
    .set_object(&object.name)
    .set_generation(object.generation)
    .send()
    .await?;
control
    .delete_bucket()
    .set_name(&bucket.name)
    .send()
    .await?;

完整代码

以下函数结合了上述所有步骤:

pub async fn sample(project_id: &str, bucket_id: &str) -> anyhow::Result<()> {
    use google_cloud_storage as gcs;
    use google_cloud_storage::client::StorageControl;
    let control = StorageControl::builder().build().await?;
    let bucket = control
        .create_bucket()
        .set_parent("projects/_")
        .set_bucket_id(bucket_id)
        .set_bucket(
            gcs::model::Bucket::new()
                .set_project(format!("projects/{project_id}"))
                .set_iam_config(
                    gcs::model::bucket::IamConfig::new().set_uniform_bucket_level_access(
                        gcs::model::bucket::iam_config::UniformBucketLevelAccess::new()
                            .set_enabled(true),
                    ),
                ),
        )
        .send()
        .await?;
    println!("bucket successfully created {bucket:?}");

    use google_cloud_storage::client::Storage;
    let client = Storage::builder().build().await?;

    let object = client
        .write_object(&bucket.name, "hello.txt", "Hello World!")
        .send_buffered()
        .await?;
    println!("object successfully uploaded {object:?}");

    let mut reader = client.read_object(&bucket.name, "hello.txt").send().await?;
    let mut contents = Vec::new();
    while let Some(chunk) = reader.next().await.transpose()? {
        contents.extend_from_slice(&chunk);
    }
    println!(
        "object contents successfully downloaded {:?}",
        bytes::Bytes::from_owner(contents)
    );

    control
        .delete_object()
        .set_bucket(&bucket.name)
        .set_object(&object.name)
        .set_generation(object.generation)
        .send()
        .await?;
    control
        .delete_bucket()
        .set_name(&bucket.name)
        .send()
        .await?;

    Ok(())
}

清理

如果示例在运行删除步骤之前提前退出,请手动删除存储桶,以免本文档中创建的资源产生持续费用。