google-cloud-pubsub 1.0.2 → 2.19.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHENTICATION.md +16 -54
  3. data/CHANGELOG.md +464 -0
  4. data/CONTRIBUTING.md +328 -116
  5. data/EMULATOR.md +1 -1
  6. data/LOGGING.md +94 -2
  7. data/OVERVIEW.md +121 -68
  8. data/TROUBLESHOOTING.md +2 -8
  9. data/lib/google/cloud/pubsub/acknowledge_result.rb +79 -0
  10. data/lib/google/cloud/pubsub/async_publisher/batch.rb +319 -0
  11. data/lib/google/cloud/pubsub/async_publisher.rb +231 -156
  12. data/lib/google/cloud/pubsub/batch_publisher.rb +60 -30
  13. data/lib/google/cloud/pubsub/convert.rb +33 -7
  14. data/lib/google/cloud/pubsub/credentials.rb +2 -2
  15. data/lib/google/cloud/pubsub/errors.rb +93 -0
  16. data/lib/google/cloud/pubsub/flow_controller.rb +137 -0
  17. data/lib/google/cloud/pubsub/message.rb +45 -4
  18. data/lib/google/cloud/pubsub/policy.rb +3 -2
  19. data/lib/google/cloud/pubsub/project.rb +316 -49
  20. data/lib/google/cloud/pubsub/publish_result.rb +6 -1
  21. data/lib/google/cloud/pubsub/received_message.rb +171 -10
  22. data/lib/google/cloud/pubsub/retry_policy.rb +88 -0
  23. data/lib/google/cloud/pubsub/schema/list.rb +180 -0
  24. data/lib/google/cloud/pubsub/schema.rb +310 -0
  25. data/lib/google/cloud/pubsub/service.rb +285 -269
  26. data/lib/google/cloud/pubsub/snapshot/list.rb +4 -6
  27. data/lib/google/cloud/pubsub/snapshot.rb +5 -2
  28. data/lib/google/cloud/pubsub/subscriber/inventory.rb +69 -32
  29. data/lib/google/cloud/pubsub/subscriber/sequencer.rb +115 -0
  30. data/lib/google/cloud/pubsub/subscriber/stream.rb +108 -49
  31. data/lib/google/cloud/pubsub/subscriber/timed_unary_buffer.rb +191 -30
  32. data/lib/google/cloud/pubsub/subscriber.rb +155 -45
  33. data/lib/google/cloud/pubsub/subscription/list.rb +4 -6
  34. data/lib/google/cloud/pubsub/subscription/push_config.rb +55 -31
  35. data/lib/google/cloud/pubsub/subscription.rb +561 -77
  36. data/lib/google/cloud/pubsub/topic/list.rb +4 -6
  37. data/lib/google/cloud/pubsub/topic.rb +372 -52
  38. data/lib/google/cloud/pubsub/version.rb +1 -1
  39. data/lib/google/cloud/pubsub.rb +35 -46
  40. data/lib/google-cloud-pubsub.rb +21 -27
  41. metadata +26 -189
  42. data/lib/google/cloud/pubsub/v1/credentials.rb +0 -41
  43. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/iam_policy.rb +0 -21
  44. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/options.rb +0 -21
  45. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/policy.rb +0 -21
  46. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/duration.rb +0 -91
  47. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/empty.rb +0 -29
  48. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/field_mask.rb +0 -222
  49. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/timestamp.rb +0 -113
  50. data/lib/google/cloud/pubsub/v1/doc/google/pubsub/v1/pubsub.rb +0 -744
  51. data/lib/google/cloud/pubsub/v1/doc/google/type/expr.rb +0 -19
  52. data/lib/google/cloud/pubsub/v1/publisher_client.rb +0 -786
  53. data/lib/google/cloud/pubsub/v1/publisher_client_config.json +0 -105
  54. data/lib/google/cloud/pubsub/v1/subscriber_client.rb +0 -1385
  55. data/lib/google/cloud/pubsub/v1/subscriber_client_config.json +0 -138
  56. data/lib/google/cloud/pubsub/v1.rb +0 -17
  57. data/lib/google/pubsub/v1/pubsub_pb.rb +0 -249
  58. data/lib/google/pubsub/v1/pubsub_services_pb.rb +0 -211
@@ -18,78 +18,94 @@ require "google/cloud/pubsub/credentials"
18
18
  require "google/cloud/pubsub/convert"
19
19
  require "google/cloud/pubsub/version"
20
20
  require "google/cloud/pubsub/v1"
21
- require "google/gax/errors"
21
+ require "securerandom"
22
22
 
23
23
  module Google
24
24
  module Cloud
25
25
  module PubSub
26
26
  ##
27
- # @private Represents the GAX Pub/Sub service, including all the API
28
- # methods.
27
+ # @private Represents the Pub/Sub service API, including IAM mixins.
29
28
  class Service
30
- attr_accessor :project, :credentials, :host, :timeout, :client_config
29
+ attr_accessor :project
30
+ attr_accessor :credentials
31
+ attr_accessor :host
32
+ attr_accessor :timeout
33
+ ###
34
+ # The same client_id is used across all streaming pull connections that are created by this client. This is
35
+ # intentional, as it indicates to the server that any guarantees, such as message ordering, made for a stream
36
+ # that is disconnected will be made for the stream that is created to replace it. The attr_accessor allows the
37
+ # value to be replaced for unit testing.
38
+ attr_accessor :client_id
39
+
40
+ attr_reader :universe_domain
31
41
 
32
42
  ##
33
43
  # Creates a new Service instance.
34
- def initialize project, credentials, host: nil, timeout: nil,
35
- client_config: nil
44
+ def initialize project, credentials, host: nil, timeout: nil, universe_domain: nil
36
45
  @project = project
37
46
  @credentials = credentials
38
- @host = host || V1::PublisherClient::SERVICE_ADDRESS
47
+ @host = host
39
48
  @timeout = timeout
40
- @client_config = client_config || {}
41
- end
42
-
43
- def channel
44
- require "grpc"
45
- GRPC::Core::Channel.new host, chan_args, chan_creds
46
- end
47
-
48
- def chan_args
49
- { "grpc.max_send_message_length" => -1,
50
- "grpc.max_receive_message_length" => -1,
51
- "grpc.keepalive_time_ms" => 300000,
52
- "grpc.service_config_disable_resolution" => 1 }
53
- end
54
-
55
- def chan_creds
56
- return credentials if insecure?
57
- require "grpc"
58
- GRPC::Core::ChannelCredentials.new.compose \
59
- GRPC::Core::CallCredentials.new credentials.client.updater_proc
49
+ @client_id = SecureRandom.uuid.freeze
50
+ @universe_domain = universe_domain || ENV["GOOGLE_CLOUD_UNIVERSE_DOMAIN"] || "googleapis.com"
60
51
  end
61
52
 
62
53
  def subscriber
63
54
  return mocked_subscriber if mocked_subscriber
64
- @subscriber ||= begin
65
- V1::SubscriberClient.new(
66
- credentials: channel,
67
- timeout: timeout,
68
- client_config: client_config,
69
- lib_name: "gccl",
70
- lib_version: Google::Cloud::PubSub::VERSION
71
- )
55
+ @subscriber ||= V1::Subscriber::Client.new do |config|
56
+ config.credentials = credentials if credentials
57
+ override_client_config_timeouts config if timeout
58
+ config.endpoint = host if host
59
+ config.universe_domain = universe_domain
60
+ config.lib_name = "gccl"
61
+ config.lib_version = Google::Cloud::PubSub::VERSION
62
+ config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
72
63
  end
73
64
  end
74
65
  attr_accessor :mocked_subscriber
75
66
 
76
67
  def publisher
77
68
  return mocked_publisher if mocked_publisher
78
- @publisher ||= begin
79
- V1::PublisherClient.new(
80
- credentials: channel,
81
- timeout: timeout,
82
- client_config: client_config,
83
- lib_name: "gccl",
84
- lib_version: Google::Cloud::PubSub::VERSION
85
- )
69
+ @publisher ||= V1::Publisher::Client.new do |config|
70
+ config.credentials = credentials if credentials
71
+ override_client_config_timeouts config if timeout
72
+ config.endpoint = host if host
73
+ config.universe_domain = universe_domain
74
+ config.lib_name = "gccl"
75
+ config.lib_version = Google::Cloud::PubSub::VERSION
76
+ config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
86
77
  end
87
78
  end
88
79
  attr_accessor :mocked_publisher
89
80
 
90
- def insecure?
91
- credentials == :this_channel_is_insecure
81
+ def iam
82
+ return mocked_iam if mocked_iam
83
+ @iam ||= begin
84
+ iam = (@publisher || @subscriber || @schemas || subscriber).iam_policy_client
85
+ iam.configure do |config|
86
+ override_client_config_timeouts config if timeout
87
+ config.lib_name = "gccl"
88
+ config.lib_version = Google::Cloud::PubSub::VERSION
89
+ config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
90
+ end
91
+ iam
92
+ end
93
+ end
94
+ attr_accessor :mocked_iam
95
+
96
+ def schemas
97
+ return mocked_schemas if mocked_schemas
98
+ @schemas ||= V1::SchemaService::Client.new do |config|
99
+ config.credentials = credentials if credentials
100
+ override_client_config_timeouts config if timeout
101
+ config.endpoint = host if host
102
+ config.universe_domain = universe_domain
103
+ config.lib_name = "gccl"
104
+ config.lib_version = Google::Cloud::PubSub::VERSION
105
+ config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}" }
106
+ end
92
107
  end
108
+ attr_accessor :mocked_schemas
93
109
 
94
110
  ##
95
111
  # Gets the configuration of a topic.
@@ -98,58 +114,59 @@ module Google
98
114
  # If other attributes are added in the future,
99
115
  # they will be returned here.
100
116
  def get_topic topic_name, options = {}
101
- execute do
102
- publisher.get_topic topic_path(topic_name, options),
103
- options: default_options
104
- end
117
+ publisher.get_topic topic: topic_path(topic_name, options)
105
118
  end
106
119
 
107
120
  ##
108
121
  # Lists matching topics.
109
122
  def list_topics options = {}
110
- call_options = default_options
111
- if (token = options[:token])
112
- call_options = Google::Gax::CallOptions.new(
113
- kwargs: default_headers,
114
- page_token: token
115
- )
116
- end
123
+ paged_enum = publisher.list_topics project: project_path(options),
124
+ page_size: options[:max],
125
+ page_token: options[:token]
117
126
 
118
- execute do
119
- paged_enum = publisher.list_topics project_path(options),
120
- page_size: options[:max],
121
- options: call_options
122
-
123
- paged_enum.page.response
124
- end
127
+ paged_enum.response
125
128
  end
126
129
 
127
130
  ##
128
131
  # Creates the given topic with the given name.
129
- def create_topic topic_name, labels: nil, kms_key_name: nil,
130
- persistence_regions: nil, options: {}
132
+ def create_topic topic_name,
133
+ labels: nil,
134
+ kms_key_name: nil,
135
+ persistence_regions: nil,
136
+ schema_name: nil,
137
+ message_encoding: nil,
138
+ retention: nil,
139
+ ingestion_data_source_settings: nil,
140
+ options: {}
131
141
  if persistence_regions
132
- message_storage_policy = {
142
+ message_storage_policy = Google::Cloud::PubSub::V1::MessageStoragePolicy.new(
133
143
  allowed_persistence_regions: Array(persistence_regions)
134
- }
144
+ )
135
145
  end
136
146
 
137
- execute do
138
- publisher.create_topic \
139
- topic_path(topic_name, options),
140
- labels: labels,
141
- kms_key_name: kms_key_name,
142
- message_storage_policy: message_storage_policy,
143
- options: default_options
147
+ if schema_name || message_encoding
148
+ unless schema_name && message_encoding
149
+ raise ArgumentError, "Schema settings must include both schema_name and message_encoding."
150
+ end
151
+ schema_settings = Google::Cloud::PubSub::V1::SchemaSettings.new(
152
+ schema: schema_path(schema_name),
153
+ encoding: message_encoding.to_s.upcase
154
+ )
144
155
  end
156
+
157
+ publisher.create_topic \
158
+ name: topic_path(topic_name, options),
159
+ labels: labels,
160
+ kms_key_name: kms_key_name,
161
+ message_storage_policy: message_storage_policy,
162
+ schema_settings: schema_settings,
163
+ message_retention_duration: Convert.number_to_duration(retention),
164
+ ingestion_data_source_settings: ingestion_data_source_settings
145
165
  end
146
166
 
147
167
  def update_topic topic_obj, *fields
148
168
  mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
149
- execute do
150
- publisher.update_topic \
151
- topic_obj, mask, options: default_options
152
- end
169
+ publisher.update_topic topic: topic_obj, update_mask: mask
153
170
  end
154
171
 
155
172
  ##
@@ -158,10 +175,7 @@ module Google
158
175
  # exist. After a topic is deleted, a new topic may be created with the
159
176
  # same name.
160
177
  def delete_topic topic_name
161
- execute do
162
- publisher.delete_topic topic_path(topic_name),
163
- options: default_options
164
- end
178
+ publisher.delete_topic topic: topic_path(topic_name)
165
179
  end
166
180
 
167
181
  ##
@@ -169,284 +183,253 @@ module Google
169
183
  # Raises GRPC status code 5 if the topic does not exist.
170
184
  # The messages parameter is an array of arrays.
171
185
  # The first element is the data, second is attributes hash.
172
- def publish topic, messages
173
- execute do
174
- publisher.publish topic_path(topic), messages,
175
- options: default_options
176
- end
186
+ def publish topic, messages, compress: false
187
+ request = { topic: topic_path(topic), messages: messages }
188
+ compress_options = ::Gapic::CallOptions.new metadata: { "grpc-internal-encoding-request": "gzip" }
189
+ compress ? (publisher.publish request, compress_options) : (publisher.publish request)
177
190
  end
178
191
 
179
192
  ##
180
193
  # Gets the details of a subscription.
181
194
  def get_subscription subscription_name, options = {}
182
- subscription = subscription_path subscription_name, options
183
- execute do
184
- subscriber.get_subscription subscription, options: default_options
185
- end
195
+ subscriber.get_subscription subscription: subscription_path(subscription_name, options)
186
196
  end
187
197
 
188
198
  ##
189
199
  # Lists matching subscriptions by project and topic.
190
200
  def list_topics_subscriptions topic, options = {}
191
- call_options = default_options
192
- if (token = options[:token])
193
- call_options = Google::Gax::CallOptions.new(
194
- kwargs: default_headers,
195
- page_token: token
196
- )
197
- end
198
-
199
- execute do
200
- paged_enum = publisher.list_topic_subscriptions \
201
- topic_path(topic, options),
202
- page_size: options[:max],
203
- options: call_options
204
-
205
- paged_enum.page.response
206
- end
201
+ publisher.list_topic_subscriptions topic: topic_path(topic, options),
202
+ page_size: options[:max],
203
+ page_token: options[:token]
207
204
  end
208
205
 
209
206
  ##
210
207
  # Lists matching subscriptions by project.
211
208
  def list_subscriptions options = {}
212
- call_options = default_options
213
- if (token = options[:token])
214
- call_options = Google::Gax::CallOptions.new(
215
- kwargs: default_headers,
216
- page_token: token
217
- )
218
- end
219
-
220
- execute do
221
- paged_enum = subscriber.list_subscriptions project_path(options),
222
- page_size: options[:max],
223
- options: call_options
209
+ paged_enum = subscriber.list_subscriptions project: project_path(options),
210
+ page_size: options[:max],
211
+ page_token: options[:token]
224
212
 
225
- paged_enum.page.response
226
- end
213
+ paged_enum.response
227
214
  end
228
215
 
229
216
  ##
230
217
  # Creates a subscription on a given topic for a given subscriber.
231
218
  def create_subscription topic, subscription_name, options = {}
232
- name = subscription_path subscription_name, options
233
- topic = topic_path topic
234
- push_config = if options[:endpoint]
235
- Google::Cloud::PubSub::V1::PushConfig.new \
236
- push_endpoint: options[:endpoint],
237
- attributes: (options[:attributes] || {}).to_h
238
- end
239
- deadline = options[:deadline]
240
- retain_acked = options[:retain_acked]
241
- mrd = Convert.number_to_duration options[:retention]
242
- labels = options[:labels]
243
-
244
- execute do
245
- subscriber.create_subscription \
246
- name, topic,
247
- push_config: push_config,
248
- ack_deadline_seconds: deadline,
249
- retain_acked_messages: retain_acked,
250
- message_retention_duration: mrd,
251
- labels: labels,
252
- options: default_options
253
- end
219
+ updated_option = construct_create_subscription_options topic, subscription_name, options
220
+ subscriber.create_subscription(**updated_option)
254
221
  end
255
222
 
256
223
  def update_subscription subscription_obj, *fields
257
224
  mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
258
- execute do
259
- subscriber.update_subscription \
260
- subscription_obj, mask, options: default_options
261
- end
225
+ subscriber.update_subscription subscription: subscription_obj, update_mask: mask
262
226
  end
263
227
 
264
228
  ##
265
- # Deletes an existing subscription.
266
- # All pending messages in the subscription are immediately dropped.
229
+ # Deletes an existing subscription. All pending messages in the subscription are immediately dropped.
267
230
  def delete_subscription subscription
268
- execute do
269
- subscriber.delete_subscription subscription_path(subscription),
270
- options: default_options
271
- end
231
+ subscriber.delete_subscription subscription: subscription_path(subscription)
232
+ end
233
+
234
+ ##
235
+ # Detaches a subscription from its topic. All messages retained in the subscription are dropped. Subsequent
236
+ # `Pull` and `StreamingPull` requests will raise `FAILED_PRECONDITION`. If the subscription is a push
237
+ # subscription, pushes to the endpoint will stop.
238
+ def detach_subscription subscription
239
+ publisher.detach_subscription subscription: subscription_path(subscription)
272
240
  end
273
241
 
274
242
  ##
275
243
  # Pulls a single message from the server.
276
244
  def pull subscription, options = {}
277
- subscription = subscription_path subscription, options
278
245
  max_messages = options.fetch(:max, 100).to_i
279
246
  return_immediately = !(!options.fetch(:immediate, true))
280
247
 
281
- execute do
282
- subscriber.pull subscription,
283
- max_messages,
284
- return_immediately: return_immediately,
285
- options: default_options
286
- end
248
+ subscriber.pull subscription: subscription_path(subscription, options),
249
+ max_messages: max_messages,
250
+ return_immediately: return_immediately
287
251
  end
288
252
 
289
- def streaming_pull request_enum
290
- execute do
291
- subscriber.streaming_pull request_enum, options: default_options
292
- end
253
+ def streaming_pull request_enum, options = {}
254
+ subscriber.streaming_pull request_enum, options
293
255
  end
294
256
 
295
257
  ##
296
258
  # Acknowledges receipt of a message.
297
259
  def acknowledge subscription, *ack_ids
298
- execute do
299
- subscriber.acknowledge subscription_path(subscription), ack_ids,
300
- options: default_options
301
- end
260
+ subscriber.acknowledge subscription: subscription_path(subscription), ack_ids: ack_ids
302
261
  end
303
262
 
304
263
  ##
305
264
  # Modifies the PushConfig for a specified subscription.
306
265
  def modify_push_config subscription, endpoint, attributes
307
- subscription = subscription_path subscription
308
266
  # Convert attributes to strings to match the protobuf definition
309
- attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
267
+ attributes = attributes.to_h { |k, v| [String(k), String(v)] }
310
268
  push_config = Google::Cloud::PubSub::V1::PushConfig.new(
311
269
  push_endpoint: endpoint,
312
270
  attributes: attributes
313
271
  )
314
272
 
315
- execute do
316
- subscriber.modify_push_config subscription, push_config,
317
- options: default_options
318
- end
273
+ subscriber.modify_push_config subscription: subscription_path(subscription),
274
+ push_config: push_config
319
275
  end
320
276
 
321
277
  ##
322
278
  # Modifies the ack deadline for a specific message.
323
279
  def modify_ack_deadline subscription, ids, deadline
324
- execute do
325
- subscriber.modify_ack_deadline subscription_path(subscription),
326
- Array(ids),
327
- deadline, options: default_options
328
- end
280
+ subscriber.modify_ack_deadline subscription: subscription_path(subscription),
281
+ ack_ids: Array(ids),
282
+ ack_deadline_seconds: deadline
329
283
  end
330
284
 
331
285
  ##
332
286
  # Lists snapshots by project.
333
287
  def list_snapshots options = {}
334
- call_options = default_options
335
- if (token = options[:token])
336
- call_options = Google::Gax::CallOptions.new(
337
- kwargs: default_headers,
338
- page_token: token
339
- )
340
- end
341
-
342
- execute do
343
- paged_enum = subscriber.list_snapshots project_path(options),
344
- page_size: options[:max],
345
- options: call_options
288
+ paged_enum = subscriber.list_snapshots project: project_path(options),
289
+ page_size: options[:max],
290
+ page_token: options[:token]
346
291
 
347
- paged_enum.page.response
348
- end
292
+ paged_enum.response
349
293
  end
350
294
 
351
295
  ##
352
296
  # Creates a snapshot on a given subscription.
353
297
  def create_snapshot subscription, snapshot_name, labels: nil
354
- name = snapshot_path snapshot_name
355
- execute do
356
- subscriber.create_snapshot name,
357
- subscription_path(subscription),
358
- labels: labels,
359
- options: default_options
360
- end
298
+ subscriber.create_snapshot name: snapshot_path(snapshot_name),
299
+ subscription: subscription_path(subscription),
300
+ labels: labels
361
301
  end
362
302
 
363
303
  def update_snapshot snapshot_obj, *fields
364
304
  mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
365
- execute do
366
- subscriber.update_snapshot \
367
- snapshot_obj, mask, options: default_options
368
- end
305
+ subscriber.update_snapshot snapshot: snapshot_obj, update_mask: mask
369
306
  end
370
307
 
371
308
  ##
372
309
  # Deletes an existing snapshot.
373
310
  # All pending messages in the snapshot are immediately dropped.
374
311
  def delete_snapshot snapshot
375
- execute do
376
- subscriber.delete_snapshot snapshot_path(snapshot),
377
- options: default_options
378
- end
312
+ subscriber.delete_snapshot snapshot: snapshot_path(snapshot)
379
313
  end
380
314
 
381
315
  ##
382
316
  # Adjusts the given subscription to a time or snapshot.
383
317
  def seek subscription, time_or_snapshot
384
- subscription = subscription_path subscription
385
- execute do
386
- if a_time? time_or_snapshot
387
- time = Convert.time_to_timestamp time_or_snapshot
388
- subscriber.seek subscription, time: time, options: default_options
389
- else
390
- if time_or_snapshot.is_a? Snapshot
391
- time_or_snapshot = time_or_snapshot.name
392
- end
393
- subscriber.seek subscription,
394
- snapshot: snapshot_path(time_or_snapshot),
395
- options: default_options
396
- end
318
+ if a_time? time_or_snapshot
319
+ time = Convert.time_to_timestamp time_or_snapshot
320
+ subscriber.seek subscription: subscription, time: time
321
+ else
322
+ time_or_snapshot = time_or_snapshot.name if time_or_snapshot.is_a? Snapshot
323
+ subscriber.seek subscription: subscription_path(subscription),
324
+ snapshot: snapshot_path(time_or_snapshot)
397
325
  end
398
326
  end
399
327
 
400
- def get_topic_policy topic_name, options = {}
401
- execute do
402
- publisher.get_iam_policy topic_path(topic_name, options),
403
- options: default_options
404
- end
328
+ ##
329
+ # Lists schemas in the current (or given) project.
330
+ # @param view [String, Symbol, nil] Possible values:
331
+ # * `BASIC` - Include the name and type of the schema, but not the definition.
332
+ # * `FULL` - Include all Schema object fields.
333
+ #
334
+ def list_schemas view, options = {}
335
+ schema_view = Google::Cloud::PubSub::V1::SchemaView.const_get view.to_s.upcase
336
+ paged_enum = schemas.list_schemas parent: project_path(options),
337
+ view: schema_view,
338
+ page_size: options[:max],
339
+ page_token: options[:token]
340
+
341
+ paged_enum.response
405
342
  end
406
343
 
407
- def set_topic_policy topic_name, new_policy, options = {}
408
- resource = topic_path topic_name, options
344
+ ##
345
+ # Creates a schema in the current (or given) project.
346
+ def create_schema schema_id, type, definition, options = {}
347
+ schema = Google::Cloud::PubSub::V1::Schema.new(
348
+ type: type,
349
+ definition: definition
350
+ )
351
+ schemas.create_schema parent: project_path(options),
352
+ schema: schema,
353
+ schema_id: schema_id
354
+ end
409
355
 
410
- execute do
411
- publisher.set_iam_policy resource, new_policy,
412
- options: default_options
413
- end
356
+ ##
357
+ # Gets the details of a schema.
358
+ # @param view [String, Symbol, nil] The set of fields to return in the response. Possible values:
359
+ # * `BASIC` - Include the name and type of the schema, but not the definition.
360
+ # * `FULL` - Include all Schema object fields.
361
+ #
362
+ def get_schema schema_name, view, options = {}
363
+ schema_view = Google::Cloud::PubSub::V1::SchemaView.const_get view.to_s.upcase
364
+ schemas.get_schema name: schema_path(schema_name, options),
365
+ view: schema_view
414
366
  end
415
367
 
416
- def test_topic_permissions topic_name, permissions, options = {}
417
- resource = topic_path topic_name, options
368
+ ##
369
+ # Delete a schema.
370
+ def delete_schema schema_name
371
+ schemas.delete_schema name: schema_path(schema_name)
372
+ end
418
373
 
419
- execute do
420
- publisher.test_iam_permissions resource, permissions,
421
- options: default_options
374
+ ##
375
+ # Validate the definition string intended for a schema.
376
+ def validate_schema type, definition, options = {}
377
+ schema = Google::Cloud::PubSub::V1::Schema.new(
378
+ type: type,
379
+ definition: definition
380
+ )
381
+ schemas.validate_schema parent: project_path(options),
382
+ schema: schema
383
+ end
384
+
385
+ ##
386
+ # Validates a message against a schema.
387
+ #
388
+ # @param message_data [String] Message to validate against the provided `schema_spec`.
389
+ # @param message_encoding [Google::Cloud::PubSub::V1::Encoding] The encoding expected for messages.
390
+ # @param schema_name [String] Name of the schema against which to validate.
391
+ # @param project [String] Name of the project if not the default project.
392
+ # @param type [String] Ad-hoc schema type against which to validate.
393
+ # @param definition [String] Ad-hoc schema definition against which to validate.
394
+ #
395
+ def validate_message message_data, message_encoding, schema_name: nil, project: nil, type: nil, definition: nil
396
+ if type && definition
397
+ schema = Google::Cloud::PubSub::V1::Schema.new(
398
+ type: type,
399
+ definition: definition
400
+ )
422
401
  end
402
+ schemas.validate_message parent: project_path(project: project),
403
+ name: schema_path(schema_name),
404
+ schema: schema,
405
+ message: message_data,
406
+ encoding: message_encoding
423
407
  end
424
408
 
425
- def get_subscription_policy subscription_name, options = {}
426
- resource = subscription_path subscription_name, options
409
+ # Helper methods
427
410
 
428
- execute do
429
- subscriber.get_iam_policy resource, options: default_options
430
- end
411
+ def get_topic_policy topic_name, options = {}
412
+ iam.get_iam_policy resource: topic_path(topic_name, options)
431
413
  end
432
414
 
433
- def set_subscription_policy subscription_name, new_policy, options = {}
434
- resource = subscription_path subscription_name, options
415
+ def set_topic_policy topic_name, new_policy, options = {}
416
+ iam.set_iam_policy resource: topic_path(topic_name, options), policy: new_policy
417
+ end
435
418
 
436
- execute do
437
- subscriber.set_iam_policy resource, new_policy,
438
- options: default_options
439
- end
419
+ def test_topic_permissions topic_name, permissions, options = {}
420
+ iam.test_iam_permissions resource: topic_path(topic_name, options), permissions: permissions
440
421
  end
441
422
 
442
- def test_subscription_permissions subscription_name,
443
- permissions, options = {}
444
- resource = subscription_path subscription_name, options
423
+ def get_subscription_policy subscription_name, options = {}
424
+ iam.get_iam_policy resource: subscription_path(subscription_name, options)
425
+ end
445
426
 
446
- execute do
447
- subscriber.test_iam_permissions resource, permissions,
448
- options: default_options
449
- end
427
+ def set_subscription_policy subscription_name, new_policy, options = {}
428
+ iam.set_iam_policy resource: subscription_path(subscription_name, options), policy: new_policy
429
+ end
430
+
431
+ def test_subscription_permissions subscription_name, permissions, options = {}
432
+ iam.test_iam_permissions resource: subscription_path(subscription_name, options), permissions: permissions
450
433
  end
451
434
 
452
435
  def project_path options = {}
@@ -465,18 +448,33 @@ module Google
465
448
  end
466
449
 
467
450
  def snapshot_path snapshot_name, options = {}
468
- if snapshot_name.nil? || snapshot_name.to_s.include?("/")
469
- return snapshot_name
470
- end
451
+ return snapshot_name if snapshot_name.nil? || snapshot_name.to_s.include?("/")
471
452
  "#{project_path options}/snapshots/#{snapshot_name}"
472
453
  end
473
454
 
455
+ def schema_path schema_name, options = {}
456
+ return schema_name if schema_name.nil? || schema_name.to_s.include?("/")
457
+ "#{project_path options}/schemas/#{schema_name}"
458
+ end
459
+
474
460
  def inspect
475
- "#<#{self.class.name} #{@project}>"
461
+ "#<#{self.class.name} (#{@project})>"
476
462
  end
477
463
 
478
464
  protected
479
465
 
466
+ # Set the timeout in the client config.
467
+ # Override the default timeout in each individual RPC config as well, since when they are non-nil, these
468
+ # defaults have precedence over the top-level config.timeout. See Gapic::CallOptions#apply_defaults.
469
+ def override_client_config_timeouts config
470
+ config.timeout = timeout
471
+ rpc_names = config.rpcs.methods - Object.methods
472
+ rpc_names.each do |rpc_name|
473
+ rpc = config.rpcs.send rpc_name
474
+ rpc.timeout = timeout if rpc.respond_to? :timeout=
475
+ end
476
+ end
477
+
480
478
  def a_time? obj
481
479
  return false unless obj.respond_to? :to_time
482
480
  # Rails' String#to_time returns nil if the string doesn't parse.
@@ -484,19 +482,37 @@ module Google
484
482
  true
485
483
  end
486
484
 
487
- def default_headers
488
- { "google-cloud-resource-prefix" => "projects/#{@project}" }
485
+ def dead_letter_policy options
486
+ return nil unless options[:dead_letter_topic_name]
487
+ policy = Google::Cloud::PubSub::V1::DeadLetterPolicy.new dead_letter_topic: options[:dead_letter_topic_name]
488
+ if options[:dead_letter_max_delivery_attempts]
489
+ policy.max_delivery_attempts = options[:dead_letter_max_delivery_attempts]
490
+ end
491
+ policy
489
492
  end
490
493
 
491
- def default_options
492
- Google::Gax::CallOptions.new kwargs: default_headers
493
- end
494
+ private
495
+
496
+ def construct_create_subscription_options topic, subscription_name, options
497
+ excess_options = [:deadline,
498
+ :retention,
499
+ :retain_acked,
500
+ :message_ordering,
501
+ :endpoint,
502
+ :dead_letter_topic_name,
503
+ :dead_letter_max_delivery_attempts,
504
+ :dead_letter_topic]
505
+
506
+ new_options = options.filter { |k, v| !v.nil? && !excess_options.include?(k) }
507
+ new_options[:name] = subscription_path subscription_name, options
508
+ new_options[:topic] = topic_path topic
509
+ new_options[:message_retention_duration] = Convert.number_to_duration options[:retention]
510
+ new_options[:dead_letter_policy] = dead_letter_policy options
511
+ new_options[:ack_deadline_seconds] = options[:deadline]
512
+ new_options[:retain_acked_messages] = options[:retain_acked]
513
+ new_options[:enable_message_ordering] = options[:message_ordering]
494
514
 
495
- def execute
496
- yield
497
- rescue Google::Gax::GaxError => e
498
- # GaxError wraps BadStatus, but exposes it as #cause
499
- raise Google::Cloud::Error.from_error(e.cause)
515
+ new_options.compact
500
516
  end
501
517
  end
502
518
  end