#286 - Send content-id in batch requests
This commit is contained in:
1 parent
ed40d7b750
commit
8b296b148e
3 files changed
+70
-25
No files matched your search
@@ -31,7 +31,7 @@ require 'google/apis/core/http_command'
|
||||
require 'google/apis/core/upload'
|
||||
require 'google/apis/core/download'
|
||||
require 'addressable/uri'
|
||||
|
||||
require 'securerandom'
|
||||
module Google
|
||||
module Apis
|
||||
module Core
|
||||
@@ -47,6 +47,7 @@ module Google
|
||||
def initialize(method, url)
|
||||
super(method, url)
|
||||
@calls = []
|
||||
@base_id = SecureRandom.uuid
|
||||
end
|
||||
|
||||
##
|
||||
@@ -78,9 +79,12 @@ module Google
|
||||
parts = split_parts(body, m[1])
|
||||
deserializer = CallDeserializer.new
|
||||
parts.each_index do |index|
|
||||
call, callback = @calls[index]
|
||||
response = deserializer.to_http_response(parts[index])
|
||||
outer_header = response.shift
|
||||
call_id = header_to_id(outer_header[:content_id]) || index
|
||||
call, callback = @calls[call_id]
|
||||
begin
|
||||
result = call.process_response(*deserializer.to_http_response(parts[index])) unless call.nil?
|
||||
result = call.process_response(*response) unless call.nil?
|
||||
success(result, &callback)
|
||||
rescue => e
|
||||
error(e, &callback)
|
||||
@@ -103,9 +107,11 @@ module Google
|
||||
|
||||
serializer = CallSerializer.new
|
||||
multipart = Multipart.new(boundary: BATCH_BOUNDARY, content_type: MULTIPART_MIXED)
|
||||
@calls.each do |(call, _)|
|
||||
@calls.each_index do |index|
|
||||
call, _ = @calls[index]
|
||||
content_id = id_to_header(index)
|
||||
io = serializer.to_upload_io(call)
|
||||
multipart.add_upload(io)
|
||||
multipart.add_upload(io, content_id: content_id)
|
||||
end
|
||||
self.body = multipart.assemble
|
||||
|
||||
@@ -120,6 +126,17 @@ module Google
|
||||
end
|
||||
fail Google::Apis::ClientError, 'Invalid command object' unless command.is_a?(HttpCommand)
|
||||
end
|
||||
|
||||
def id_to_header(call_id)
|
||||
return sprintf('<%s+%i>', @base_id, call_id)
|
||||
end
|
||||
|
||||
def header_to_id(content_id)
|
||||
match = /<response-.*\+(\d+)>/.match(content_id)
|
||||
return match[1].to_i if match
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Wrapper request for batching multiple uploads in a single server request
|
||||
@@ -180,19 +197,19 @@ module Google
|
||||
# Deconstructs a raw HTTP response part
|
||||
# @private
|
||||
class CallDeserializer
|
||||
# Convert a single batched response into a BatchedCallResponse object.
|
||||
# Parse a batched response.
|
||||
#
|
||||
# @param [String] call_response
|
||||
# the response to parse.
|
||||
# @return [Array<(Fixnum, Hurley::Header, String)>]
|
||||
# Status, header, and response body.
|
||||
def to_http_response(call_response)
|
||||
_, outer_body = split_header_and_body(call_response)
|
||||
outer_header, outer_body = split_header_and_body(call_response)
|
||||
status_line, payload = outer_body.split(/\n/, 2)
|
||||
_, status = status_line.split(' ', 3)
|
||||
|
||||
header, body = split_header_and_body(payload)
|
||||
[status.to_i, header, body]
|
||||
[outer_header, status.to_i, header, body]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
@@ -31,7 +31,7 @@ module Google
|
||||
# Multipart boundary
|
||||
# @param [String] value
|
||||
# JSON content
|
||||
def initialize(boundary, value)
|
||||
def initialize(boundary, value, header = {})
|
||||
@part = build_part(boundary, value)
|
||||
@length = @part.bytesize
|
||||
@io = StringIO.new(@part)
|
||||
@@ -95,19 +95,25 @@ module Google
|
||||
# @param [Hash] header
|
||||
# Headers for the part
|
||||
def build_head(boundary, type, content_len, header)
|
||||
content_id = ''
|
||||
if header[:content_id]
|
||||
content_id = sprintf(CID_FORMAT, header[:content_id])
|
||||
end
|
||||
sprintf(HEAD_FORMAT,
|
||||
boundary,
|
||||
content_len.to_i,
|
||||
content_id,
|
||||
header[:content_type] || type,
|
||||
header[:content_transfer_encoding] || DEFAULT_TR_ENCODING)
|
||||
end
|
||||
|
||||
DEFAULT_TR_ENCODING = 'binary'.freeze
|
||||
FOOT = "\r\n".freeze
|
||||
CID_FORMAT = "Content-ID: %s\r\n"
|
||||
HEAD_FORMAT = <<-END
|
||||
--%s\r
|
||||
Content-Length: %d\r
|
||||
Content-Type: %s\r
|
||||
%sContent-Type: %s\r
|
||||
Content-Transfer-Encoding: %s\r
|
||||
\r
|
||||
END
|
||||
@@ -137,9 +143,12 @@ Content-Transfer-Encoding: %s\r
|
||||
#
|
||||
# @param [String] body
|
||||
# JSON text
|
||||
# @param [String] content_id
|
||||
# Optional unique ID of this part
|
||||
# @return [self]
|
||||
def add_json(body)
|
||||
@parts << Google::Apis::Core::JsonPart.new(@boundary, body)
|
||||
def add_json(body, content_id: nil)
|
||||
header = { :content_id => content_id }
|
||||
@parts << Google::Apis::Core::JsonPart.new(@boundary, body, header)
|
||||
self
|
||||
end
|
||||
|
||||
@@ -147,9 +156,14 @@ Content-Transfer-Encoding: %s\r
|
||||
#
|
||||
# @param [Google::Apis::Core::UploadIO] upload_io
|
||||
# IO stream
|
||||
# @param [String] content_id
|
||||
# Optional unique ID of this part
|
||||
# @return [self]
|
||||
def add_upload(upload_io)
|
||||
@parts << Google::Apis::Core::FilePart.new(@boundary, upload_io)
|
||||
def add_upload(upload_io, content_id: nil)
|
||||
header = { :content_id => content_id }
|
||||
@parts << Google::Apis::Core::FilePart.new(@boundary,
|
||||
upload_io,
|
||||
header)
|
||||
self
|
||||
end
|
||||
|
||||
|
||||
Reference in new issue
Block a user