1use std::{env, fs, io::Write};
2
3use anyhow::Error;
4use async_trait::async_trait;
5use aws_config::meta::region::RegionProviderChain;
6use aws_sdk_s3::{primitives::ByteStream, Client};
7use owo_colors::OwoColorize;
8
9use super::CacheBackend;
10
11pub struct S3 {
12 client: Client,
13 prefix: String,
14}
15
16pub async fn new() -> Result<S3, Error> {
17 let region_provider = RegionProviderChain::default_provider().or_else("us-east-1");
18
19 #[allow(deprecated)]
20 let config = aws_config::from_env()
21 .endpoint_url(std::env::var("FLUENTCI_CACHE_S3_ENDPOINT")?)
22 .region(region_provider)
23 .load()
24 .await;
25 let client = Client::new(&config);
26 let prefix = format!("{}/{}", env::consts::OS, env::consts::ARCH);
27
28 Ok(S3 { client, prefix })
29}
30
31#[async_trait]
32impl CacheBackend for S3 {
33 async fn restore(&self, path: &str) -> Result<(), Error> {
34 let filename = path.split("/").last().unwrap();
35 let bucket = env::var("FLUENTCI_CACHE_S3_BUCKET")?;
36 let key = format!("{}/{}", self.prefix, filename);
37
38 if let Ok(mut object) = self
39 .client
40 .get_object()
41 .bucket(bucket)
42 .key(key.clone())
43 .send()
44 .await
45 {
46 let mut file = fs::File::create(path)?;
47 while let Some(chunk) = object.body.try_next().await? {
48 file.write_all(&chunk)?;
49 }
50 return Ok(());
51 }
52
53 println!("{} Cache not found for key: {}", "[s3]".cyan(), key);
54
55 Ok(())
56 }
57
58 async fn save(&self, path: &str) -> Result<(), Error> {
59 let body = ByteStream::read_from()
60 .path(path)
61 .buffer_size(2048)
62 .build()
63 .await?;
64
65 let bucket = env::var("FLUENTCI_CACHE_S3_BUCKET")?;
66
67 let filename = path.split("/").last().unwrap();
68 let key = format!("{}/{}", self.prefix, filename);
69
70 match self
71 .client
72 .put_object()
73 .bucket(bucket)
74 .key(key)
75 .body(body)
76 .send()
77 .await
78 {
79 Ok(_) => {
80 println!(" Uploaded succesfully")
81 }
82 Err(e) => {
83 println!(" Failed to upload: {}", e)
84 }
85 }
86
87 Ok(())
88 }
89}