1use crate::types::{ClientConfigLocation, S3Credentials, SseCustomerKey, SseKmsKeyId, StoragePath};
2use aws_sdk_s3::types::{
3 ChecksumAlgorithm, ChecksumMode, ObjectCannedAcl, RequestPayer, ServerSideEncryption,
4 StorageClass,
5};
6use aws_smithy_types::checksum_config::RequestChecksumCalculation;
7use chrono::{DateTime, Utc};
8use std::collections::HashMap;
9use std::sync::Arc;
10use tokio::sync::Semaphore;
11
12pub mod args;
13
14#[derive(Debug, Clone)]
15pub struct Config {
16 pub source: StoragePath,
17 pub target: StoragePath,
18 pub show_progress: bool,
19 pub source_client_config: Option<ClientConfig>,
20 pub target_client_config: Option<ClientConfig>,
21 pub tracing_config: Option<TracingConfig>,
22 pub transfer_config: TransferConfig,
23 pub disable_tagging: bool,
24 pub server_side_copy: bool,
25 pub no_guess_mime_type: bool,
26 pub disable_multipart_verify: bool,
27 pub disable_etag_verify: bool,
28 pub disable_additional_checksum_verify: bool,
29 pub storage_class: Option<StorageClass>,
30 pub sse: Option<ServerSideEncryption>,
31 pub sse_kms_key_id: SseKmsKeyId,
32 pub source_sse_c: Option<String>,
33 pub source_sse_c_key: SseCustomerKey,
34 pub source_sse_c_key_md5: Option<String>,
35 pub target_sse_c: Option<String>,
36 pub target_sse_c_key: SseCustomerKey,
37 pub target_sse_c_key_md5: Option<String>,
38 pub canned_acl: Option<ObjectCannedAcl>,
39 pub additional_checksum_mode: Option<ChecksumMode>,
40 pub additional_checksum_algorithm: Option<ChecksumAlgorithm>,
41 pub cache_control: Option<String>,
42 pub content_disposition: Option<String>,
43 pub content_encoding: Option<String>,
44 pub content_language: Option<String>,
45 pub content_type: Option<String>,
46 pub expires: Option<DateTime<Utc>>,
47 pub metadata: Option<HashMap<String, String>>,
48 pub no_sync_system_metadata: bool,
49 pub no_sync_user_defined_metadata: bool,
50 pub website_redirect: Option<String>,
51 pub tagging: Option<String>,
52 pub put_last_modified_metadata: bool,
53 pub disable_payload_signing: bool,
54 pub disable_content_md5_header: bool,
55 pub full_object_checksum: bool,
56 pub source_accelerate: bool,
57 pub target_accelerate: bool,
58 pub source_request_payer: bool,
59 pub target_request_payer: bool,
60 pub if_none_match: bool,
61 pub disable_stalled_stream_protection: bool,
62 pub disable_express_one_zone_additional_checksum: bool,
63 pub max_parallel_uploads: u16,
64 pub rate_limit_bandwidth: Option<u64>,
65 pub version_id: Option<String>,
66 pub is_stdio_source: bool,
67 pub is_stdio_target: bool,
68 pub no_fail_on_verify_error: bool,
69 pub skip_existing: bool,
70 pub dry_run: bool,
71}
72
73#[derive(Debug, Clone)]
74pub struct ClientConfig {
75 pub client_config_location: ClientConfigLocation,
76 pub credential: S3Credentials,
77 pub region: Option<String>,
78 pub endpoint_url: Option<String>,
79 pub force_path_style: bool,
80 pub accelerate: bool,
81 pub request_payer: Option<RequestPayer>,
82 pub retry_config: RetryConfig,
83 pub cli_timeout_config: CLITimeoutConfig,
84 pub disable_stalled_stream_protection: bool,
85 pub request_checksum_calculation: RequestChecksumCalculation,
86 pub parallel_upload_semaphore: Arc<Semaphore>,
87}
88
89#[derive(Debug, Clone)]
90pub struct RetryConfig {
91 pub aws_max_attempts: u32,
92 pub initial_backoff_milliseconds: u64,
93}
94
95#[derive(Debug, Clone)]
96pub struct CLITimeoutConfig {
97 pub operation_timeout_milliseconds: Option<u64>,
98 pub operation_attempt_timeout_milliseconds: Option<u64>,
99 pub connect_timeout_milliseconds: Option<u64>,
100 pub read_timeout_milliseconds: Option<u64>,
101}
102
103#[derive(Debug, Clone, Copy)]
104pub struct TracingConfig {
105 pub tracing_level: log::Level,
106 pub json_tracing: bool,
107 pub aws_sdk_tracing: bool,
108 pub span_events_tracing: bool,
109 pub disable_color_tracing: bool,
110}
111
112#[derive(Debug, Clone, Copy)]
113pub struct TransferConfig {
114 pub multipart_threshold: u64,
115 pub multipart_chunksize: u64,
116 pub auto_chunksize: bool,
117}
118
119impl TransferConfig {
120 pub fn is_multipart_upload_required(&self, content_length: u64) -> bool {
121 self.multipart_threshold <= content_length
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_is_multipart_upload_necessary() {
131 let transfer_config = TransferConfig {
132 multipart_threshold: 8 * 1024 * 1024,
133 multipart_chunksize: 8 * 1024 * 1024,
134 auto_chunksize: false,
135 };
136
137 assert!(transfer_config.is_multipart_upload_required(8 * 1024 * 1024));
138 assert!(transfer_config.is_multipart_upload_required((8 * 1024 * 1024) + 1));
139 assert!(!transfer_config.is_multipart_upload_required((8 * 1024 * 1024) - 1));
140 }
141}