aws-sdk-resources 2.3.23 → 3.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/bin/aws-v3.rb +201 -0
- data/lib/aws-sdk-resources.rb +223 -87
- metadata +3073 -71
- data/lib/aws-sdk-resources/batch.rb +0 -143
- data/lib/aws-sdk-resources/builder.rb +0 -85
- data/lib/aws-sdk-resources/builder_sources.rb +0 -105
- data/lib/aws-sdk-resources/collection.rb +0 -107
- data/lib/aws-sdk-resources/definition.rb +0 -331
- data/lib/aws-sdk-resources/documenter.rb +0 -70
- data/lib/aws-sdk-resources/documenter/base_operation_documenter.rb +0 -279
- data/lib/aws-sdk-resources/documenter/data_operation_documenter.rb +0 -25
- data/lib/aws-sdk-resources/documenter/has_many_operation_documenter.rb +0 -67
- data/lib/aws-sdk-resources/documenter/has_operation_documenter.rb +0 -66
- data/lib/aws-sdk-resources/documenter/operation_documenter.rb +0 -20
- data/lib/aws-sdk-resources/documenter/resource_operation_documenter.rb +0 -53
- data/lib/aws-sdk-resources/documenter/waiter_operation_documenter.rb +0 -77
- data/lib/aws-sdk-resources/errors.rb +0 -15
- data/lib/aws-sdk-resources/operation_methods.rb +0 -83
- data/lib/aws-sdk-resources/operations.rb +0 -280
- data/lib/aws-sdk-resources/options.rb +0 -17
- data/lib/aws-sdk-resources/request.rb +0 -39
- data/lib/aws-sdk-resources/request_params.rb +0 -140
- data/lib/aws-sdk-resources/resource.rb +0 -243
- data/lib/aws-sdk-resources/services/ec2.rb +0 -21
- data/lib/aws-sdk-resources/services/ec2/instance.rb +0 -29
- data/lib/aws-sdk-resources/services/iam.rb +0 -19
- data/lib/aws-sdk-resources/services/s3.rb +0 -19
- data/lib/aws-sdk-resources/services/s3/bucket.rb +0 -127
- data/lib/aws-sdk-resources/services/s3/encryption.rb +0 -21
- data/lib/aws-sdk-resources/services/s3/encryption/client.rb +0 -369
- data/lib/aws-sdk-resources/services/s3/encryption/decrypt_handler.rb +0 -174
- data/lib/aws-sdk-resources/services/s3/encryption/default_cipher_provider.rb +0 -63
- data/lib/aws-sdk-resources/services/s3/encryption/default_key_provider.rb +0 -38
- data/lib/aws-sdk-resources/services/s3/encryption/encrypt_handler.rb +0 -50
- data/lib/aws-sdk-resources/services/s3/encryption/errors.rb +0 -13
- data/lib/aws-sdk-resources/services/s3/encryption/io_auth_decrypter.rb +0 -50
- data/lib/aws-sdk-resources/services/s3/encryption/io_decrypter.rb +0 -29
- data/lib/aws-sdk-resources/services/s3/encryption/io_encrypter.rb +0 -69
- data/lib/aws-sdk-resources/services/s3/encryption/key_provider.rb +0 -29
- data/lib/aws-sdk-resources/services/s3/encryption/kms_cipher_provider.rb +0 -71
- data/lib/aws-sdk-resources/services/s3/encryption/materials.rb +0 -58
- data/lib/aws-sdk-resources/services/s3/encryption/utils.rb +0 -79
- data/lib/aws-sdk-resources/services/s3/file_part.rb +0 -75
- data/lib/aws-sdk-resources/services/s3/file_uploader.rb +0 -58
- data/lib/aws-sdk-resources/services/s3/multipart_file_uploader.rb +0 -187
- data/lib/aws-sdk-resources/services/s3/multipart_upload.rb +0 -42
- data/lib/aws-sdk-resources/services/s3/multipart_upload_error.rb +0 -16
- data/lib/aws-sdk-resources/services/s3/object.rb +0 -257
- data/lib/aws-sdk-resources/services/s3/object_copier.rb +0 -99
- data/lib/aws-sdk-resources/services/s3/object_multipart_copier.rb +0 -179
- data/lib/aws-sdk-resources/services/s3/object_summary.rb +0 -65
- data/lib/aws-sdk-resources/services/s3/presigned_post.rb +0 -647
- data/lib/aws-sdk-resources/services/sns.rb +0 -7
- data/lib/aws-sdk-resources/services/sns/message_verifier.rb +0 -157
- data/lib/aws-sdk-resources/services/sqs.rb +0 -7
- data/lib/aws-sdk-resources/services/sqs/queue_poller.rb +0 -521
- data/lib/aws-sdk-resources/source.rb +0 -39
@@ -1,29 +0,0 @@
|
|
1
|
-
module Aws
|
2
|
-
module S3
|
3
|
-
module Encryption
|
4
|
-
|
5
|
-
# This module defines the interface required for a {Client#key_provider}.
|
6
|
-
# A key provider is any object that:
|
7
|
-
#
|
8
|
-
# * Responds to {#encryption_materials} with an {Materials} object.
|
9
|
-
#
|
10
|
-
# * Responds to {#key_for}, receiving a JSON document String,
|
11
|
-
# returning an encryption key. The returned encryption key
|
12
|
-
# must be one of:
|
13
|
-
#
|
14
|
-
# * `OpenSSL::PKey::RSA` - for asymmetric encryption
|
15
|
-
# * `String` - 32, 24, or 16 bytes long, for symmetric encryption
|
16
|
-
#
|
17
|
-
module KeyProvider
|
18
|
-
|
19
|
-
# @return [Materials]
|
20
|
-
def encryption_materials; end
|
21
|
-
|
22
|
-
# @param [String<JSON>] materials_description
|
23
|
-
# @return [OpenSSL::PKey::RSA, String] encryption_key
|
24
|
-
def key_for(materials_description); end
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
require 'base64'
|
2
|
-
|
3
|
-
module Aws
|
4
|
-
module S3
|
5
|
-
module Encryption
|
6
|
-
# @api private
|
7
|
-
class KmsCipherProvider
|
8
|
-
|
9
|
-
def initialize(options = {})
|
10
|
-
@kms_key_id = options[:kms_key_id]
|
11
|
-
@kms_client = options[:kms_client]
|
12
|
-
end
|
13
|
-
|
14
|
-
# @return [Array<Hash,Cipher>] Creates an returns a new encryption
|
15
|
-
# envelope and encryption cipher.
|
16
|
-
def encryption_cipher
|
17
|
-
encryption_context = { "kms_cmk_id" => @kms_key_id }
|
18
|
-
key_data = @kms_client.generate_data_key(
|
19
|
-
key_id: @kms_key_id,
|
20
|
-
encryption_context: encryption_context,
|
21
|
-
key_spec: 'AES_256',
|
22
|
-
)
|
23
|
-
cipher = Utils.aes_encryption_cipher(:CBC)
|
24
|
-
cipher.key = key_data.plaintext
|
25
|
-
envelope = {
|
26
|
-
'x-amz-key-v2' => encode64(key_data.ciphertext_blob),
|
27
|
-
'x-amz-iv' => encode64(cipher.iv = cipher.random_iv),
|
28
|
-
'x-amz-cek-alg' => 'AES/CBC/PKCS5Padding',
|
29
|
-
'x-amz-wrap-alg' => 'kms',
|
30
|
-
'x-amz-matdesc' => Json.dump(encryption_context)
|
31
|
-
}
|
32
|
-
[envelope, cipher]
|
33
|
-
end
|
34
|
-
|
35
|
-
# @return [Cipher] Given an encryption envelope, returns a
|
36
|
-
# decryption cipher.
|
37
|
-
def decryption_cipher(envelope)
|
38
|
-
encryption_context = Json.load(envelope['x-amz-matdesc'])
|
39
|
-
key = @kms_client.decrypt(
|
40
|
-
ciphertext_blob: decode64(envelope['x-amz-key-v2']),
|
41
|
-
encryption_context: encryption_context,
|
42
|
-
).plaintext
|
43
|
-
iv = decode64(envelope['x-amz-iv'])
|
44
|
-
block_mode =
|
45
|
-
case envelope['x-amz-cek-alg']
|
46
|
-
when 'AES/CBC/PKCS5Padding'
|
47
|
-
:CBC
|
48
|
-
when 'AES/GCM/NoPadding'
|
49
|
-
:GCM
|
50
|
-
else
|
51
|
-
type = envelope['x-amz-cek-alg'].inspect
|
52
|
-
msg = "unsupported content encrypting key (cek) format: #{type}"
|
53
|
-
raise Errors::DecryptionError, msg
|
54
|
-
end
|
55
|
-
Utils.aes_decryption_cipher(block_mode, key, iv)
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def encode64(str)
|
61
|
-
Base64.encode64(str).split("\n") * ""
|
62
|
-
end
|
63
|
-
|
64
|
-
def decode64(str)
|
65
|
-
Base64.decode64(str)
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'base64'
|
2
|
-
|
3
|
-
module Aws
|
4
|
-
module S3
|
5
|
-
module Encryption
|
6
|
-
class Materials
|
7
|
-
|
8
|
-
# @option options [required, OpenSSL::PKey::RSA, String] :key
|
9
|
-
# The master key to use for encrypting/decrypting all objects.
|
10
|
-
#
|
11
|
-
# @option options [String<JSON>] :description ('{}')
|
12
|
-
# The encryption materials description. This is must be
|
13
|
-
# a JSON document string.
|
14
|
-
#
|
15
|
-
def initialize(options = {})
|
16
|
-
@key = validate_key(options[:key])
|
17
|
-
@description = validate_desc(options[:description])
|
18
|
-
end
|
19
|
-
|
20
|
-
# @return [OpenSSL::PKey::RSA, String]
|
21
|
-
attr_reader :key
|
22
|
-
|
23
|
-
# @return [String<JSON>]
|
24
|
-
attr_reader :description
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def validate_key(key)
|
29
|
-
case key
|
30
|
-
when OpenSSL::PKey::RSA then key
|
31
|
-
when String
|
32
|
-
if [32, 24, 16].include?(key.bytesize)
|
33
|
-
key
|
34
|
-
else
|
35
|
-
msg = "invalid key, symmetric key required to be 16, 24, or "
|
36
|
-
msg << "32 bytes in length, saw length 31"
|
37
|
-
raise ArgumentError, msg
|
38
|
-
end
|
39
|
-
else
|
40
|
-
msg = "invalid encryption key, expected an OpenSSL::PKey::RSA key "
|
41
|
-
msg << "(for asymmetric encryption) or a String (for symmetric "
|
42
|
-
msg << "encryption)."
|
43
|
-
raise ArgumentError, msg
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def validate_desc(description)
|
48
|
-
Json.load(description)
|
49
|
-
description
|
50
|
-
rescue Json::ParseError
|
51
|
-
msg = "expected description to be a valid JSON document string"
|
52
|
-
raise ArgumentError, msg
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
|
3
|
-
module Aws
|
4
|
-
module S3
|
5
|
-
module Encryption
|
6
|
-
# @api private
|
7
|
-
module Utils
|
8
|
-
|
9
|
-
UNSAFE_MSG = "unsafe encryption, data is longer than key length"
|
10
|
-
|
11
|
-
class << self
|
12
|
-
|
13
|
-
def encrypt(key, data)
|
14
|
-
case key
|
15
|
-
when OpenSSL::PKey::RSA # asymmetric encryption
|
16
|
-
warn(UNSAFE_MSG) if key.public_key.n.num_bits < cipher_size(data)
|
17
|
-
key.public_encrypt(data)
|
18
|
-
when String # symmetric encryption
|
19
|
-
warn(UNSAFE_MSG) if cipher_size(key) < cipher_size(data)
|
20
|
-
cipher = aes_encryption_cipher(:ECB, key)
|
21
|
-
cipher.update(data) + cipher.final
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def decrypt(key, data)
|
26
|
-
begin
|
27
|
-
case key
|
28
|
-
when OpenSSL::PKey::RSA # asymmetric decryption
|
29
|
-
key.private_decrypt(data)
|
30
|
-
when String # symmetric Decryption
|
31
|
-
cipher = aes_cipher(:decrypt, :ECB, key, nil)
|
32
|
-
cipher.update(data) + cipher.final
|
33
|
-
end
|
34
|
-
rescue OpenSSL::Cipher::CipherError
|
35
|
-
msg = 'decryption failed, possible incorrect key'
|
36
|
-
raise Errors::DecryptionError, msg
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# @param [String] block_mode "CBC" or "ECB"
|
41
|
-
# @param [OpenSSL::PKey::RSA, String, nil] key
|
42
|
-
# @param [String, nil] iv The initialization vector
|
43
|
-
def aes_encryption_cipher(block_mode, key = nil, iv = nil)
|
44
|
-
aes_cipher(:encrypt, block_mode, key, iv)
|
45
|
-
end
|
46
|
-
|
47
|
-
# @param [String] block_mode "CBC" or "ECB"
|
48
|
-
# @param [OpenSSL::PKey::RSA, String, nil] key
|
49
|
-
# @param [String, nil] iv The initialization vector
|
50
|
-
def aes_decryption_cipher(block_mode, key = nil, iv = nil)
|
51
|
-
aes_cipher(:decrypt, block_mode, key, iv)
|
52
|
-
end
|
53
|
-
|
54
|
-
# @param [String] mode "encrypt" or "decrypt"
|
55
|
-
# @param [String] block_mode "CBC" or "ECB"
|
56
|
-
# @param [OpenSSL::PKey::RSA, String, nil] key
|
57
|
-
# @param [String, nil] iv The initialization vector
|
58
|
-
def aes_cipher(mode, block_mode, key, iv)
|
59
|
-
cipher = key ?
|
60
|
-
OpenSSL::Cipher.new("aes-#{cipher_size(key)}-#{block_mode.downcase}") :
|
61
|
-
OpenSSL::Cipher.new("aes-256-#{block_mode.downcase}")
|
62
|
-
cipher.send(mode) # encrypt or decrypt
|
63
|
-
cipher.key = key if key
|
64
|
-
cipher.iv = iv if iv
|
65
|
-
cipher
|
66
|
-
end
|
67
|
-
|
68
|
-
# @param [String] key
|
69
|
-
# @return [Integer]
|
70
|
-
# @raise ArgumentError
|
71
|
-
def cipher_size(key)
|
72
|
-
key.bytesize * 8
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
module Aws
|
2
|
-
module S3
|
3
|
-
|
4
|
-
# A utility class that provides an IO-like interface to a portion of
|
5
|
-
# a file on disk.
|
6
|
-
# @api private
|
7
|
-
class FilePart
|
8
|
-
|
9
|
-
# @option options [required,String,Pathname,File,Tempfile] :source
|
10
|
-
# @option options [required,Integer] :offset The file part will read
|
11
|
-
# starting at this byte offset.
|
12
|
-
# @option options [required,Integer] :size The maximum number of bytes to
|
13
|
-
# read from the `:offset`.
|
14
|
-
def initialize(options = {})
|
15
|
-
@source = options[:source]
|
16
|
-
@first_byte = options[:offset]
|
17
|
-
@last_byte = @first_byte + options[:size]
|
18
|
-
@size = options[:size]
|
19
|
-
@file = nil
|
20
|
-
end
|
21
|
-
|
22
|
-
# @return [String,Pathname,File,Tempfile]
|
23
|
-
attr_reader :source
|
24
|
-
|
25
|
-
# @return [Integer]
|
26
|
-
attr_reader :first_byte
|
27
|
-
|
28
|
-
# @return [Integer]
|
29
|
-
attr_reader :last_byte
|
30
|
-
|
31
|
-
# @return [Integer]
|
32
|
-
attr_reader :size
|
33
|
-
|
34
|
-
def read(bytes = nil, output_buffer = nil)
|
35
|
-
open_file unless @file
|
36
|
-
read_from_file(bytes, output_buffer)
|
37
|
-
end
|
38
|
-
|
39
|
-
def rewind
|
40
|
-
if @file
|
41
|
-
@file.seek(@first_byte)
|
42
|
-
@position = @first_byte
|
43
|
-
end
|
44
|
-
0
|
45
|
-
end
|
46
|
-
|
47
|
-
def close
|
48
|
-
@file.close if @file
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def open_file
|
54
|
-
@file = File.open(@source, 'rb')
|
55
|
-
rewind
|
56
|
-
end
|
57
|
-
|
58
|
-
def read_from_file(bytes, output_buffer)
|
59
|
-
if bytes
|
60
|
-
data = @file.read([remaining_bytes, bytes].min)
|
61
|
-
data = nil if data == ''
|
62
|
-
else
|
63
|
-
data = @file.read(remaining_bytes)
|
64
|
-
end
|
65
|
-
@position += data ? data.bytesize : 0
|
66
|
-
output_buffer ? output_buffer.replace(data || '') : data
|
67
|
-
end
|
68
|
-
|
69
|
-
def remaining_bytes
|
70
|
-
@last_byte - @position
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
module Aws
|
4
|
-
module S3
|
5
|
-
# @api private
|
6
|
-
class FileUploader
|
7
|
-
|
8
|
-
FIFTEEN_MEGABYTES = 15 * 1024 * 1024
|
9
|
-
|
10
|
-
# @option options [Client] :client
|
11
|
-
# @option options [Integer] :multipart_threshold Files greater than
|
12
|
-
# `:multipart_threshold` bytes are uploaded using S3 multipart APIs.
|
13
|
-
def initialize(options = {})
|
14
|
-
@options = options
|
15
|
-
@client = options[:client] || Client.new
|
16
|
-
@multipart_threshold = options[:multipart_threshold] || FIFTEEN_MEGABYTES
|
17
|
-
end
|
18
|
-
|
19
|
-
# @return [Client]
|
20
|
-
attr_reader :client
|
21
|
-
|
22
|
-
# @return [Integer] Files larger than this in bytes are uploaded
|
23
|
-
# using a {MultipartFileUploader}.
|
24
|
-
attr_reader :multipart_threshold
|
25
|
-
|
26
|
-
# @param [String,Pathname,File,Tempfile] source
|
27
|
-
# @option options [required,String] :bucket
|
28
|
-
# @option options [required,String] :key
|
29
|
-
# @return [void]
|
30
|
-
def upload(source, options = {})
|
31
|
-
if File.size(source) >= multipart_threshold
|
32
|
-
MultipartFileUploader.new(@options).upload(source, options)
|
33
|
-
else
|
34
|
-
put_object(source, options)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def put_object(source, options)
|
41
|
-
open_file(source) do |file|
|
42
|
-
@client.put_object(options.merge(body: file))
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def open_file(source)
|
47
|
-
if String === source || Pathname === source
|
48
|
-
file = File.open(source, 'rb')
|
49
|
-
yield(file)
|
50
|
-
file.close
|
51
|
-
else
|
52
|
-
yield(source)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
@@ -1,187 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
require 'thread'
|
3
|
-
require 'set'
|
4
|
-
|
5
|
-
module Aws
|
6
|
-
module S3
|
7
|
-
# @api private
|
8
|
-
class MultipartFileUploader
|
9
|
-
|
10
|
-
MIN_PART_SIZE = 5 * 1024 * 1024 # 5MB
|
11
|
-
|
12
|
-
FILE_TOO_SMALL = "unable to multipart upload files smaller than 5MB"
|
13
|
-
|
14
|
-
MAX_PARTS = 10_000
|
15
|
-
|
16
|
-
THREAD_COUNT = 10
|
17
|
-
|
18
|
-
# @api private
|
19
|
-
CREATE_OPTIONS =
|
20
|
-
Set.new(Client.api.operation(:create_multipart_upload).input.shape.member_names)
|
21
|
-
|
22
|
-
# @api private
|
23
|
-
UPLOAD_PART_OPTIONS =
|
24
|
-
Set.new(Client.api.operation(:upload_part).input.shape.member_names)
|
25
|
-
|
26
|
-
# @option options [Client] :client
|
27
|
-
def initialize(options = {})
|
28
|
-
@client = options[:client] || Client.new
|
29
|
-
@thread_count = options[:thread_count] || THREAD_COUNT
|
30
|
-
end
|
31
|
-
|
32
|
-
# @return [Client]
|
33
|
-
attr_reader :client
|
34
|
-
|
35
|
-
# @param [String,Pathname,File,Tempfile] source
|
36
|
-
# @option options [required,String] :bucket
|
37
|
-
# @option options [required,String] :key
|
38
|
-
# @return [void]
|
39
|
-
def upload(source, options = {})
|
40
|
-
if File.size(source) < MIN_PART_SIZE
|
41
|
-
raise ArgumentError, FILE_TOO_SMALL
|
42
|
-
else
|
43
|
-
upload_id = initiate_upload(options)
|
44
|
-
parts = upload_parts(upload_id, source, options)
|
45
|
-
complete_upload(upload_id, parts, options)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def initiate_upload(options)
|
52
|
-
@client.create_multipart_upload(create_opts(options)).upload_id
|
53
|
-
end
|
54
|
-
|
55
|
-
def complete_upload(upload_id, parts, options)
|
56
|
-
@client.complete_multipart_upload(
|
57
|
-
bucket: options[:bucket],
|
58
|
-
key: options[:key],
|
59
|
-
upload_id: upload_id,
|
60
|
-
multipart_upload: { parts: parts })
|
61
|
-
end
|
62
|
-
|
63
|
-
def upload_parts(upload_id, source, options)
|
64
|
-
pending = PartList.new(compute_parts(upload_id, source, options))
|
65
|
-
completed = PartList.new
|
66
|
-
errors = upload_in_threads(pending, completed)
|
67
|
-
if errors.empty?
|
68
|
-
completed.to_a.sort_by { |part| part[:part_number] }
|
69
|
-
else
|
70
|
-
abort_upload(upload_id, options, errors)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def abort_upload(upload_id, options, errors)
|
75
|
-
@client.abort_multipart_upload(
|
76
|
-
bucket: options[:bucket],
|
77
|
-
key: options[:key],
|
78
|
-
upload_id: upload_id
|
79
|
-
)
|
80
|
-
msg = "multipart upload failed: #{errors.map(&:message).join("; ")}"
|
81
|
-
raise MultipartUploadError.new(msg, errors)
|
82
|
-
rescue MultipartUploadError => error
|
83
|
-
raise error
|
84
|
-
rescue => error
|
85
|
-
msg = "failed to abort multipart upload: #{error.message}"
|
86
|
-
raise MultipartUploadError.new(msg, errors + [error])
|
87
|
-
end
|
88
|
-
|
89
|
-
def compute_parts(upload_id, source, options)
|
90
|
-
size = File.size(source)
|
91
|
-
default_part_size = compute_default_part_size(size)
|
92
|
-
offset = 0
|
93
|
-
part_number = 1
|
94
|
-
parts = []
|
95
|
-
while offset < size
|
96
|
-
parts << upload_part_opts(options).merge({
|
97
|
-
upload_id: upload_id,
|
98
|
-
part_number: part_number,
|
99
|
-
body: FilePart.new(
|
100
|
-
source: source,
|
101
|
-
offset: offset,
|
102
|
-
size: part_size(size, default_part_size, offset)
|
103
|
-
)
|
104
|
-
})
|
105
|
-
part_number += 1
|
106
|
-
offset += default_part_size
|
107
|
-
end
|
108
|
-
parts
|
109
|
-
end
|
110
|
-
|
111
|
-
def create_opts(options)
|
112
|
-
CREATE_OPTIONS.inject({}) do |hash, key|
|
113
|
-
hash[key] = options[key] if options.key?(key)
|
114
|
-
hash
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def upload_part_opts(options)
|
119
|
-
UPLOAD_PART_OPTIONS.inject({}) do |hash, key|
|
120
|
-
hash[key] = options[key] if options.key?(key)
|
121
|
-
hash
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def upload_in_threads(pending, completed)
|
126
|
-
threads = []
|
127
|
-
@thread_count.times do
|
128
|
-
thread = Thread.new do
|
129
|
-
begin
|
130
|
-
while part = pending.shift
|
131
|
-
resp = @client.upload_part(part)
|
132
|
-
part[:body].close
|
133
|
-
completed.push(etag: resp.etag, part_number: part[:part_number])
|
134
|
-
end
|
135
|
-
nil
|
136
|
-
rescue => error
|
137
|
-
# keep other threads from uploading other parts
|
138
|
-
pending.clear!
|
139
|
-
error
|
140
|
-
end
|
141
|
-
end
|
142
|
-
thread.abort_on_exception = true
|
143
|
-
threads << thread
|
144
|
-
end
|
145
|
-
threads.map(&:value).compact
|
146
|
-
end
|
147
|
-
|
148
|
-
def compute_default_part_size(source_size)
|
149
|
-
[(source_size.to_f / MAX_PARTS).ceil, MIN_PART_SIZE].max.to_i
|
150
|
-
end
|
151
|
-
|
152
|
-
def part_size(total_size, part_size, offset)
|
153
|
-
if offset + part_size > total_size
|
154
|
-
total_size - offset
|
155
|
-
else
|
156
|
-
part_size
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
# @api private
|
161
|
-
class PartList
|
162
|
-
|
163
|
-
def initialize(parts = [])
|
164
|
-
@parts = parts
|
165
|
-
@mutex = Mutex.new
|
166
|
-
end
|
167
|
-
|
168
|
-
def push(part)
|
169
|
-
@mutex.synchronize { @parts.push(part) }
|
170
|
-
end
|
171
|
-
|
172
|
-
def shift
|
173
|
-
@mutex.synchronize { @parts.shift }
|
174
|
-
end
|
175
|
-
|
176
|
-
def clear!
|
177
|
-
@mutex.synchronize { @parts.clear }
|
178
|
-
end
|
179
|
-
|
180
|
-
def to_a
|
181
|
-
@mutex.synchronize { @parts.dup }
|
182
|
-
end
|
183
|
-
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|