bitcoind_cache/store/
r2.rs

1use std::time::Duration;
2
3use crate::store::{AsyncStoreResult, Store, StoreError};
4
5use s3::creds::Credentials;
6use s3::Bucket;
7use s3::Region;
8
9#[derive(Clone)]
10pub struct R2Store {
11    bucket: s3::Bucket,
12}
13
14impl R2Store {
15    pub fn new(
16        access_key_id: String,
17        secret_access_key: String,
18        account_id: String,
19        bucket_name: String,
20    ) -> R2Store {
21        let endpoint = format!("https://{}.r2.cloudflarestorage.com", account_id);
22        let region = Region::Custom {
23            region: String::from("auto"),
24            endpoint,
25        };
26        let creds = Credentials::new(
27            Some(&access_key_id),
28            Some(&secret_access_key),
29            None,
30            None,
31            None,
32        )
33        .unwrap();
34        let mut bucket = Bucket::new(&bucket_name, region, creds).unwrap();
35        bucket.set_request_timeout(Some(Duration::from_secs(10)));
36        R2Store { bucket }
37    }
38}
39
40impl Store for R2Store {
41    fn get_object(&self, filename: String) -> AsyncStoreResult<Option<Vec<u8>>> {
42        Box::pin(async move {
43            let mut retries = 30;
44            let mut success = false;
45            let mut last_response = None;
46
47            while !success && retries > 0 {
48                let response = self.bucket.get_object(filename.clone()).await;
49                success = response.is_err();
50                last_response = Some(response);
51                retries -= 1;
52            }
53
54            match last_response {
55                Some(Ok(response)) => Ok(Some(response.bytes().to_vec())),
56                Some(Err(e)) => Err(StoreError::R2(e)),
57                None => Ok(None),
58            }
59        })
60    }
61
62    fn put_object<'a>(&'a self, filename: String, content: &'a [u8]) -> AsyncStoreResult<()> {
63        Box::pin(async move {
64            let mut retries = 30;
65            let mut success = false;
66            let mut last_response = None;
67
68            while !success && retries > 0 {
69                let response = self.bucket.put_object(filename.clone(), content).await;
70                success = response.is_ok();
71                last_response = Some(response);
72                retries -= 1;
73            }
74
75            match last_response {
76                Some(Ok(_)) => Ok(()),
77                Some(Err(e)) => Err(StoreError::R2(e)),
78                None => Ok(()),
79            }
80        })
81    }
82}