aws-sdk-resources 2.11.632 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/lib/aws-sdk-resources.rb +1 -91
  3. metadata +14 -85
  4. data/lib/aws-sdk-resources/batch.rb +0 -143
  5. data/lib/aws-sdk-resources/builder.rb +0 -85
  6. data/lib/aws-sdk-resources/builder_sources.rb +0 -105
  7. data/lib/aws-sdk-resources/collection.rb +0 -107
  8. data/lib/aws-sdk-resources/definition.rb +0 -331
  9. data/lib/aws-sdk-resources/documenter.rb +0 -70
  10. data/lib/aws-sdk-resources/documenter/base_operation_documenter.rb +0 -279
  11. data/lib/aws-sdk-resources/documenter/data_operation_documenter.rb +0 -25
  12. data/lib/aws-sdk-resources/documenter/has_many_operation_documenter.rb +0 -69
  13. data/lib/aws-sdk-resources/documenter/has_operation_documenter.rb +0 -66
  14. data/lib/aws-sdk-resources/documenter/operation_documenter.rb +0 -20
  15. data/lib/aws-sdk-resources/documenter/resource_operation_documenter.rb +0 -53
  16. data/lib/aws-sdk-resources/documenter/waiter_operation_documenter.rb +0 -77
  17. data/lib/aws-sdk-resources/errors.rb +0 -15
  18. data/lib/aws-sdk-resources/operation_methods.rb +0 -83
  19. data/lib/aws-sdk-resources/operations.rb +0 -280
  20. data/lib/aws-sdk-resources/options.rb +0 -17
  21. data/lib/aws-sdk-resources/request.rb +0 -39
  22. data/lib/aws-sdk-resources/request_params.rb +0 -140
  23. data/lib/aws-sdk-resources/resource.rb +0 -243
  24. data/lib/aws-sdk-resources/services/ec2.rb +0 -21
  25. data/lib/aws-sdk-resources/services/ec2/instance.rb +0 -29
  26. data/lib/aws-sdk-resources/services/iam.rb +0 -19
  27. data/lib/aws-sdk-resources/services/s3.rb +0 -21
  28. data/lib/aws-sdk-resources/services/s3/bucket.rb +0 -131
  29. data/lib/aws-sdk-resources/services/s3/encryption.rb +0 -24
  30. data/lib/aws-sdk-resources/services/s3/encryption/client.rb +0 -386
  31. data/lib/aws-sdk-resources/services/s3/encryption/decrypt_handler.rb +0 -225
  32. data/lib/aws-sdk-resources/services/s3/encryption/default_cipher_provider.rb +0 -101
  33. data/lib/aws-sdk-resources/services/s3/encryption/default_key_provider.rb +0 -40
  34. data/lib/aws-sdk-resources/services/s3/encryption/encrypt_handler.rb +0 -61
  35. data/lib/aws-sdk-resources/services/s3/encryption/errors.rb +0 -15
  36. data/lib/aws-sdk-resources/services/s3/encryption/io_auth_decrypter.rb +0 -58
  37. data/lib/aws-sdk-resources/services/s3/encryption/io_decrypter.rb +0 -37
  38. data/lib/aws-sdk-resources/services/s3/encryption/io_encrypter.rb +0 -71
  39. data/lib/aws-sdk-resources/services/s3/encryption/key_provider.rb +0 -31
  40. data/lib/aws-sdk-resources/services/s3/encryption/kms_cipher_provider.rb +0 -104
  41. data/lib/aws-sdk-resources/services/s3/encryption/materials.rb +0 -60
  42. data/lib/aws-sdk-resources/services/s3/encryption/utils.rb +0 -104
  43. data/lib/aws-sdk-resources/services/s3/encryptionV2/client.rb +0 -561
  44. data/lib/aws-sdk-resources/services/s3/encryptionV2/decrypt_handler.rb +0 -214
  45. data/lib/aws-sdk-resources/services/s3/encryptionV2/default_cipher_provider.rb +0 -170
  46. data/lib/aws-sdk-resources/services/s3/encryptionV2/default_key_provider.rb +0 -40
  47. data/lib/aws-sdk-resources/services/s3/encryptionV2/encrypt_handler.rb +0 -69
  48. data/lib/aws-sdk-resources/services/s3/encryptionV2/errors.rb +0 -37
  49. data/lib/aws-sdk-resources/services/s3/encryptionV2/io_auth_decrypter.rb +0 -58
  50. data/lib/aws-sdk-resources/services/s3/encryptionV2/io_decrypter.rb +0 -37
  51. data/lib/aws-sdk-resources/services/s3/encryptionV2/io_encrypter.rb +0 -73
  52. data/lib/aws-sdk-resources/services/s3/encryptionV2/key_provider.rb +0 -31
  53. data/lib/aws-sdk-resources/services/s3/encryptionV2/kms_cipher_provider.rb +0 -169
  54. data/lib/aws-sdk-resources/services/s3/encryptionV2/materials.rb +0 -60
  55. data/lib/aws-sdk-resources/services/s3/encryptionV2/utils.rb +0 -103
  56. data/lib/aws-sdk-resources/services/s3/encryption_v2.rb +0 -24
  57. data/lib/aws-sdk-resources/services/s3/file_downloader.rb +0 -169
  58. data/lib/aws-sdk-resources/services/s3/file_part.rb +0 -75
  59. data/lib/aws-sdk-resources/services/s3/file_uploader.rb +0 -58
  60. data/lib/aws-sdk-resources/services/s3/multipart_file_uploader.rb +0 -187
  61. data/lib/aws-sdk-resources/services/s3/multipart_upload.rb +0 -42
  62. data/lib/aws-sdk-resources/services/s3/multipart_upload_error.rb +0 -16
  63. data/lib/aws-sdk-resources/services/s3/object.rb +0 -290
  64. data/lib/aws-sdk-resources/services/s3/object_copier.rb +0 -99
  65. data/lib/aws-sdk-resources/services/s3/object_multipart_copier.rb +0 -180
  66. data/lib/aws-sdk-resources/services/s3/object_summary.rb +0 -73
  67. data/lib/aws-sdk-resources/services/s3/presigned_post.rb +0 -651
  68. data/lib/aws-sdk-resources/services/sns.rb +0 -7
  69. data/lib/aws-sdk-resources/services/sns/message_verifier.rb +0 -171
  70. data/lib/aws-sdk-resources/services/sqs.rb +0 -7
  71. data/lib/aws-sdk-resources/services/sqs/queue_poller.rb +0 -521
  72. data/lib/aws-sdk-resources/source.rb +0 -39
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'openssl'
4
-
5
- module Aws
6
- module S3
7
- module EncryptionV2
8
- # @api private
9
- module Utils
10
-
11
- class << self
12
-
13
- def encrypt_aes_gcm(key, data, auth_data)
14
- cipher = aes_encryption_cipher(:GCM, key)
15
- cipher.iv = (iv = cipher.random_iv)
16
- cipher.auth_data = auth_data
17
-
18
- iv + cipher.update(data) + cipher.final + cipher.auth_tag
19
- end
20
-
21
- def encrypt_rsa(key, data, auth_data)
22
- # Plaintext must be KeyLengthInBytes (1 Byte) + DataKey + AuthData
23
- buf = [data.bytesize] + data.unpack('C*') + auth_data.unpack('C*')
24
- key.public_encrypt(buf.pack('C*'), OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
25
- end
26
-
27
- def decrypt(key, data)
28
- begin
29
- case key
30
- when OpenSSL::PKey::RSA # asymmetric decryption
31
- key.private_decrypt(data)
32
- when String # symmetric Decryption
33
- cipher = aes_cipher(:decrypt, :ECB, key, nil)
34
- cipher.update(data) + cipher.final
35
- end
36
- rescue OpenSSL::Cipher::CipherError
37
- msg = 'decryption failed, possible incorrect key'
38
- raise Errors::DecryptionError, msg
39
- end
40
- end
41
-
42
- def decrypt_aes_gcm(key, data, auth_data)
43
- # data is iv (12B) + key + tag (16B)
44
- buf = data.unpack('C*')
45
- iv = buf[0,12].pack('C*') # iv will always be 12 bytes
46
- tag = buf[-16, 16].pack('C*') # tag is 16 bytes
47
- enc_key = buf[12, buf.size - (12+16)].pack('C*')
48
- cipher = aes_cipher(:decrypt, :GCM, key, iv)
49
- cipher.auth_tag = tag
50
- cipher.auth_data = auth_data
51
- cipher.update(enc_key) + cipher.final
52
- end
53
-
54
- # returns the decrypted data + auth_data
55
- def decrypt_rsa(key, enc_data)
56
- # Plaintext must be KeyLengthInBytes (1 Byte) + DataKey + AuthData
57
- buf = key.private_decrypt(enc_data, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING).unpack('C*')
58
- key_length = buf[0]
59
- data = buf[1, key_length].pack('C*')
60
- auth_data = buf[key_length+1, buf.length - key_length].pack('C*')
61
- [data, auth_data]
62
- end
63
-
64
- # @param [String] block_mode "CBC" or "ECB"
65
- # @param [OpenSSL::PKey::RSA, String, nil] key
66
- # @param [String, nil] iv The initialization vector
67
- def aes_encryption_cipher(block_mode, key = nil, iv = nil)
68
- aes_cipher(:encrypt, block_mode, key, iv)
69
- end
70
-
71
- # @param [String] block_mode "CBC" or "ECB"
72
- # @param [OpenSSL::PKey::RSA, String, nil] key
73
- # @param [String, nil] iv The initialization vector
74
- def aes_decryption_cipher(block_mode, key = nil, iv = nil)
75
- aes_cipher(:decrypt, block_mode, key, iv)
76
- end
77
-
78
- # @param [String] mode "encrypt" or "decrypt"
79
- # @param [String] block_mode "CBC" or "ECB"
80
- # @param [OpenSSL::PKey::RSA, String, nil] key
81
- # @param [String, nil] iv The initialization vector
82
- def aes_cipher(mode, block_mode, key, iv)
83
- cipher = key ?
84
- OpenSSL::Cipher.new("aes-#{cipher_size(key)}-#{block_mode.downcase}") :
85
- OpenSSL::Cipher.new("aes-256-#{block_mode.downcase}")
86
- cipher.send(mode) # encrypt or decrypt
87
- cipher.key = key if key
88
- cipher.iv = iv if iv
89
- cipher
90
- end
91
-
92
- # @param [String] key
93
- # @return [Integer]
94
- # @raise ArgumentError
95
- def cipher_size(key)
96
- key.bytesize * 8
97
- end
98
-
99
- end
100
- end
101
- end
102
- end
103
- end
@@ -1,24 +0,0 @@
1
- module Aws
2
- module S3
3
- module EncryptionV2
4
-
5
- AES_GCM_TAG_LEN_BYTES = 16
6
- EC_USER_AGENT = 'S3CryptoV2'
7
-
8
- autoload :Client, 'aws-sdk-resources/services/s3/encryptionV2/client'
9
- autoload :DecryptHandler, 'aws-sdk-resources/services/s3/encryptionV2/decrypt_handler'
10
- autoload :DefaultCipherProvider, 'aws-sdk-resources/services/s3/encryptionV2/default_cipher_provider'
11
- autoload :DefaultKeyProvider, 'aws-sdk-resources/services/s3/encryptionV2/default_key_provider'
12
- autoload :EncryptHandler, 'aws-sdk-resources/services/s3/encryptionV2/encrypt_handler'
13
- autoload :Errors, 'aws-sdk-resources/services/s3/encryptionV2/errors'
14
- autoload :IOEncrypter, 'aws-sdk-resources/services/s3/encryptionV2/io_encrypter'
15
- autoload :IOAuthDecrypter, 'aws-sdk-resources/services/s3/encryptionV2/io_auth_decrypter'
16
- autoload :IODecrypter, 'aws-sdk-resources/services/s3/encryptionV2/io_decrypter'
17
- autoload :KeyProvider, 'aws-sdk-resources/services/s3/encryptionV2/key_provider'
18
- autoload :KmsCipherProvider, 'aws-sdk-resources/services/s3/encryptionV2/kms_cipher_provider'
19
- autoload :Materials, 'aws-sdk-resources/services/s3/encryptionV2/materials'
20
- autoload :Utils, 'aws-sdk-resources/services/s3/encryptionV2/utils'
21
-
22
- end
23
- end
24
- end
@@ -1,169 +0,0 @@
1
- require 'pathname'
2
- require 'thread'
3
- require 'set'
4
- require 'tmpdir'
5
-
6
- module Aws
7
- module S3
8
- # @api private
9
- class FileDownloader
10
-
11
- MIN_CHUNK_SIZE = 5 * 1024 * 1024
12
- MAX_PARTS = 10_000
13
- THREAD_COUNT = 10
14
-
15
- def initialize(options = {})
16
- @client = options[:client] || Client.new
17
- end
18
-
19
- # @return [Client]
20
- attr_reader :client
21
-
22
- def download(destination, options = {})
23
- @path = destination
24
- @mode = options[:mode] || "auto"
25
- @thread_count = options[:thread_count] || THREAD_COUNT
26
- @chunk_size = options[:chunk_size]
27
- @bucket = options[:bucket]
28
- @key = options[:key]
29
-
30
- case @mode
31
- when "auto" then multipart_download
32
- when "single_request" then single_request
33
- when "get_range"
34
- if @chunk_size
35
- resp = @client.head_object(bucket: @bucket, key: @key)
36
- multithreaded_get_by_ranges(construct_chunks(resp.content_length))
37
- else
38
- msg = "In :get_range mode, :chunk_size must be provided"
39
- raise ArgumentError, msg
40
- end
41
- else
42
- msg = "Invalid mode #{@mode} provided, "\
43
- "mode should be :single_request, :get_range or :auto"
44
- raise ArgumentError, msg
45
- end
46
- end
47
-
48
- private
49
-
50
- def multipart_download
51
- resp = @client.head_object(bucket: @bucket, key: @key, part_number: 1)
52
- count = resp.parts_count
53
- if count.nil? || count <= 1
54
- resp.content_length < MIN_CHUNK_SIZE ?
55
- single_request :
56
- multithreaded_get_by_ranges(construct_chunks(resp.content_length))
57
- else
58
- # partNumber is an option
59
- resp = @client.head_object(bucket: @bucket, key: @key)
60
- resp.content_length < MIN_CHUNK_SIZE ?
61
- single_request :
62
- compute_mode(resp.content_length, count)
63
- end
64
- end
65
-
66
- def compute_mode(file_size, count)
67
- chunk_size = compute_chunk(file_size)
68
- part_size = (file_size.to_f / count.to_f).ceil
69
- if chunk_size < part_size
70
- multithreaded_get_by_ranges(construct_chunks(file_size))
71
- else
72
- multithreaded_get_by_parts(count)
73
- end
74
- end
75
-
76
- def construct_chunks(file_size)
77
- offset = 0
78
- default_chunk_size = compute_chunk(file_size)
79
- chunks = []
80
- while offset <= file_size
81
- progress = offset + default_chunk_size
82
- chunks << "bytes=#{offset}-#{progress < file_size ? progress : file_size}"
83
- offset = progress + 1
84
- end
85
- chunks
86
- end
87
-
88
- def compute_chunk(file_size)
89
- if @chunk_size && @chunk_size > file_size
90
- raise ArgumentError, ":chunk_size shouldn't exceed total file size."
91
- else
92
- default_chunk_size = @chunk_size || [(file_size.to_f / MAX_PARTS).ceil, MIN_CHUNK_SIZE].max.to_i
93
- end
94
- end
95
-
96
- def sort_files(files)
97
- # sort file by start range count or part number
98
- files.sort do |a, b|
99
- a[/([^\=]+)$/].split('-')[0].to_i <=> b[/([^\=]+)$/].split('-')[0].to_i
100
- end
101
- end
102
-
103
- def concatenate_parts(fileparts)
104
- File.open(@path, 'wb')do |output_path|
105
- sort_files(fileparts).each {|part| IO.copy_stream(part, output_path)}
106
- end
107
- end
108
-
109
- def file_batches(chunks, dir, mode)
110
- batches = []
111
- chunks = (1..chunks) if mode.eql? 'part_number'
112
- chunks.each_slice(@thread_count) do |slice|
113
- batches << map_files(slice, dir, mode)
114
- end
115
- batches
116
- end
117
-
118
- def map_files(slice, dir, mode)
119
- case mode
120
- when 'range'
121
- slice.inject({}) {|h, chunk| h[chunk] = File.join(dir, chunk); h}
122
- when 'part_number'
123
- slice.inject({}) {|h, part| h[part] = File.join(dir, "part_number=#{part}"); h}
124
- end
125
- end
126
-
127
- def multithreaded_get_by_ranges(chunks)
128
- thread_batches(chunks, 'range')
129
- end
130
-
131
- def multithreaded_get_by_parts(parts)
132
- thread_batches(parts, 'part_number')
133
- end
134
-
135
- def thread_batches(chunks, param)
136
- # create a tmp dir under destination dir for batches
137
- dir = Dir.mktmpdir(nil, File.dirname(@path))
138
- batches = file_batches(chunks, dir, param)
139
- parts = batches.flat_map(&:values)
140
- begin
141
- batches.each do |batch|
142
- threads = []
143
- batch.each do |chunk, file|
144
- threads << Thread.new do
145
- resp = @client.get_object(
146
- :bucket => @bucket,
147
- :key => @key,
148
- param.to_sym => chunk,
149
- :response_target => file
150
- )
151
- end
152
- end
153
- threads.each(&:join)
154
- end
155
- concatenate_parts(parts)
156
- ensure
157
- # clean up tmp dir
158
- FileUtils.remove_entry(dir)
159
- end
160
- end
161
-
162
- def single_request
163
- @client.get_object(
164
- bucket: @bucket, key: @key, response_target: @path
165
- )
166
- end
167
- end
168
- end
169
- 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