|
|
@ -1,4 +1,4 @@ |
|
|
|
use std::fmt; |
|
|
|
use std::{fmt, time::Duration}; |
|
|
|
|
|
|
|
|
|
|
|
use abacus_core::SignedCheckpoint; |
|
|
|
use abacus_core::SignedCheckpoint; |
|
|
|
use async_trait::async_trait; |
|
|
|
use async_trait::async_trait; |
|
|
@ -11,9 +11,15 @@ use rusoto_core::{ |
|
|
|
HttpClient, Region, RusotoError, |
|
|
|
HttpClient, Region, RusotoError, |
|
|
|
}; |
|
|
|
}; |
|
|
|
use rusoto_s3::{GetObjectError, GetObjectRequest, PutObjectRequest, S3Client, S3}; |
|
|
|
use rusoto_s3::{GetObjectError, GetObjectRequest, PutObjectRequest, S3Client, S3}; |
|
|
|
|
|
|
|
use tokio::time::timeout; |
|
|
|
|
|
|
|
|
|
|
|
use crate::CheckpointSyncer; |
|
|
|
use crate::CheckpointSyncer; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// The timeout for S3 requests. Rusoto doesn't offer timeout configuration
|
|
|
|
|
|
|
|
/// out of the box, so S3 requests must be wrapped with a timeout.
|
|
|
|
|
|
|
|
/// See https://github.com/rusoto/rusoto/issues/1795.
|
|
|
|
|
|
|
|
const S3_REQUEST_TIMEOUT_SECONDS: u64 = 30; |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)] |
|
|
|
#[derive(Clone)] |
|
|
|
/// Type for reading/writing to S3
|
|
|
|
/// Type for reading/writing to S3
|
|
|
|
pub struct S3Storage { |
|
|
|
pub struct S3Storage { |
|
|
@ -58,7 +64,11 @@ impl S3Storage { |
|
|
|
content_type: Some("application/json".to_owned()), |
|
|
|
content_type: Some("application/json".to_owned()), |
|
|
|
..Default::default() |
|
|
|
..Default::default() |
|
|
|
}; |
|
|
|
}; |
|
|
|
self.authenticated_client().put_object(req).await?; |
|
|
|
timeout( |
|
|
|
|
|
|
|
Duration::from_secs(S3_REQUEST_TIMEOUT_SECONDS), |
|
|
|
|
|
|
|
self.authenticated_client().put_object(req), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.await??; |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -69,7 +79,13 @@ impl S3Storage { |
|
|
|
bucket: self.bucket.clone(), |
|
|
|
bucket: self.bucket.clone(), |
|
|
|
..Default::default() |
|
|
|
..Default::default() |
|
|
|
}; |
|
|
|
}; |
|
|
|
match self.anonymous_client().get_object(req).await { |
|
|
|
let get_object_result = timeout( |
|
|
|
|
|
|
|
Duration::from_secs(S3_REQUEST_TIMEOUT_SECONDS), |
|
|
|
|
|
|
|
self.anonymous_client().get_object(req), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.await?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match get_object_result { |
|
|
|
Ok(res) => match res.body { |
|
|
|
Ok(res) => match res.body { |
|
|
|
Some(body) => Ok(Some(body.map_ok(|b| b.to_vec()).try_concat().await?)), |
|
|
|
Some(body) => Ok(Some(body.map_ok(|b| b.to_vec()).try_concat().await?)), |
|
|
|
None => Ok(None), |
|
|
|
None => Ok(None), |
|
|
|