gapic-common 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ # Copyright 2019 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "grpc"
16
+ require "grpc/errors"
17
+ require "grpc/google_rpc_status_utils"
18
+ require "google/protobuf/well_known_types"
19
+ # Required in order to deserialize common error detail proto types
20
+ require "google/rpc/error_details_pb"
21
+
22
+ module GRPC
23
+ class BadStatus < StandardError
24
+ def status_details
25
+ rpc_status = to_rpc_status
26
+
27
+ return nil.to_a if rpc_status.nil?
28
+
29
+ rpc_status.details.map do |detail|
30
+ begin
31
+ detail_type = Google::Protobuf::DescriptorPool.generated_pool.lookup detail.type_name
32
+ detail = detail.unpack detail_type.msgclass if detail_type
33
+ detail
34
+ rescue Google::Protobuf::ParseError
35
+ detail
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,43 @@
1
+ # Copyright 2019 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "gapic/operation/retry_policy"
16
+ require "google/protobuf/well_known_types"
17
+ require "gapic/common/version"
18
+
19
+ module Gapic
20
+ # A collection of common header values.
21
+ module Headers
22
+ ##
23
+ # @param ruby_version [String] The ruby version. Defaults to `RUBY_VERSION`.
24
+ # @param lib_name [String] The client library name.
25
+ # @param lib_version [String] The client library version.
26
+ # @param gax_version [String] The Gapic version. Defaults to `Gapic::Common::VERSION`.
27
+ # @param gapic_version [String] The Gapic version.
28
+ # @param grpc_version [String] The GRPC version. Defaults to `GRPC::VERSION`.
29
+ def self.x_goog_api_client ruby_version: nil, lib_name: nil, lib_version: nil,
30
+ gax_version: nil, gapic_version: nil, grpc_version: nil
31
+ ruby_version ||= ::RUBY_VERSION
32
+ gax_version ||= ::Gapic::Common::VERSION
33
+ grpc_version ||= ::GRPC::VERSION if defined? ::GRPC
34
+
35
+ x_goog_api_client_header = ["gl-ruby/#{ruby_version}"]
36
+ x_goog_api_client_header << "#{lib_name}/#{lib_version}" if lib_name
37
+ x_goog_api_client_header << "gax/#{gax_version}"
38
+ x_goog_api_client_header << "gapic/#{gapic_version}" if gapic_version
39
+ x_goog_api_client_header << "grpc/#{grpc_version}" if grpc_version
40
+ x_goog_api_client_header.join " ".freeze
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,278 @@
1
+ # Copyright 2019 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "gapic/operation/retry_policy"
16
+ require "google/protobuf/well_known_types"
17
+
18
+ module Gapic
19
+ # A class used to wrap Google::Longrunning::Operation objects. This class provides helper methods to check the
20
+ # status of an Operation
21
+ #
22
+ # @example Checking Operation status
23
+ # # this example assumes both api_client and operations_client
24
+ # # already exist.
25
+ # require "gapic/operation"
26
+ #
27
+ # op = Gapic::Operation.new(
28
+ # api_client.method_that_returns_longrunning_operation(),
29
+ # operations_client,
30
+ # Google::Example::ResultType,
31
+ # Google::Example::MetadataType
32
+ # )
33
+ #
34
+ # op.done? # => false
35
+ # op.reload! # => operation completed
36
+ #
37
+ # if op.done?
38
+ # results = op.results
39
+ # handle_error(results) if op.error?
40
+ # # Handle results.
41
+ # end
42
+ #
43
+ # @example Working with callbacks
44
+ # # this example assumes both api_client and operations_client
45
+ # # already exist.
46
+ # require "gapic/operation"
47
+ #
48
+ # op = Gapic::Operation.new(
49
+ # api_client.method_that_returns_longrunning_operation(),
50
+ # operations_client,
51
+ # Google::Example::ResultType,
52
+ # Google::Example::MetadataType
53
+ # )
54
+ #
55
+ # # Register a callback to be run when an operation is done.
56
+ # op.on_done do |operation|
57
+ # raise operation.results.message if operation.error?
58
+ # # process(operation.results)
59
+ # # process(operation.metadata)
60
+ # end
61
+ #
62
+ # # Reload the operation running callbacks if operation completed.
63
+ # op.reload!
64
+ #
65
+ # # Or block until the operation completes, passing a block to be called
66
+ # # on completion.
67
+ # op.wait_until_done do |operation|
68
+ # raise operation.results.message if operation.error?
69
+ # # process(operation.results)
70
+ # # process(operation.rmetadata)
71
+ # end
72
+ #
73
+ # @attribute [r] grpc_op
74
+ # @return [Google::Longrunning::Operation] The wrapped grpc
75
+ # operation object.
76
+ class Operation
77
+ attr_reader :grpc_op
78
+
79
+ ##
80
+ # @param grpc_op [Google::Longrunning::Operation] The inital longrunning operation.
81
+ # @param client [Google::Longrunning::OperationsClient] The client that handles the grpc operations.
82
+ # @param result_type [Class] The class type to be unpacked from the result. If not provided the class type will be
83
+ # looked up. Optional.
84
+ # @param metadata_type [Class] The class type to be unpacked from the metadata. If not provided the class type
85
+ # will be looked up. Optional.
86
+ #
87
+ def initialize grpc_op, client, result_type: nil, metadata_type: nil
88
+ @grpc_op = grpc_op
89
+ @client = client
90
+ @result_type = result_type
91
+ @metadata_type = metadata_type
92
+ @on_done_callbacks = []
93
+ end
94
+
95
+ ##
96
+ # If the operation is done, returns the response. If the operation response is an error, the error will be
97
+ # returned. Otherwise returns nil.
98
+ #
99
+ # @return [Object, Google::Rpc::Status, nil] The result of the operation. If it is an error a
100
+ # {Google::Rpc::Status} will be returned.
101
+ def results
102
+ return error if error?
103
+ return response if response?
104
+ end
105
+
106
+ ##
107
+ # Returns the server-assigned name of the operation, which is only unique within the same service that originally
108
+ # returns it. If you use the default HTTP mapping, the name should have the format of operations/some/unique/name.
109
+ #
110
+ # @return [String] The name of the operation.
111
+ #
112
+ def name
113
+ @grpc_op.name
114
+ end
115
+
116
+ ##
117
+ # Returns the metadata of an operation. If a type is provided, the metadata will be unpacked using the type
118
+ # provided; returning nil if the metadata is not of the type provided. If the type is not of provided, the
119
+ # metadata will be unpacked using the metadata's type_url if the type_url is found in the
120
+ # {Google::Protobuf::DescriptorPool.generated_pool}. If the type cannot be found the raw metadata is retuned.
121
+ #
122
+ # @return [Object, nil] The metadata of the operation. Can be nil.
123
+ #
124
+ def metadata
125
+ return if @grpc_op.metadata.nil?
126
+
127
+ return @grpc_op.metadata.unpack @metadata_type if @metadata_type
128
+
129
+ descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup @grpc_op.metadata.type_name
130
+
131
+ return @grpc_op.metadata.unpack descriptor.msgclass if descriptor
132
+
133
+ @grpc_op.metadata
134
+ end
135
+
136
+ ##
137
+ # Checks if the operation is done. This does not send a new api call, but checks the result of the previous api
138
+ # call to see if done.
139
+ #
140
+ # @return [Boolean] Whether the operation is done.
141
+ #
142
+ def done?
143
+ @grpc_op.done
144
+ end
145
+
146
+ ##
147
+ # Checks if the operation is done and the result is a response. If the operation is not finished then this will
148
+ # return false.
149
+ #
150
+ # @return [Boolean] Whether a response has been returned.
151
+ #
152
+ def response?
153
+ done? ? @grpc_op.result == :response : false
154
+ end
155
+
156
+ ##
157
+ # If the operation is done, returns the response, otherwise returns nil.
158
+ #
159
+ # @return [Object, nil] The response of the operation.
160
+ def response
161
+ return unless response?
162
+
163
+ return @grpc_op.response.unpack @result_type if @result_type
164
+
165
+ descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup @grpc_op.response.type_name
166
+
167
+ return @grpc_op.response.unpack descriptor.msgclass if descriptor
168
+
169
+ @grpc_op.response
170
+ end
171
+
172
+ ##
173
+ # Checks if the operation is done and the result is an error. If the operation is not finished then this will
174
+ # return false.
175
+ #
176
+ # @return [Boolean] Whether an error has been returned.
177
+ #
178
+ def error?
179
+ done? ? @grpc_op.result == :error : false
180
+ end
181
+
182
+ ##
183
+ # If the operation response is an error, the error will be returned, otherwise returns nil.
184
+ #
185
+ # @return [Google::Rpc::Status, nil] The error object.
186
+ #
187
+ def error
188
+ @grpc_op.error if error?
189
+ end
190
+
191
+ ##
192
+ # Cancels the operation.
193
+ #
194
+ # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to customize
195
+ # the options object, using keys that match the arguments for {Gapic::CallOptions.new}.
196
+ #
197
+ def cancel options: nil
198
+ # Converts hash and nil to an options object
199
+ options = Gapic::CallOptions.new options.to_h if options.respond_to? :to_h
200
+
201
+ @client.cancel_operation({ name: @grpc_op.name }, options)
202
+ end
203
+
204
+ ##
205
+ # Deletes the operation.
206
+ #
207
+ # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to customize
208
+ # the options object, using keys that match the arguments for {Gapic::CallOptions.new}.
209
+ #
210
+ def delete options: nil
211
+ # Converts hash and nil to an options object
212
+ options = Gapic::CallOptions.new options.to_h if options.respond_to? :to_h
213
+
214
+ @client.delete_operation({ name: @grpc_op.name }, options)
215
+ end
216
+
217
+ ##
218
+ # Reloads the operation object.
219
+ #
220
+ # @param options [Gapic::CallOptions, Hash] The options for making the RPC call. A Hash can be provided to customize
221
+ # the options object, using keys that match the arguments for {Gapic::CallOptions.new}.
222
+ #
223
+ # @return [Gapic::Operation] Since this method changes internal state, it returns itself.
224
+ #
225
+ def reload! options: nil
226
+ # Converts hash and nil to an options object
227
+ options = Gapic::CallOptions.new options.to_h if options.respond_to? :to_h
228
+
229
+ gax_op = @client.get_operation({ name: @grpc_op.name }, options)
230
+ @grpc_op = gax_op.grpc_op
231
+
232
+ if done?
233
+ @on_done_callbacks.each { |proc| proc.call self }
234
+ @on_done_callbacks.clear
235
+ end
236
+
237
+ self
238
+ end
239
+ alias refresh! reload!
240
+
241
+ ##
242
+ # Blocking method to wait until the operation has completed or the maximum timeout has been reached. Upon
243
+ # completion, registered callbacks will be called, then - if a block is given - the block will be called.
244
+ #
245
+ # @param retry_policy [RetryPolicy, Hash, Proc] The policy for retry. A custom proc that takes the error as an
246
+ # argument and blocks can also be provided.
247
+ #
248
+ # @yield operation [Gapic::Operation] Yields the finished Operation.
249
+ #
250
+ def wait_until_done! retry_policy: nil
251
+ retry_policy = RetryPolicy.new retry_policy if retry_policy.is_a? Hash
252
+ retry_policy ||= RetryPolicy.new
253
+
254
+ until done?
255
+ reload!
256
+ break unless retry_policy.call
257
+ end
258
+
259
+ yield self if block_given?
260
+
261
+ self
262
+ end
263
+
264
+ ##
265
+ # Registers a callback to be run when a refreshed operation is marked as done. If the operation has completed
266
+ # prior to a call to this function the callback will be called instead of registered.
267
+ #
268
+ # @yield operation [Gapic::Operation] Yields the finished Operation.
269
+ #
270
+ def on_done &block
271
+ if done?
272
+ yield self
273
+ else
274
+ @on_done_callbacks.push block
275
+ end
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,92 @@
1
+ # Copyright 2019 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Gapic
16
+ class Operation
17
+ ##
18
+ # The policy for retrying operation reloads using an incremental backoff. A new object instance should be used for
19
+ # every Operation invocation.
20
+ #
21
+ class RetryPolicy
22
+ ##
23
+ # Create new Operation RetryPolicy.
24
+ #
25
+ # @param initial_delay [Numeric] client-side timeout
26
+ # @param multiplier [Numeric] client-side timeout
27
+ # @param max_delay [Numeric] client-side timeout
28
+ # @param timeout [Numeric] client-side timeout
29
+ #
30
+ def initialize initial_delay: nil, multiplier: nil, max_delay: nil, timeout: nil
31
+ @initial_delay = initial_delay
32
+ @multiplier = multiplier
33
+ @max_delay = max_delay
34
+ @timeout = timeout
35
+ @delay = nil
36
+ end
37
+
38
+ def initial_delay
39
+ @initial_delay || 10
40
+ end
41
+
42
+ def multiplier
43
+ @multiplier || 1.3
44
+ end
45
+
46
+ def max_delay
47
+ @max_delay || 300 # Five minutes
48
+ end
49
+
50
+ def timeout
51
+ @timeout || 3600 # One hour
52
+ end
53
+
54
+ def call
55
+ return unless retry?
56
+
57
+ delay!
58
+ increment_delay!
59
+
60
+ true
61
+ end
62
+
63
+ private
64
+
65
+ def deadline
66
+ # memoize the deadline
67
+ @deadline ||= Time.now + timeout
68
+ end
69
+
70
+ def retry?
71
+ deadline > Time.now
72
+ end
73
+
74
+ ##
75
+ # The current delay value.
76
+ def delay
77
+ @delay || initial_delay
78
+ end
79
+
80
+ def delay!
81
+ # Call Kernel.sleep so we can stub it.
82
+ Kernel.sleep delay
83
+ end
84
+
85
+ ##
86
+ # Calculate and set the next delay value.
87
+ def increment_delay!
88
+ @delay = [delay * multiplier, max_delay].min
89
+ end
90
+ end
91
+ end
92
+ end