mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 19:31:35 +00:00
More migration work for rusty-s3
This commit is contained in:
parent
ab7fd9aaf7
commit
ff1771e016
6 changed files with 116 additions and 48 deletions
|
@ -543,13 +543,30 @@ struct Filesystem {
|
||||||
#[derive(Clone, Debug, Parser, serde::Serialize)]
|
#[derive(Clone, Debug, Parser, serde::Serialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
struct ObjectStorage {
|
struct ObjectStorage {
|
||||||
|
/// The base endpoint for the object storage
|
||||||
|
///
|
||||||
|
/// Examples:
|
||||||
|
/// - `http://localhost:9000`
|
||||||
|
/// - `https://s3.dualstack.eu-west-1.amazonaws.com`
|
||||||
|
#[clap(short, long)]
|
||||||
|
endpoint: Url,
|
||||||
|
|
||||||
|
/// Determines whether to use path style or virtualhost style for accessing objects
|
||||||
|
///
|
||||||
|
/// When this is true, objects will be fetched from {endpoint}/{bucket_name}/{object}
|
||||||
|
/// When false, objects will be fetched from {bucket_name}.{endpoint}/{object}
|
||||||
|
#[clap(short, long)]
|
||||||
|
use_path_style: bool,
|
||||||
|
|
||||||
/// The bucket in which to store media
|
/// The bucket in which to store media
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
bucket_name: Option<String>,
|
bucket_name: Option<String>,
|
||||||
|
|
||||||
/// The region the bucket is located in
|
/// The region the bucket is located in
|
||||||
|
///
|
||||||
|
/// For minio deployments, this can just be 'minio'
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
region: Option<Serde<s3::Region>>,
|
region: Option<String>,
|
||||||
|
|
||||||
/// The Access Key for the user accessing the bucket
|
/// The Access Key for the user accessing the bucket
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::magick::ValidInputType;
|
use crate::magick::ValidInputType;
|
||||||
use crate::serde_str::Serde;
|
|
||||||
use clap::ArgEnum;
|
use clap::ArgEnum;
|
||||||
use std::{fmt::Display, path::PathBuf, str::FromStr};
|
use std::{fmt::Display, path::PathBuf, str::FromStr};
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
|
@ -63,13 +63,28 @@ pub(crate) struct Filesystem {
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, clap::Parser)]
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, clap::Parser)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub(crate) struct ObjectStorage {
|
pub(crate) struct ObjectStorage {
|
||||||
|
/// The base endpoint for the object storage
|
||||||
|
///
|
||||||
|
/// Examples:
|
||||||
|
/// - `http://localhost:9000`
|
||||||
|
/// - `https://s3.dualstack.eu-west-1.amazonaws.com`
|
||||||
|
#[clap(short, long)]
|
||||||
|
pub(crate) endpoint: Url,
|
||||||
|
|
||||||
|
/// Determines whether to use path style or virtualhost style for accessing objects
|
||||||
|
///
|
||||||
|
/// When this is true, objects will be fetched from {endpoint}/{bucket_name}/{object}
|
||||||
|
/// When false, objects will be fetched from {bucket_name}.{endpoint}/{object}
|
||||||
|
#[clap(short, long)]
|
||||||
|
pub(crate) use_path_style: bool,
|
||||||
|
|
||||||
/// The bucket in which to store media
|
/// The bucket in which to store media
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub(crate) bucket_name: String,
|
pub(crate) bucket_name: String,
|
||||||
|
|
||||||
/// The region the bucket is located in
|
/// The region the bucket is located in
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub(crate) region: Serde<s3::Region>,
|
pub(crate) region: String,
|
||||||
|
|
||||||
/// The Access Key for the user accessing the bucket
|
/// The Access Key for the user accessing the bucket
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
@ -219,7 +234,8 @@ impl Display for LogFormat {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Serde, Targets};
|
use super::Targets;
|
||||||
|
use crate::serde_str::Serde;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builds_info_targets() {
|
fn builds_info_targets() {
|
||||||
|
|
50
src/main.rs
50
src/main.rs
|
@ -10,6 +10,7 @@ use futures_util::{
|
||||||
Stream, StreamExt, TryStreamExt,
|
Stream, StreamExt, TryStreamExt,
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
use rusty_s3::UrlStyle;
|
||||||
use std::{
|
use std::{
|
||||||
future::ready,
|
future::ready,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
@ -970,15 +971,15 @@ fn next_worker_id() -> String {
|
||||||
format!("{}-{}", CONFIG.server.worker_id, next_id)
|
format!("{}-{}", CONFIG.server.worker_id, next_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn launch<R: FullRepo + Clone + 'static, S: Store + Clone + 'static>(
|
async fn launch<R: FullRepo + 'static, S: Store + 'static>(
|
||||||
repo: R,
|
repo: R,
|
||||||
store: S,
|
store: S::Config,
|
||||||
) -> color_eyre::Result<()> {
|
) -> color_eyre::Result<()> {
|
||||||
repo.requeue_in_progress(CONFIG.server.worker_id.as_bytes().to_vec())
|
repo.requeue_in_progress(CONFIG.server.worker_id.as_bytes().to_vec())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
let store = store.clone();
|
let store = S::init(store.clone());
|
||||||
let repo = repo.clone();
|
let repo = repo.clone();
|
||||||
|
|
||||||
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
tracing::trace_span!(parent: None, "Spawn task").in_scope(|| {
|
||||||
|
@ -1081,6 +1082,8 @@ where
|
||||||
match to {
|
match to {
|
||||||
config::Store::Filesystem(config::Filesystem { path }) => {
|
config::Store::Filesystem(config::Filesystem { path }) => {
|
||||||
let to = FileStore::build(path.clone(), repo.clone()).await?;
|
let to = FileStore::build(path.clone(), repo.clone()).await?;
|
||||||
|
let to = FileStore::init(to);
|
||||||
|
|
||||||
match repo {
|
match repo {
|
||||||
Repo::Sled(repo) => migrate_store(repo, from, to).await?,
|
Repo::Sled(repo) => migrate_store(repo, from, to).await?,
|
||||||
}
|
}
|
||||||
|
@ -1088,25 +1091,30 @@ where
|
||||||
config::Store::ObjectStorage(config::ObjectStorage {
|
config::Store::ObjectStorage(config::ObjectStorage {
|
||||||
endpoint,
|
endpoint,
|
||||||
bucket_name,
|
bucket_name,
|
||||||
url_style,
|
use_path_style,
|
||||||
region,
|
region,
|
||||||
access_key,
|
access_key,
|
||||||
secret_key,
|
secret_key,
|
||||||
session_token,
|
session_token,
|
||||||
}) => {
|
}) => {
|
||||||
let to = ObjectStore::build(
|
let to = ObjectStore::build(
|
||||||
endpoint,
|
endpoint.clone(),
|
||||||
bucket_name,
|
bucket_name,
|
||||||
url_style,
|
if *use_path_style {
|
||||||
|
UrlStyle::Path
|
||||||
|
} else {
|
||||||
|
UrlStyle::VirtualHost
|
||||||
|
},
|
||||||
region.as_ref(),
|
region.as_ref(),
|
||||||
Some(access_key.clone()),
|
Some(access_key.clone()),
|
||||||
Some(secret_key.clone()),
|
Some(secret_key.clone()),
|
||||||
session_token.clone(),
|
session_token.clone(),
|
||||||
repo.clone(),
|
repo.clone(),
|
||||||
build_client(),
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let to = ObjectStore::init(to);
|
||||||
|
|
||||||
match repo {
|
match repo {
|
||||||
Repo::Sled(repo) => migrate_store(repo, from, to).await?,
|
Repo::Sled(repo) => migrate_store(repo, from, to).await?,
|
||||||
}
|
}
|
||||||
|
@ -1129,29 +1137,34 @@ async fn main() -> color_eyre::Result<()> {
|
||||||
match from {
|
match from {
|
||||||
config::Store::Filesystem(config::Filesystem { path }) => {
|
config::Store::Filesystem(config::Filesystem { path }) => {
|
||||||
let from = FileStore::build(path.clone(), repo.clone()).await?;
|
let from = FileStore::build(path.clone(), repo.clone()).await?;
|
||||||
|
let from = FileStore::init(from);
|
||||||
migrate_inner(&repo, from, &to).await?;
|
migrate_inner(&repo, from, &to).await?;
|
||||||
}
|
}
|
||||||
config::Store::ObjectStorage(config::ObjectStorage {
|
config::Store::ObjectStorage(config::ObjectStorage {
|
||||||
endpoint,
|
endpoint,
|
||||||
bucket_name,
|
bucket_name,
|
||||||
url_style,
|
use_path_style,
|
||||||
region,
|
region,
|
||||||
access_key,
|
access_key,
|
||||||
secret_key,
|
secret_key,
|
||||||
session_token,
|
session_token,
|
||||||
}) => {
|
}) => {
|
||||||
let from = ObjectStore::build(
|
let from = ObjectStore::build(
|
||||||
endpoint,
|
endpoint.clone(),
|
||||||
&bucket_name,
|
&bucket_name,
|
||||||
url_style,
|
if *use_path_style {
|
||||||
|
UrlStyle::Path
|
||||||
|
} else {
|
||||||
|
UrlStyle::VirtualHost
|
||||||
|
},
|
||||||
Serde::into_inner(region),
|
Serde::into_inner(region),
|
||||||
Some(access_key),
|
Some(access_key),
|
||||||
Some(secret_key),
|
Some(secret_key),
|
||||||
session_token,
|
session_token,
|
||||||
repo.clone(),
|
repo.clone(),
|
||||||
build_client(),
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
let from = ObjectStore::init(from);
|
||||||
|
|
||||||
migrate_inner(&repo, from, &to).await?;
|
migrate_inner(&repo, from, &to).await?;
|
||||||
}
|
}
|
||||||
|
@ -1167,33 +1180,36 @@ async fn main() -> color_eyre::Result<()> {
|
||||||
|
|
||||||
let store = FileStore::build(path, repo.clone()).await?;
|
let store = FileStore::build(path, repo.clone()).await?;
|
||||||
match repo {
|
match repo {
|
||||||
Repo::Sled(sled_repo) => launch(sled_repo, store).await,
|
Repo::Sled(sled_repo) => launch::<_, FileStore>(sled_repo, store).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config::Store::ObjectStorage(config::ObjectStorage {
|
config::Store::ObjectStorage(config::ObjectStorage {
|
||||||
endpoint,
|
endpoint,
|
||||||
bucket_name,
|
bucket_name,
|
||||||
url_style,
|
use_path_style,
|
||||||
region,
|
region,
|
||||||
access_key,
|
access_key,
|
||||||
secret_key,
|
secret_key,
|
||||||
session_token,
|
session_token,
|
||||||
}) => {
|
}) => {
|
||||||
let store = ObjectStore::build(
|
let store = ObjectStore::build(
|
||||||
endpoint,
|
endpoint.clone(),
|
||||||
&bucket_name,
|
&bucket_name,
|
||||||
url_style,
|
if *use_path_style {
|
||||||
|
UrlStyle::Path
|
||||||
|
} else {
|
||||||
|
UrlStyle::VirtualHost
|
||||||
|
},
|
||||||
Serde::into_inner(region),
|
Serde::into_inner(region),
|
||||||
Some(access_key),
|
Some(access_key),
|
||||||
Some(secret_key),
|
Some(secret_key),
|
||||||
session_token,
|
session_token,
|
||||||
repo.clone(),
|
repo.clone(),
|
||||||
build_client(),
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
match repo {
|
match repo {
|
||||||
Repo::Sled(sled_repo) => launch(sled_repo, store).await,
|
Repo::Sled(sled_repo) => launch::<_, ObjectStore>(sled_repo, store).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,13 @@ pub(crate) trait Identifier: Send + Sync + Clone + Debug {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
pub(crate) trait Store: Send + Sync + Clone + Debug {
|
pub(crate) trait Store: Clone + Debug {
|
||||||
|
type Config: Send + Sync + Clone;
|
||||||
type Identifier: Identifier + 'static;
|
type Identifier: Identifier + 'static;
|
||||||
type Stream: Stream<Item = std::io::Result<Bytes>> + 'static;
|
type Stream: Stream<Item = std::io::Result<Bytes>> + 'static;
|
||||||
|
|
||||||
|
fn init(config: Self::Config) -> Self;
|
||||||
|
|
||||||
async fn save_async_read<Reader>(&self, reader: &mut Reader) -> Result<Self::Identifier, Error>
|
async fn save_async_read<Reader>(&self, reader: &mut Reader) -> Result<Self::Identifier, Error>
|
||||||
where
|
where
|
||||||
Reader: AsyncRead + Unpin;
|
Reader: AsyncRead + Unpin;
|
||||||
|
|
|
@ -49,9 +49,14 @@ pub(crate) struct FileStore {
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Store for FileStore {
|
impl Store for FileStore {
|
||||||
|
type Config = Self;
|
||||||
type Identifier = FileId;
|
type Identifier = FileId;
|
||||||
type Stream = Pin<Box<dyn Stream<Item = std::io::Result<Bytes>>>>;
|
type Stream = Pin<Box<dyn Stream<Item = std::io::Result<Bytes>>>>;
|
||||||
|
|
||||||
|
fn init(config: Self::Config) -> Self {
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(reader))]
|
#[tracing::instrument(skip(reader))]
|
||||||
async fn save_async_read<Reader>(&self, reader: &mut Reader) -> Result<Self::Identifier, Error>
|
async fn save_async_read<Reader>(&self, reader: &mut Reader) -> Result<Self::Identifier, Error>
|
||||||
where
|
where
|
||||||
|
|
|
@ -12,15 +12,11 @@ use actix_web::{
|
||||||
};
|
};
|
||||||
use awc::{Client, ClientRequest};
|
use awc::{Client, ClientRequest};
|
||||||
use futures_util::{Stream, TryStreamExt};
|
use futures_util::{Stream, TryStreamExt};
|
||||||
use rusty_s3::{
|
use rusty_s3::{actions::S3Action, Bucket, Credentials, UrlStyle};
|
||||||
actions::{PutObject, S3Action},
|
|
||||||
Bucket, Credentials, UrlStyle,
|
|
||||||
};
|
|
||||||
use std::{pin::Pin, string::FromUtf8Error, time::Duration};
|
use std::{pin::Pin, string::FromUtf8Error, time::Duration};
|
||||||
use storage_path_generator::{Generator, Path};
|
use storage_path_generator::{Generator, Path};
|
||||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
|
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
|
||||||
use tokio_util::io::ReaderStream;
|
use tokio_util::io::ReaderStream;
|
||||||
use tracing::Instrument;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
mod object_id;
|
mod object_id;
|
||||||
|
@ -55,24 +51,41 @@ pub(crate) struct ObjectStore {
|
||||||
client: Client,
|
client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct ObjectStoreConfig {
|
||||||
|
path_gen: Generator,
|
||||||
|
repo: Repo,
|
||||||
|
bucket: Bucket,
|
||||||
|
credentials: Credentials,
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Store for ObjectStore {
|
impl Store for ObjectStore {
|
||||||
|
type Config = ObjectStoreConfig;
|
||||||
type Identifier = ObjectId;
|
type Identifier = ObjectId;
|
||||||
type Stream = Pin<Box<dyn Stream<Item = std::io::Result<Bytes>>>>;
|
type Stream = Pin<Box<dyn Stream<Item = std::io::Result<Bytes>>>>;
|
||||||
|
|
||||||
|
fn init(config: Self::Config) -> Self {
|
||||||
|
ObjectStore {
|
||||||
|
path_gen: config.path_gen,
|
||||||
|
repo: config.repo,
|
||||||
|
bucket: config.bucket,
|
||||||
|
credentials: config.credentials,
|
||||||
|
client: crate::build_client(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(reader))]
|
#[tracing::instrument(skip(reader))]
|
||||||
async fn save_async_read<Reader>(&self, reader: &mut Reader) -> Result<Self::Identifier, Error>
|
async fn save_async_read<Reader>(&self, reader: &mut Reader) -> Result<Self::Identifier, Error>
|
||||||
where
|
where
|
||||||
Reader: AsyncRead + Unpin,
|
Reader: AsyncRead + Unpin,
|
||||||
{
|
{
|
||||||
let response = self
|
let (req, object_id) = self.put_object_request().await?;
|
||||||
.put_object_request()
|
|
||||||
.await?
|
let response = req.send_stream(ReaderStream::new(reader)).await?;
|
||||||
.send_stream(ReaderStream::new(reader))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if response.status().is_success() {
|
if response.status().is_success() {
|
||||||
return Ok(ObjectId::from_string(path));
|
return Ok(object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(ObjectError::Status(response.status()).into())
|
Err(ObjectError::Status(response.status()).into())
|
||||||
|
@ -80,12 +93,12 @@ impl Store for ObjectStore {
|
||||||
|
|
||||||
#[tracing::instrument(skip(bytes))]
|
#[tracing::instrument(skip(bytes))]
|
||||||
async fn save_bytes(&self, bytes: Bytes) -> Result<Self::Identifier, Error> {
|
async fn save_bytes(&self, bytes: Bytes) -> Result<Self::Identifier, Error> {
|
||||||
let req = self.put_object_request().await?;
|
let (req, object_id) = self.put_object_request().await?;
|
||||||
|
|
||||||
let response = req.send_body(bytes).await?;
|
let response = req.send_body(bytes).await?;
|
||||||
|
|
||||||
if response.status().is_success() {
|
if response.status().is_success() {
|
||||||
return Ok(ObjectId::from_string(path));
|
return Ok(object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(ObjectError::Status(response.status()).into())
|
Err(ObjectError::Status(response.status()).into())
|
||||||
|
@ -103,7 +116,7 @@ impl Store for ObjectStore {
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if response.status.is_success() {
|
if response.status().is_success() {
|
||||||
return Ok(Box::pin(response));
|
return Ok(Box::pin(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,11 +133,11 @@ impl Store for ObjectStore {
|
||||||
Writer: AsyncWrite + Send + Unpin,
|
Writer: AsyncWrite + Send + Unpin,
|
||||||
{
|
{
|
||||||
let response = self
|
let response = self
|
||||||
.get_object_request(identifier, from_start, len)
|
.get_object_request(identifier, None, None)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !response.status.is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(ObjectError::Status(response.status()).into());
|
return Err(ObjectError::Status(response.status()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +154,7 @@ impl Store for ObjectStore {
|
||||||
async fn len(&self, identifier: &Self::Identifier) -> Result<u64, Error> {
|
async fn len(&self, identifier: &Self::Identifier) -> Result<u64, Error> {
|
||||||
let response = self.head_object_request(identifier).send().await?;
|
let response = self.head_object_request(identifier).send().await?;
|
||||||
|
|
||||||
if !response.status.is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(ObjectError::Status(response.status()).into());
|
return Err(ObjectError::Status(response.status()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +174,7 @@ impl Store for ObjectStore {
|
||||||
async fn remove(&self, identifier: &Self::Identifier) -> Result<(), Error> {
|
async fn remove(&self, identifier: &Self::Identifier) -> Result<(), Error> {
|
||||||
let response = self.delete_object_request(identifier).send().await?;
|
let response = self.delete_object_request(identifier).send().await?;
|
||||||
|
|
||||||
if !response.status.is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(ObjectError::Status(response.status()).into());
|
return Err(ObjectError::Status(response.status()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,29 +193,27 @@ impl ObjectStore {
|
||||||
secret_key: Option<String>,
|
secret_key: Option<String>,
|
||||||
session_token: Option<String>,
|
session_token: Option<String>,
|
||||||
repo: Repo,
|
repo: Repo,
|
||||||
client: reqwest::Client,
|
) -> Result<ObjectStoreConfig, Error> {
|
||||||
) -> Result<ObjectStore, Error> {
|
|
||||||
let path_gen = init_generator(&repo).await?;
|
let path_gen = init_generator(&repo).await?;
|
||||||
|
|
||||||
Ok(ObjectStore {
|
Ok(ObjectStoreConfig {
|
||||||
path_gen,
|
path_gen,
|
||||||
repo,
|
repo,
|
||||||
bucket: Bucket::new(endpoint, url_style, bucket_name, region)
|
bucket: Bucket::new(endpoint, url_style, bucket_name, region)
|
||||||
.map_err(ObjectError::from)?,
|
.map_err(ObjectError::from)?,
|
||||||
credentials: Credentials::new_with_token(access_key, secret_key, session_token),
|
credentials: Credentials::new_with_token(access_key, secret_key, session_token),
|
||||||
client,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn put_object_request(&self) -> Result<ClientRequest, Error> {
|
async fn put_object_request(&self) -> Result<(ClientRequest, ObjectId), Error> {
|
||||||
let path = self.next_file().await?;
|
let path = self.next_file().await?;
|
||||||
|
|
||||||
let action = self.bucket.put_object(Some(&self.credentials), &path);
|
let action = self.bucket.put_object(Some(&self.credentials), &path);
|
||||||
|
|
||||||
Ok(self.build_request(action))
|
Ok((self.build_request(action), ObjectId::from_string(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_request<A: S3Action>(&self, action: A) -> ClientRequest {
|
fn build_request<'a, A: S3Action<'a>>(&'a self, action: A) -> ClientRequest {
|
||||||
let method = match A::METHOD {
|
let method = match A::METHOD {
|
||||||
rusty_s3::Method::Head => awc::http::Method::HEAD,
|
rusty_s3::Method::Head => awc::http::Method::HEAD,
|
||||||
rusty_s3::Method::Get => awc::http::Method::GET,
|
rusty_s3::Method::Get => awc::http::Method::GET,
|
||||||
|
@ -243,7 +254,7 @@ impl ObjectStore {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(range) = range {
|
if let Some(range) = range {
|
||||||
req.insert_header(Range::Bytes(vec![range])).send().await?;
|
req.insert_header(Range::Bytes(vec![range]))
|
||||||
} else {
|
} else {
|
||||||
req
|
req
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue