google-api-client 0.4.7 → 0.5.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.
@@ -20,8 +20,42 @@ require 'compat/multi_json'
20
20
  module Google
21
21
  class APIClient
22
22
  ##
23
- # Manages the persistence of client configuration data and secrets.
23
+ # Manages the persistence of client configuration data and secrets. Format
24
+ # inspired by the Google API Python client.
25
+ #
26
+ # @see https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
27
+ #
28
+ # @example
29
+ # {
30
+ # "web": {
31
+ # "client_id": "asdfjasdljfasdkjf",
32
+ # "client_secret": "1912308409123890",
33
+ # "redirect_uris": ["https://www.example.com/oauth2callback"],
34
+ # "auth_uri": "https://accounts.google.com/o/oauth2/auth",
35
+ # "token_uri": "https://accounts.google.com/o/oauth2/token"
36
+ # }
37
+ # }
38
+ #
39
+ # @example
40
+ # {
41
+ # "installed": {
42
+ # "client_id": "837647042410-75ifg...usercontent.com",
43
+ # "client_secret":"asdlkfjaskd",
44
+ # "redirect_uris": ["http://localhost", "urn:ietf:oauth:2.0:oob"],
45
+ # "auth_uri": "https://accounts.google.com/o/oauth2/auth",
46
+ # "token_uri": "https://accounts.google.com/o/oauth2/token"
47
+ # }
48
+ # }
24
49
  class ClientSecrets
50
+
51
+ ##
52
+ # Reads client configuration from a file
53
+ #
54
+ # @param [String] filename
55
+ # Path to file to load
56
+ #
57
+ # @return [Google::APIClient::ClientSecrets]
58
+ # OAuth client settings
25
59
  def self.load(filename=nil)
26
60
  if filename && File.directory?(filename)
27
61
  search_path = File.expand_path(filename)
@@ -44,6 +78,11 @@ module Google
44
78
  return self.new(data)
45
79
  end
46
80
 
81
+ ##
82
+ # Intialize OAuth client settings.
83
+ #
84
+ # @param [Hash] options
85
+ # Parsed client secrets files
47
86
  def initialize(options={})
48
87
  # Client auth configuration
49
88
  @flow = options[:flow] || options.keys.first.to_s || 'web'
@@ -77,6 +116,11 @@ module Google
77
116
  :refresh_token, :id_token, :expires_in, :expires_at, :issued_at
78
117
  )
79
118
 
119
+ ##
120
+ # Serialize back to the original JSON form
121
+ #
122
+ # @return [String]
123
+ # JSON
80
124
  def to_json
81
125
  return MultiJson.dump({
82
126
  self.flow => ({
@@ -29,13 +29,9 @@ module Google
29
29
  ##
30
30
  # Creates a description of a particular version of a service.
31
31
  #
32
- # @param [String] api
33
- # The identifier for the service. Note that while this frequently
34
- # matches the first segment of all of the service's RPC names, this
35
- # should not be assumed. There is no requirement that these match.
36
- # @param [String] version
37
- # The identifier for the service version.
38
- # @param [Hash] api_description
32
+ # @param [String] document_base
33
+ # Base URI for the service
34
+ # @param [Hash] discovery_document
39
35
  # The section of the discovery document that applies to this service
40
36
  # version.
41
37
  #
@@ -57,6 +53,9 @@ module Google
57
53
  end
58
54
  end
59
55
  end
56
+
57
+ # @return [String] unparsed discovery document for the API
58
+ attr_reader :discovery_document
60
59
 
61
60
  ##
62
61
  # Returns the id of the service.
@@ -159,7 +158,7 @@ module Google
159
158
  ##
160
159
  # Updates the hierarchy of resources and methods with the new base.
161
160
  #
162
- # @param [Addressable::URI, #to_str, String] new_base
161
+ # @param [Addressable::URI, #to_str, String] new_method_base
163
162
  # The new base URI to use for the service.
164
163
  def method_base=(new_method_base)
165
164
  @method_base = Addressable::URI.parse(new_method_base)
@@ -34,7 +34,7 @@ module Google
34
34
  # The base URI for the service.
35
35
  # @param [String] method_name
36
36
  # The identifier for the method.
37
- # @param [Hash] method_description
37
+ # @param [Hash] discovery_document
38
38
  # The section of the discovery document that applies to this method.
39
39
  #
40
40
  # @return [Google::APIClient::Method] The constructed method object.
@@ -45,6 +45,9 @@ module Google
45
45
  @discovery_document = discovery_document
46
46
  end
47
47
 
48
+ # @return [String] unparsed discovery document for the method
49
+ attr_reader :discovery_document
50
+
48
51
  ##
49
52
  # Returns the API this method belongs to.
50
53
  #
@@ -57,13 +60,6 @@ module Google
57
60
  # @return [String] The method identifier.
58
61
  attr_reader :name
59
62
 
60
- ##
61
- # Returns the parsed section of the discovery document that applies to
62
- # this method.
63
- #
64
- # @return [Hash] The method description.
65
- attr_reader :description
66
-
67
63
  ##
68
64
  # Returns the base URI for the method.
69
65
  #
@@ -74,13 +70,21 @@ module Google
74
70
  ##
75
71
  # Updates the method with the new base.
76
72
  #
77
- # @param [Addressable::URI, #to_str, String] new_base
73
+ # @param [Addressable::URI, #to_str, String] new_method_base
78
74
  # The new base URI to use for the method.
79
75
  def method_base=(new_method_base)
80
76
  @method_base = Addressable::URI.parse(new_method_base)
81
77
  @uri_template = nil
82
78
  end
83
79
 
80
+ ##
81
+ # Returns a human-readable description of the method.
82
+ #
83
+ # @return [Hash] The API description.
84
+ def description
85
+ return @discovery_document['description']
86
+ end
87
+
84
88
  ##
85
89
  # Returns the method ID.
86
90
  #
@@ -176,6 +180,7 @@ module Google
176
180
  ##
177
181
  # Expands the method's URI template using a parameter list.
178
182
  #
183
+ # @api private
179
184
  # @param [Hash, Array] parameters
180
185
  # The parameter list to use.
181
186
  #
@@ -214,6 +219,7 @@ module Google
214
219
  ##
215
220
  # Generates an HTTP request for this method.
216
221
  #
222
+ # @api private
217
223
  # @param [Hash, Array] parameters
218
224
  # The parameters to send.
219
225
  # @param [String, StringIO] body The body for the HTTP request.
@@ -222,28 +228,14 @@ module Google
222
228
  # The HTTP connection to use.
223
229
  #
224
230
  # @return [Array] The generated HTTP request.
225
- def generate_request(parameters={}, body='', headers=[], options={})
226
- options[:connection] ||= Faraday.default_connection
227
- if body.respond_to?(:string)
228
- body = body.string
229
- elsif body.respond_to?(:to_str)
230
- body = body.to_str
231
- else
232
- raise TypeError, "Expected String or StringIO, got #{body.class}."
233
- end
231
+ def generate_request(parameters={}, body='', headers={}, options={})
234
232
  if !headers.kind_of?(Array) && !headers.kind_of?(Hash)
235
233
  raise TypeError, "Expected Hash or Array, got #{headers.class}."
236
234
  end
237
- method = self.http_method
235
+ method = self.http_method.to_s.downcase.to_sym
238
236
  uri = self.generate_uri(parameters)
239
- headers = headers.to_a if headers.kind_of?(Hash)
240
- return options[:connection].build_request(
241
- method.to_s.downcase.to_sym
242
- ) do |req|
243
- req.url(Addressable::URI.parse(uri).normalize.to_s)
244
- req.headers = Faraday::Utils::Headers.new(headers)
245
- req.body = body
246
- end
237
+ headers = Faraday::Utils::Headers.new(headers)
238
+ return [method, uri, headers, body]
247
239
  end
248
240
 
249
241
 
@@ -302,6 +294,7 @@ module Google
302
294
  # Verifies that the parameters are valid for this method. Raises an
303
295
  # exception if validation fails.
304
296
  #
297
+ # @api private
305
298
  # @param [Hash, Array] parameters
306
299
  # The parameters to verify.
307
300
  #
@@ -28,11 +28,13 @@ module Google
28
28
  ##
29
29
  # Creates a description of a particular version of a resource.
30
30
  #
31
- # @param [Addressable::URI] base
31
+ # @param [Google::APIClient::API] api
32
+ # The API this resource belongs to.
33
+ # @param [Addressable::URI] method_base
32
34
  # The base URI for the service.
33
35
  # @param [String] resource_name
34
36
  # The identifier for the resource.
35
- # @param [Hash] resource_description
37
+ # @param [Hash] discovery_document
36
38
  # The section of the discovery document that applies to this resource.
37
39
  #
38
40
  # @return [Google::APIClient::Resource] The constructed resource object.
@@ -56,29 +58,33 @@ module Google
56
58
  end
57
59
  end
58
60
 
61
+ # @return [String] unparsed discovery document for the resource
62
+ attr_reader :discovery_document
63
+
59
64
  ##
60
65
  # Returns the identifier for the resource.
61
66
  #
62
67
  # @return [String] The resource identifier.
63
68
  attr_reader :name
64
69
 
65
- ##
66
- # Returns the parsed section of the discovery document that applies to
67
- # this resource.
68
- #
69
- # @return [Hash] The resource description.
70
- attr_reader :description
71
-
72
70
  ##
73
71
  # Returns the base URI for this resource.
74
72
  #
75
73
  # @return [Addressable::URI] The base URI that methods are joined to.
76
74
  attr_reader :method_base
77
75
 
76
+ ##
77
+ # Returns a human-readable description of the resource.
78
+ #
79
+ # @return [Hash] The API description.
80
+ def description
81
+ return @discovery_document['description']
82
+ end
83
+
78
84
  ##
79
85
  # Updates the hierarchy of resources and methods with the new base.
80
86
  #
81
- # @param [Addressable::URI, #to_str, String] new_base
87
+ # @param [Addressable::URI, #to_str, String] new_method_base
82
88
  # The new base URI to use for the resource.
83
89
  def method_base=(new_method_base)
84
90
  @method_base = Addressable::URI.parse(new_method_base)
@@ -27,6 +27,8 @@ require 'google/api_client/errors'
27
27
 
28
28
  module Google
29
29
  class APIClient
30
+ ##
31
+ # @api private
30
32
  module Schema
31
33
  def self.parse(api, schema_data)
32
34
  # This method is super-long, but hard to break up due to the
@@ -11,6 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+ require 'google/api_client/reference'
14
15
 
15
16
  module Google
16
17
  class APIClient
@@ -23,7 +24,8 @@ module Google
23
24
  class UploadIO < Faraday::UploadIO
24
25
  ##
25
26
  # Get the length of the stream
26
- # @return [Integer]
27
+ #
28
+ # @return [Fixnum]
27
29
  # Length of stream, in bytes
28
30
  def length
29
31
  io.respond_to?(:length) ? io.length : File.size(local_path)
@@ -33,41 +35,35 @@ module Google
33
35
  ##
34
36
  # Resumable uploader.
35
37
  #
36
- class ResumableUpload
37
- attr_reader :result
38
- attr_accessor :client
38
+ class ResumableUpload < Request
39
+ # @return [Fixnum] Max bytes to send in a single request
39
40
  attr_accessor :chunk_size
40
- attr_accessor :media
41
- attr_accessor :location
42
41
 
43
42
  ##
44
43
  # Creates a new uploader.
45
44
  #
46
- # @param [Google::APIClient::Result] result
47
- # Result of the initial request that started the upload
48
- # @param [Google::APIClient::UploadIO] media
49
- # Media to upload
50
- # @param [String] location
51
- # URL to upload to
52
- def initialize(result, media, location)
53
- self.media = media
54
- self.location = location
55
- self.chunk_size = 256 * 1024
56
-
57
- @api_method = result.reference.api_method
58
- @result = result
59
- @offset = 0
45
+ # @param [Hash] options
46
+ # Request options
47
+ def initialize(options={})
48
+ super options
49
+ self.uri = options[:uri]
50
+ self.http_method = :put
51
+ @offset = options[:offset] || 0
60
52
  @complete = false
53
+ @expired = false
61
54
  end
62
55
 
63
56
  ##
64
57
  # Sends all remaining chunks to the server
65
58
  #
59
+ # @deprecated Pass the instance to {Google::APIClient#execute} instead
60
+ #
66
61
  # @param [Google::APIClient] api_client
67
62
  # API Client instance to use for sending
68
63
  def send_all(api_client)
64
+ result = nil
69
65
  until complete?
70
- send_chunk(api_client)
66
+ result = send_chunk(api_client)
71
67
  break unless result.status == 308
72
68
  end
73
69
  return result
@@ -77,28 +73,12 @@ module Google
77
73
  ##
78
74
  # Sends the next chunk to the server
79
75
  #
76
+ # @deprecated Pass the instance to {Google::APIClient#execute} instead
77
+ #
80
78
  # @param [Google::APIClient] api_client
81
79
  # API Client instance to use for sending
82
80
  def send_chunk(api_client)
83
- if @offset.nil?
84
- return resync_range(api_client)
85
- end
86
-
87
- start_offset = @offset
88
- self.media.io.pos = start_offset
89
- chunk = self.media.io.read(chunk_size)
90
- content_length = chunk.bytesize
91
-
92
- end_offset = start_offset + content_length - 1
93
- @result = api_client.execute(
94
- :uri => self.location,
95
- :http_method => :put,
96
- :headers => {
97
- 'Content-Length' => "#{content_length}",
98
- 'Content-Type' => self.media.content_type,
99
- 'Content-Range' => "bytes #{start_offset}-#{end_offset}/#{media.length}" },
100
- :body => chunk)
101
- return process_result(@result)
81
+ return api_client.execute(self)
102
82
  end
103
83
 
104
84
  ##
@@ -117,54 +97,86 @@ module Google
117
97
  # @return [TrueClass, FalseClass]
118
98
  # Whether or not the upload has expired and can not be resumed
119
99
  def expired?
120
- return @result.status == 404 || @result.status == 410
100
+ return @expired
121
101
  end
122
102
 
123
103
  ##
124
- # Get the last saved range from the server in case an error occurred
125
- # and the offset is not known.
104
+ # Check if upload is resumable. That is, neither complete nor expired
126
105
  #
127
- # @param [Google::APIClient] api_client
128
- # API Client instance to use for sending
129
- def resync_range(api_client)
130
- r = api_client.execute(
131
- :uri => self.location,
132
- :http_method => :put,
133
- :headers => {
106
+ # @return [TrueClass, FalseClass] True if upload can be resumed
107
+ def resumable?
108
+ return !(self.complete? or self.expired?)
109
+ end
110
+
111
+ ##
112
+ # Convert to an HTTP request. Returns components in order of method, URI,
113
+ # request headers, and body
114
+ #
115
+ # @api private
116
+ #
117
+ # @return [Array<(Symbol, Addressable::URI, Hash, [#read,#to_str])>]
118
+ def to_http_request
119
+ if @complete
120
+ raise Google::APIClient::ClientError, "Upload already complete"
121
+ elsif @offset.nil?
122
+ self.headers.update({
134
123
  'Content-Length' => "0",
135
124
  'Content-Range' => "bytes */#{media.length}" })
136
- return process_result(r)
125
+ else
126
+ start_offset = @offset
127
+ self.media.io.pos = start_offset
128
+ chunk = self.media.io.read(chunk_size)
129
+ content_length = chunk.bytesize
130
+ end_offset = start_offset + content_length - 1
131
+
132
+ self.headers.update({
133
+ 'Content-Length' => "#{content_length}",
134
+ 'Content-Type' => self.media.content_type,
135
+ 'Content-Range' => "bytes #{start_offset}-#{end_offset}/#{media.length}" })
136
+ self.body = chunk
137
+ end
138
+ super
137
139
  end
138
140
 
139
141
  ##
140
142
  # Check the result from the server, updating the offset and/or location
141
143
  # if available.
142
144
  #
143
- # @param [Google::APIClient::Result] r
144
- # Result of a chunk upload or range query
145
- def process_result(result)
146
- case result.status
145
+ # @api private
146
+ #
147
+ # @param [Faraday::Response] response
148
+ # HTTP response
149
+ #
150
+ # @return [Google::APIClient::Result]
151
+ # Processed API response
152
+ def process_http_response(response)
153
+ case response.status
147
154
  when 200...299
148
155
  @complete = true
149
- if @api_method
150
- # Inject the original API method so data is parsed correctly
151
- result.reference.api_method = @api_method
152
- end
153
- return result
154
156
  when 308
155
- range = result.headers['range']
157
+ range = response.headers['range']
156
158
  if range
157
159
  @offset = range.scan(/\d+/).collect{|x| Integer(x)}.last + 1
158
160
  end
159
- if result.headers['location']
160
- self.location = result.headers['location']
161
+ if response.headers['location']
162
+ self.uri = response.headers['location']
161
163
  end
164
+ when 400...499
165
+ @expired = true
162
166
  when 500...599
163
167
  # Invalidate the offset to mark it needs to be queried on the
164
168
  # next request
165
169
  @offset = nil
166
170
  end
167
- return nil
171
+ return Google::APIClient::Result.new(self, response)
172
+ end
173
+
174
+ ##
175
+ # Hashified verison of the API request
176
+ #
177
+ # @return [Hash]
178
+ def to_hash
179
+ super.merge(:offset => @offset)
168
180
  end
169
181
 
170
182
  end