1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
#[macro_use]
extern crate derive_error;
extern crate hyper;
extern crate rusoto_core;
extern crate rusoto_credential;
extern crate rusoto_s3;

pub mod error;
use error::{S4Error, S4Result};

use hyper::Client;
use rusoto_core::{default_tls_client, DispatchSignedRequest, Region};
use rusoto_credential::{CredentialsError, DefaultCredentialsProvider, ProvideAwsCredentials,
                        StaticProvider};
use rusoto_s3::{GetObjectOutput, GetObjectRequest, S3, S3Client};
use std::convert::AsRef;
use std::fs::OpenOptions;
use std::io::{self, Write};
use std::path::Path;

/// Create client using given static access/secret keys
///
/// # Panics
///
/// Panics if TLS cannot be initialized.
pub fn new_s3client_with_credentials(
    region: Region,
    access_key: String,
    secret_key: String,
) -> S3Client<StaticProvider, Client> {
    S3Client::new(
        default_tls_client().expect("failed to initialize TLS client"),
        StaticProvider::new_minimal(access_key, secret_key),
        region,
    )
}

/// Create client with default TLS client and credentials provider
///
/// # Panics
///
/// Panics if TLS cannot be initialized.
pub fn new_s3client_simple(
    region: Region,
) -> Result<S3Client<DefaultCredentialsProvider, Client>, CredentialsError> {
    Ok(S3Client::new(
        default_tls_client().expect("failed to initialize TLS client"),
        DefaultCredentialsProvider::new()?,
        region,
    ))
}

pub trait S4 {
    /// Get object and write it to file `target`
    fn object_to_file<F>(&self, source: &GetObjectRequest, target: F) -> S4Result<GetObjectOutput>
    where
        F: AsRef<Path>;

    /// Get object and write it to `target`
    fn object_to_write<W>(
        &self,
        source: &GetObjectRequest,
        target: &mut W,
    ) -> S4Result<GetObjectOutput>
    where
        W: Write;
}

impl<P, D> S4 for S3Client<P, D>
where
    P: ProvideAwsCredentials,
    D: DispatchSignedRequest,
{
    fn object_to_file<F>(
        &self,
        source: &GetObjectRequest,
        target: F,
    ) -> Result<GetObjectOutput, S4Error>
    where
        F: AsRef<Path>,
    {
        let mut resp = self.get_object(source)?;
        let mut body = resp.body.take().expect("no body");
        let mut target = OpenOptions::new()
            .write(true)
            .create_new(true)
            .open(target)?;
        io::copy(&mut body, &mut target)?;
        Ok(resp)
    }

    fn object_to_write<W>(
        &self,
        source: &GetObjectRequest,
        mut target: &mut W,
    ) -> Result<GetObjectOutput, S4Error>
    where
        W: Write,
    {
        let mut resp = self.get_object(source)?;
        let mut body = resp.body.take().expect("no body");
        io::copy(&mut body, &mut target)?;
        Ok(resp)
    }
}