X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/06cdb76670763fd60f6dba71e385a98867c87ac1..18d3cccd6a471ce4b75460836730ed0918b36439:/lib/google/api_client/reference.rb diff --git a/lib/google/api_client/reference.rb b/lib/google/api_client/reference.rb index 4c67bca1eb..4bf41f4e40 100644 --- a/lib/google/api_client/reference.rb +++ b/lib/google/api_client/reference.rb @@ -12,47 +12,41 @@ # See the License for the specific language governing permissions and # limitations under the License. - -gem 'faraday', '~> 0.7.0' require 'faraday' require 'faraday/utils' require 'multi_json' +require 'compat/multi_json' require 'addressable/uri' require 'stringio' require 'google/api_client/discovery' +# TODO - needs some serious cleanup module Google class APIClient class Reference + MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze + def initialize(options={}) - # We only need this to do lookups on method ID String values - # It's optional, but method ID lookups will fail if the client is - # omitted. - @client = options[:client] - @version = options[:version] || 'v1' self.connection = options[:connection] || Faraday.default_connection + self.authorization = options[:authorization] self.api_method = options[:api_method] + self.parameters = options[:parameters] || {} # These parameters are handled differently because they're not # parameters to the API method, but rather to the API system. self.parameters['key'] ||= options[:key] if options[:key] self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip] - self.headers = options[:headers] || [] - if options[:body] + + self.headers = options[:headers] || {} + if options[:media] + self.initialize_media_upload + elsif options[:body] self.body = options[:body] elsif options[:body_object] - if options[:body_object].respond_to?(:to_json) - serialized_body = options[:body_object].to_json - elsif options[:body_object].respond_to?(:to_hash) - serialized_body = MultiJson.encode(options[:body_object].to_hash) - else - raise TypeError, - 'Could not convert body object to JSON.' + - 'Must respond to :to_json or :to_hash.' - end - self.body = serialized_body + self.headers['Content-Type'] ||= 'application/json' + self.body = serialize_body(options[:body_object]) else self.body = '' end @@ -60,12 +54,76 @@ module Google self.http_method = options[:http_method] || 'GET' self.uri = options[:uri] unless self.parameters.empty? - self.uri.query_values = - (self.uri.query_values || {}).merge(self.parameters) + self.uri.query = Addressable::URI.form_encode(self.parameters) + end + end + end + + def initialize_media_upload + self.media = options[:media] + case self.upload_type + when "media" + if options[:body] || options[:body_object] + raise ArgumentError, "Can not specify body & body object for simple uploads" end + self.headers['Content-Type'] ||= self.media.content_type + self.body = self.media + when "multipart" + unless options[:body_object] + raise ArgumentError, "Multipart requested but no body object" + end + metadata = StringIO.new(serialize_body(options[:body_object])) + env = { + :request_headers => {'Content-Type' => "multipart/related;boundary=#{MULTIPART_BOUNDARY}"}, + :request => { :boundary => MULTIPART_BOUNDARY } + } + multipart = Faraday::Request::Multipart.new + self.body = multipart.create_multipart(env, [ + [nil,Faraday::UploadIO.new(metadata, 'application/json', 'file.json')], + [nil, self.media]]) + self.headers.update(env[:request_headers]) + when "resumable" + file_length = self.media.length + self.headers['X-Upload-Content-Type'] = self.media.content_type + self.headers['X-Upload-Content-Length'] = file_length.to_s + if options[:body_object] + self.headers['Content-Type'] ||= 'application/json' + self.body = serialize_body(options[:body_object]) + else + self.body = '' + end + else + raise ArgumentError, "Invalid uploadType for media" end end + def serialize_body(body) + return body.to_json if body.respond_to?(:to_json) + return MultiJson.dump(options[:body_object].to_hash) if body.respond_to?(:to_hash) + raise TypeError, 'Could not convert body object to JSON.' + + 'Must respond to :to_json or :to_hash.' + end + + def media + return @media + end + + def media=(media) + @media = (media) + end + + def upload_type + return self.parameters['uploadType'] || self.parameters['upload_type'] + end + + def authorization + return @authorization + end + + def authorization=(new_authorization) + @authorization = new_authorization + end + def connection return @connection end @@ -87,29 +145,6 @@ module Google if new_api_method.kind_of?(Google::APIClient::Method) || new_api_method == nil @api_method = new_api_method - elsif new_api_method.respond_to?(:to_str) || - new_api_method.kind_of?(Symbol) - unless @client - raise ArgumentError, - "API method lookup impossible without client instance." - end - new_api_method = new_api_method.to_s - # This method of guessing the API is unreliable. This will fail for - # APIs where the first segment of the RPC name does not match the - # service name. However, this is a fallback mechanism anyway. - # Developers should be passing in a reference to the method, rather - # than passing in a string or symbol. This should raise an error - # in the case of a mismatch. - api = new_api_method[/^([^.]+)\./, 1] - @api_method = @client.discovered_method( - new_api_method, api, @version - ) - if @api_method - # Ditch the client reference, we won't need it again. - @client = nil - else - raise ArgumentError, "API method could not be found." - end else raise TypeError, "Expected Google::APIClient::Method, got #{new_api_method.class}." @@ -121,8 +156,7 @@ module Google end def parameters=(new_parameters) - # No type-checking needed, the Method class handles this. - @parameters = new_parameters + @parameters = Hash[new_parameters] end def body @@ -130,20 +164,11 @@ module Google end def body=(new_body) - if new_body.respond_to?(:to_str) - @body = new_body.to_str - elsif new_body.respond_to?(:inject) - @body = (new_body.inject(StringIO.new) do |accu, chunk| - accu.write(chunk) - accu - end).string - else - raise TypeError, "Expected body to be String or Enumerable chunks." - end + @body = new_body end def headers - return @headers ||= [] + return @headers ||= {} end def headers=(new_headers) @@ -160,9 +185,9 @@ module Google def http_method=(new_http_method) if new_http_method.kind_of?(Symbol) - @http_method = new_http_method.to_s.upcase + @http_method = new_http_method.to_s.downcase.to_sym elsif new_http_method.respond_to?(:to_str) - @http_method = new_http_method.to_str.upcase + @http_method = new_http_method.to_s.downcase.to_sym else raise TypeError, "Expected String or Symbol, got #{new_http_method.class}." @@ -177,20 +202,27 @@ module Google @uri = Addressable::URI.parse(new_uri) end - def to_request - if self.api_method - return self.api_method.generate_request( - self.parameters, self.body, self.headers + def to_http_request + request = ( + if self.api_method + self.api_method.generate_request( + self.parameters, self.body, self.headers, :connection => self.connection + ) + else + self.connection.build_request(self.http_method) do |req| + req.url(self.uri.to_str) + req.headers.update(self.headers) + req.body = self.body + end + end) + + if self.authorization.respond_to?(:generate_authenticated_request) + request = self.authorization.generate_authenticated_request( + :request => request, + :connection => self.connection ) - else - return Faraday::Request.create( - self.http_method.to_s.downcase.to_sym - ) do |req| - req.url(Addressable::URI.parse(self.uri)) - req.headers = Faraday::Utils::Headers.new(self.headers) - req.body = self.body - end end + return request end def to_hash @@ -205,6 +237,9 @@ module Google options[:headers] = self.headers options[:body] = self.body options[:connection] = self.connection + unless self.authorization.nil? + options[:authorization] = self.authorization + end return options end end