-
Notifications
You must be signed in to change notification settings - Fork 885
feat(storage): Restart & delete resumable upload #21896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 20 commits
0b91b6b
63b3af0
308ef36
8768271
cb561a4
1d26f0d
fd8b6fd
02be397
5daa50a
fa2b1ae
e891f3d
0cc8b2b
de23583
872802b
b92dd7f
6fbf86a
fa884a8
8d956f2
a1df390
ebb5d6c
6fc5733
422dc99
238a1e2
89e281d
53b8d50
0a9bb3f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,6 +49,14 @@ class StorageUploadCommand < ApiCommand | |
| # @return [Integer] | ||
| attr_accessor :upload_chunk_size | ||
|
|
||
| # Unique upload_id of a resumable upload | ||
| # @return [String] | ||
| attr_accessor :upload_id | ||
|
|
||
| # Boolean Value to specify is a resumable upload is to be deleted or not | ||
| # @return [Boolean] | ||
| attr_accessor :delete_upload | ||
|
|
||
| # Ensure the content is readable and wrapped in an IO instance. | ||
| # | ||
| # @return [void] | ||
|
|
@@ -96,8 +104,16 @@ def execute(client) | |
| prepare! | ||
| opencensus_begin_span | ||
| @upload_chunk_size = options.upload_chunk_size | ||
| if upload_id.nil? | ||
| res = do_retry :initiate_resumable_upload, client | ||
| elsif delete_upload && !upload_id.nil? | ||
| make_resumable_upload_url upload_id | ||
| res = do_retry :cancel_resumable_upload, client | ||
| else | ||
| make_resumable_upload_url upload_id | ||
| res = do_retry :reinitiate_resumable_upload, client | ||
| end | ||
|
|
||
| do_retry :initiate_resumable_upload, client | ||
| while @upload_incomplete | ||
| res = do_retry :send_upload_command, client | ||
| end | ||
|
|
@@ -131,6 +147,24 @@ def initiate_resumable_upload(client) | |
| error(e, rethrow: true) | ||
| end | ||
|
|
||
| # Reinitiating resumable upload | ||
| def reinitiate_resumable_upload(client) | ||
|
shubhangi-google marked this conversation as resolved.
|
||
| logger.debug { sprintf('Restarting resumable upload command to %s', url) } | ||
| check_resumable_upload_status client | ||
| upload_io.pos = @offset | ||
|
bajajneha27 marked this conversation as resolved.
|
||
| rescue => e | ||
|
shubhangi-google marked this conversation as resolved.
Outdated
|
||
| error(e, rethrow: true) | ||
| end | ||
|
|
||
| # Making resumable upload url from upload_id | ||
| def make_resumable_upload_url(upload_id) | ||
|
shubhangi-google marked this conversation as resolved.
Outdated
|
||
| query_params = query.dup | ||
| query_params['uploadType'] = RESUMABLE | ||
| query_params['upload_id'] = upload_id | ||
| resumable_upload_params = query_params.map { |key, value| "#{key}=#{value}" }.join('&') | ||
| @upload_url = "#{url}&#{resumable_upload_params}" | ||
| end | ||
|
|
||
| # Send the actual content | ||
| # | ||
| # @param [HTTPClient] client | ||
|
|
@@ -160,6 +194,9 @@ def send_upload_command(client) | |
| @offset += current_chunk_size if @upload_incomplete | ||
| success(result) | ||
| rescue => e | ||
| logger.warn { | ||
| "error occured please use uploadId-#{response.headers['X-GUploader-UploadID']} to resume your upload" | ||
| } unless response.nil? | ||
| upload_io.pos = @offset | ||
| error(e, rethrow: true) | ||
| end | ||
|
|
@@ -182,6 +219,54 @@ def process_response(status, header, body) | |
| super(status, header, body) | ||
| end | ||
|
|
||
| def check_resumable_upload_status(client) | ||
|
shubhangi-google marked this conversation as resolved.
Outdated
|
||
| # Setting up request header | ||
| request_header = header.dup | ||
| request_header[CONTENT_RANGE_HEADER] = "bytes */#{upload_io.size}" | ||
| request_header[CONTENT_LENGTH_HEADER] = '0' | ||
| # Initiating call | ||
| response = client.put(@upload_url, header: request_header, follow_redirect: true) | ||
|
bajajneha27 marked this conversation as resolved.
|
||
|
|
||
| case response.code.to_i | ||
| when 308 | ||
| if response.headers['Range'] | ||
| range = response.headers['Range'] | ||
| @offset = range ? range.split('-').last.to_i + 1 : 0 | ||
| puts "Upload is incomplete. Bytes uploaded so far: #{response.headers['Range']}" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any particular reason why you're using |
||
| else | ||
| puts 'No bytes uploaded yet.' | ||
| end | ||
| @upload_incomplete = true | ||
| when 400..499 | ||
| # Upload is canceled | ||
| @upload_incomplete = false | ||
| when 200, 201 | ||
| # Upload is complete. | ||
| @upload_incomplete = false | ||
| else | ||
| puts "Unexpected response: #{response.code} - #{response.body}" | ||
| @upload_incomplete = true | ||
| end | ||
| end | ||
|
|
||
| # Cancel resumable upload | ||
| def cancel_resumable_upload(client) | ||
| # Setting up request header | ||
| request_header = header.dup | ||
| request_header[CONTENT_LENGTH_HEADER] = '0' | ||
| # Initiating call | ||
| response = client.delete(@upload_url, header: request_header, follow_redirect: true) | ||
| case response.code.to_i | ||
| when 400..499 | ||
| @close_io_on_finish = true | ||
|
shubhangi-google marked this conversation as resolved.
Outdated
|
||
| @upload_incomplete = false | ||
| true # method returns true if upload is sucessfully cancelled | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we returning boolean from this method?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since this delete_resumable_upload is not supposed to return any thing (example any object) |
||
| else | ||
| puts "Failed to cancel upload session. Response: #{response.code} - #{response.body}" | ||
| false # method returns false if upload is not cancelled | ||
| end | ||
| end | ||
|
|
||
| def streamable?(upload_source) | ||
| upload_source.is_a?(IO) || upload_source.is_a?(StringIO) || upload_source.is_a?(Tempfile) | ||
| end | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.