bitcoind_cache/store/
r2.rs1use 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}