1use aws_sdk_s3::Client;
2use aws_sdk_s3::primitives::ByteStream;
3use aws_sdk_s3::types::ChecksumAlgorithm;
4
5pub async fn get_file_size(client: &Client, bucket: &str, key: &str) -> anyhow::Result<i64> {
6 let resp = client.head_object().bucket(bucket).key(key).send().await?;
7 Ok(resp.content_length.unwrap_or(0))
8}
9
10pub async fn append_to_file_multipart(
11 client: &Client,
12 bucket: &str,
13 key: &str,
14 content_to_append: &str,
16) -> anyhow::Result<()> {
17 let offset = get_file_size(client, bucket, key).await.unwrap_or(0);
18 let content_to_append = content_to_append.as_bytes().to_vec();
19 client
20 .put_object()
21 .set_write_offset_bytes(Some(offset))
22 .checksum_algorithm(ChecksumAlgorithm::Crc64Nvme)
23 .bucket(bucket)
24 .key(key)
25 .body(ByteStream::from(content_to_append)) .send()
27 .await?;
28 Ok(())
29}
30
31#[cfg(test)]
32mod tests {
33 use crate::config::{Bucket, Config, CronIntervalInMs, Endpoint, ObjectSizeLimitMb, Prefix};
34 use crate::s3_helpers::{append_to_file_multipart, get_file_size};
35 use chrono::Utc;
36
37 #[tokio::test]
38 pub async fn append_to_file_test() {
39 let config = Config::new(
40 None,
41 None,
42 None,
43 Bucket(None),
44 Prefix("prefix"),
45 Endpoint(None),
46 ObjectSizeLimitMb(1),
47 CronIntervalInMs(1_000),
48 )
49 .await
50 .unwrap();
51 for _ in 0..5 {
52 let result = append_to_file_multipart(
53 &config.aws_client,
54 &config.bucket,
55 "check-file-exists.log",
56 &format!("hello world {}\n", Utc::now()),
57 )
58 .await;
59 println!("append_to_file_test result => {result:?}");
60 }
61 }
62}