google-cloud-pubsub 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +18 -0
  3. data/AUTHENTICATION.md +177 -0
  4. data/CHANGELOG.md +538 -0
  5. data/CODE_OF_CONDUCT.md +40 -0
  6. data/CONTRIBUTING.md +188 -0
  7. data/EMULATOR.md +37 -0
  8. data/LICENSE +201 -0
  9. data/LOGGING.md +32 -0
  10. data/OVERVIEW.md +557 -0
  11. data/TROUBLESHOOTING.md +31 -0
  12. data/lib/google-cloud-pubsub.rb +139 -0
  13. data/lib/google/cloud/pubsub.rb +173 -0
  14. data/lib/google/cloud/pubsub/async_publisher.rb +399 -0
  15. data/lib/google/cloud/pubsub/async_publisher/batch.rb +309 -0
  16. data/lib/google/cloud/pubsub/batch_publisher.rb +99 -0
  17. data/lib/google/cloud/pubsub/convert.rb +91 -0
  18. data/lib/google/cloud/pubsub/credentials.rb +47 -0
  19. data/lib/google/cloud/pubsub/errors.rb +85 -0
  20. data/lib/google/cloud/pubsub/message.rb +158 -0
  21. data/lib/google/cloud/pubsub/policy.rb +187 -0
  22. data/lib/google/cloud/pubsub/project.rb +393 -0
  23. data/lib/google/cloud/pubsub/publish_result.rb +103 -0
  24. data/lib/google/cloud/pubsub/received_message.rb +297 -0
  25. data/lib/google/cloud/pubsub/retry_policy.rb +90 -0
  26. data/lib/google/cloud/pubsub/service.rb +514 -0
  27. data/lib/google/cloud/pubsub/snapshot.rb +202 -0
  28. data/lib/google/cloud/pubsub/snapshot/list.rb +178 -0
  29. data/lib/google/cloud/pubsub/subscriber.rb +399 -0
  30. data/lib/google/cloud/pubsub/subscriber/enumerator_queue.rb +54 -0
  31. data/lib/google/cloud/pubsub/subscriber/inventory.rb +166 -0
  32. data/lib/google/cloud/pubsub/subscriber/sequencer.rb +115 -0
  33. data/lib/google/cloud/pubsub/subscriber/stream.rb +401 -0
  34. data/lib/google/cloud/pubsub/subscriber/timed_unary_buffer.rb +231 -0
  35. data/lib/google/cloud/pubsub/subscription.rb +1279 -0
  36. data/lib/google/cloud/pubsub/subscription/list.rb +205 -0
  37. data/lib/google/cloud/pubsub/subscription/push_config.rb +244 -0
  38. data/lib/google/cloud/pubsub/topic.rb +934 -0
  39. data/lib/google/cloud/pubsub/topic/list.rb +171 -0
  40. data/lib/google/cloud/pubsub/v1.rb +17 -0
  41. data/lib/google/cloud/pubsub/v1/credentials.rb +41 -0
  42. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/iam_policy.rb +21 -0
  43. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/options.rb +21 -0
  44. data/lib/google/cloud/pubsub/v1/doc/google/iam/v1/policy.rb +21 -0
  45. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/duration.rb +91 -0
  46. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/empty.rb +29 -0
  47. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/field_mask.rb +222 -0
  48. data/lib/google/cloud/pubsub/v1/doc/google/protobuf/timestamp.rb +113 -0
  49. data/lib/google/cloud/pubsub/v1/doc/google/pubsub/v1/pubsub.rb +833 -0
  50. data/lib/google/cloud/pubsub/v1/doc/google/type/expr.rb +19 -0
  51. data/lib/google/cloud/pubsub/v1/publisher_client.rb +928 -0
  52. data/lib/google/cloud/pubsub/v1/publisher_client_config.json +120 -0
  53. data/lib/google/cloud/pubsub/v1/subscriber_client.rb +1466 -0
  54. data/lib/google/cloud/pubsub/v1/subscriber_client_config.json +153 -0
  55. data/lib/google/cloud/pubsub/version.rb +24 -0
  56. data/lib/google/pubsub/v1/pubsub_pb.rb +269 -0
  57. data/lib/google/pubsub/v1/pubsub_services_pb.rb +215 -0
  58. metadata +337 -0
@@ -0,0 +1,297 @@
1
+ # Copyright 2015 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
+
16
+ require "google/cloud/errors"
17
+ require "google/cloud/pubsub/message"
18
+
19
+ module Google
20
+ module Cloud
21
+ module PubSub
22
+ ##
23
+ # # ReceivedMessage
24
+ #
25
+ # Represents a Pub/Sub {Message} that can be acknowledged or delayed.
26
+ #
27
+ # @example
28
+ # require "google/cloud/pubsub"
29
+ #
30
+ # pubsub = Google::Cloud::PubSub.new
31
+ #
32
+ # sub = pubsub.subscription "my-topic-sub"
33
+ # subscriber = sub.listen do |received_message|
34
+ # puts received_message.message.data
35
+ # received_message.acknowledge!
36
+ # end
37
+ #
38
+ # # Start background threads that will call the block passed to listen.
39
+ # subscriber.start
40
+ #
41
+ # # Shut down the subscriber when ready to stop receiving messages.
42
+ # subscriber.stop.wait!
43
+ #
44
+ class ReceivedMessage
45
+ ##
46
+ # @private The {Subscription} object.
47
+ attr_accessor :subscription
48
+
49
+ ##
50
+ # @private The gRPC Google::Cloud::PubSub::V1::ReceivedMessage object.
51
+ attr_accessor :grpc
52
+
53
+ ##
54
+ # @private Create an empty {Subscription} object.
55
+ def initialize
56
+ @subscription = nil
57
+ @grpc = Google::Cloud::PubSub::V1::ReceivedMessage.new
58
+ end
59
+
60
+ ##
61
+ # The acknowledgment ID for the message.
62
+ def ack_id
63
+ @grpc.ack_id
64
+ end
65
+
66
+ ##
67
+ # Returns the delivery attempt counter for the message. If a dead letter policy is not set on the subscription,
68
+ # this will be `nil`. See {Topic#subscribe}, {Subscription#dead_letter_topic=} and
69
+ # {Subscription#dead_letter_max_delivery_attempts=}.
70
+ #
71
+ # The delivery attempt counter is `1 + (the sum of number of NACKs and number of ack_deadline exceeds)` for the
72
+ # message.
73
+ #
74
+ # A NACK is any call to `ModifyAckDeadline` with a `0` deadline. An `ack_deadline` exceeds event is whenever a
75
+ # message is not acknowledged within `ack_deadline`. Note that `ack_deadline` is initially
76
+ # `Subscription.ackDeadlineSeconds`, but may get extended automatically by the client library.
77
+ #
78
+ # The first delivery of a given message will have this value as `1`. The value is calculated at best effort and
79
+ # is approximate.
80
+ #
81
+ # @return [Integer, nil] A delivery attempt value of `1` or greater, or `nil` if a dead letter policy is not set
82
+ # on the subscription.
83
+ #
84
+ # @example
85
+ # require "google/cloud/pubsub"
86
+ #
87
+ # pubsub = Google::Cloud::PubSub.new
88
+ #
89
+ # topic = pubsub.topic "my-topic"
90
+ # dead_letter_topic = pubsub.topic "my-dead-letter-topic", skip_lookup: true
91
+ # sub = topic.subscribe "my-topic-sub",
92
+ # dead_letter_topic: dead_letter_topic,
93
+ # dead_letter_max_delivery_attempts: 10
94
+ #
95
+ # subscriber = sub.listen do |received_message|
96
+ # puts received_message.message.delivery_attempt
97
+ # end
98
+ #
99
+ def delivery_attempt
100
+ return nil if @grpc.delivery_attempt && @grpc.delivery_attempt < 1
101
+ @grpc.delivery_attempt
102
+ end
103
+
104
+ ##
105
+ # The received message.
106
+ def message
107
+ Message.from_grpc @grpc.message
108
+ end
109
+ alias msg message
110
+
111
+ ##
112
+ # The received message payload. This data is a list of bytes encoded as
113
+ # ASCII-8BIT.
114
+ def data
115
+ message.data
116
+ end
117
+
118
+ ##
119
+ # Optional attributes for the received message.
120
+ def attributes
121
+ message.attributes
122
+ end
123
+
124
+ ##
125
+ # The ID of the received message, assigned by the server at publication
126
+ # time. Guaranteed to be unique within the topic.
127
+ def message_id
128
+ message.message_id
129
+ end
130
+ alias msg_id message_id
131
+
132
+ ##
133
+ # Identifies related messages for which publish order should be
134
+ # respected.
135
+ #
136
+ # Google Cloud Pub/Sub ordering keys provide the ability to ensure
137
+ # related messages are sent to subscribers in the order in which they
138
+ # were published. Messages can be tagged with an ordering key, a string
139
+ # that identifies related messages for which publish order should be
140
+ # respected. The service guarantees that, for a given ordering key and
141
+ # publisher, messages are sent to subscribers in the order in which they
142
+ # were published. Ordering does not require sacrificing high throughput
143
+ # or scalability, as the service automatically distributes messages for
144
+ # different ordering keys across subscribers.
145
+ #
146
+ # See {Topic#publish_async} and {Subscription#listen}.
147
+ #
148
+ # @return [String]
149
+ #
150
+ def ordering_key
151
+ message.ordering_key
152
+ end
153
+
154
+ ##
155
+ # The time at which the message was published.
156
+ def published_at
157
+ message.published_at
158
+ end
159
+ alias publish_time published_at
160
+
161
+ ##
162
+ # Acknowledges receipt of the message.
163
+ #
164
+ # @example
165
+ # require "google/cloud/pubsub"
166
+ #
167
+ # pubsub = Google::Cloud::PubSub.new
168
+ #
169
+ # sub = pubsub.subscription "my-topic-sub"
170
+ # subscriber = sub.listen do |received_message|
171
+ # puts received_message.message.data
172
+ #
173
+ # received_message.acknowledge!
174
+ # end
175
+ #
176
+ # # Start background threads that will call block passed to listen.
177
+ # subscriber.start
178
+ #
179
+ # # Shut down the subscriber when ready to stop receiving messages.
180
+ # subscriber.stop.wait!
181
+ #
182
+ def acknowledge!
183
+ ensure_subscription!
184
+ subscription.acknowledge ack_id
185
+ end
186
+ alias ack! acknowledge!
187
+
188
+ ##
189
+ # Modifies the acknowledge deadline for the message.
190
+ #
191
+ # This indicates that more time is needed to process the message, or to
192
+ # make the message available for redelivery.
193
+ #
194
+ # @param [Integer] new_deadline The new ack deadline in seconds from the
195
+ # time this request is sent to the Pub/Sub system. Must be >= 0. For
196
+ # example, if the value is `10`, the new ack deadline will expire 10
197
+ # seconds after the call is made. Specifying `0` may immediately make
198
+ # the message available for another pull request.
199
+ #
200
+ # @example
201
+ # require "google/cloud/pubsub"
202
+ #
203
+ # pubsub = Google::Cloud::PubSub.new
204
+ #
205
+ # sub = pubsub.subscription "my-topic-sub"
206
+ # subscriber = sub.listen do |received_message|
207
+ # puts received_message.message.data
208
+ #
209
+ # # Delay for 2 minutes
210
+ # received_message.modify_ack_deadline! 120
211
+ # end
212
+ #
213
+ # # Start background threads that will call block passed to listen.
214
+ # subscriber.start
215
+ #
216
+ # # Shut down the subscriber when ready to stop receiving messages.
217
+ # subscriber.stop.wait!
218
+ #
219
+ def modify_ack_deadline! new_deadline
220
+ ensure_subscription!
221
+ subscription.modify_ack_deadline new_deadline, ack_id
222
+ end
223
+
224
+ ##
225
+ # Resets the acknowledge deadline for the message without acknowledging
226
+ # it.
227
+ #
228
+ # This will make the message available for redelivery.
229
+ #
230
+ # @example
231
+ # require "google/cloud/pubsub"
232
+ #
233
+ # pubsub = Google::Cloud::PubSub.new
234
+ #
235
+ # sub = pubsub.subscription "my-topic-sub"
236
+ # subscriber = sub.listen do |received_message|
237
+ # puts received_message.message.data
238
+ #
239
+ # # Release message back to the API.
240
+ # received_message.reject!
241
+ # end
242
+ #
243
+ # # Start background threads that will call block passed to listen.
244
+ # subscriber.start
245
+ #
246
+ # # Shut down the subscriber when ready to stop receiving messages.
247
+ # subscriber.stop.wait!
248
+ #
249
+ def reject!
250
+ modify_ack_deadline! 0
251
+ end
252
+ alias nack! reject!
253
+ alias ignore! reject!
254
+
255
+ # @private
256
+ def hash
257
+ @grpc.hash
258
+ end
259
+
260
+ # @private
261
+ def eql? other
262
+ return false unless other.is_a? self.class
263
+ @grpc.hash == other.hash
264
+ end
265
+ # @private
266
+ alias == eql?
267
+
268
+ # @private
269
+ def <=> other
270
+ return nil unless other.is_a? self.class
271
+ other_grpc = other.instance_variable_get :@grpc
272
+ @grpc <=> other_grpc
273
+ end
274
+
275
+ ##
276
+ # @private New ReceivedMessage from a
277
+ # Google::Cloud::PubSub::V1::ReceivedMessage object.
278
+ def self.from_grpc grpc, subscription
279
+ new.tap do |rm|
280
+ rm.grpc = grpc
281
+ rm.subscription = subscription
282
+ end
283
+ end
284
+
285
+ protected
286
+
287
+ ##
288
+ # Raise an error unless an active subscription is available.
289
+ def ensure_subscription!
290
+ raise "Must have active subscription" unless subscription
291
+ end
292
+ end
293
+ end
294
+
295
+ Pubsub = PubSub unless const_defined? :Pubsub
296
+ end
297
+ end
@@ -0,0 +1,90 @@
1
+ # Copyright 2016 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
+
16
+ require "google/cloud/errors"
17
+
18
+ module Google
19
+ module Cloud
20
+ module PubSub
21
+ ##
22
+ # # RetryPolicy
23
+ #
24
+ # An immutable Retry Policy value object that specifies how Cloud Pub/Sub retries message delivery.
25
+ #
26
+ # Retry delay will be exponential based on provided minimum and maximum backoffs. (See [Exponential
27
+ # backoff](https://en.wikipedia.org/wiki/Exponential_backoff).)
28
+ #
29
+ # Retry Policy will be triggered on NACKs or acknowledgement deadline exceeded events for a given message.
30
+ #
31
+ # Retry Policy is implemented on a best effort basis. At times, the delay between consecutive deliveries may not
32
+ # match the configuration. That is, delay can be more or less than configured backoff.
33
+ #
34
+ # **EXPERIMENTAL:** This API might be changed in backward-incompatible ways and is not recommended for production
35
+ # use. It is not subject to any SLA or deprecation policy.
36
+ #
37
+ # @attr [Numeric] minimum_backoff The minimum delay between consecutive deliveries of a given message. Value
38
+ # should be between 0 and 600 seconds. The default value is 10 seconds.
39
+ # @attr [Numeric] maximum_backoff The maximum delay between consecutive deliveries of a given message. Value
40
+ # should be between 0 and 600 seconds. The default value is 600 seconds.
41
+ #
42
+ # @example
43
+ # require "google/cloud/pubsub"
44
+ #
45
+ # pubsub = Google::Cloud::PubSub.new
46
+ #
47
+ # sub = pubsub.subscription "my-topic-sub"
48
+ #
49
+ # sub.retry_policy = Google::Cloud::PubSub::RetryPolicy.new minimum_backoff: 5, maximum_backoff: 300
50
+ #
51
+ # sub.retry_policy.minimum_backoff #=> 5
52
+ # sub.retry_policy.maximum_backoff #=> 300
53
+ #
54
+ class RetryPolicy
55
+ attr_reader :minimum_backoff, :maximum_backoff
56
+
57
+ ##
58
+ # Creates a new, immutable RetryPolicy value object.
59
+ #
60
+ # @attr [Numeric, nil] minimum_backoff The minimum delay between consecutive deliveries of a given message.
61
+ # Value should be between 0 and 600 seconds. If `nil` is provided, the default value is 10 seconds.
62
+ # @attr [Numeric, nil] maximum_backoff The maximum delay between consecutive deliveries of a given message.
63
+ # Value should be between 0 and 600 seconds. If `nil` is provided, the default value is 600 seconds.
64
+ #
65
+ def initialize minimum_backoff: nil, maximum_backoff: nil
66
+ @minimum_backoff = minimum_backoff
67
+ @maximum_backoff = maximum_backoff
68
+ end
69
+
70
+ ##
71
+ # @private Convert the RetryPolicy to a Google::Cloud::PubSub::V1::RetryPolicy object.
72
+ def to_grpc
73
+ Google::Cloud::PubSub::V1::RetryPolicy.new(
74
+ minimum_backoff: Convert.number_to_duration(minimum_backoff),
75
+ maximum_backoff: Convert.number_to_duration(maximum_backoff)
76
+ )
77
+ end
78
+
79
+ ##
80
+ # @private New RetryPolicy from a Google::Cloud::PubSub::V1::RetryPolicy object.
81
+ def self.from_grpc grpc
82
+ new(
83
+ minimum_backoff: Convert.duration_to_number(grpc.minimum_backoff),
84
+ maximum_backoff: Convert.duration_to_number(grpc.maximum_backoff)
85
+ )
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,514 @@
1
+ # Copyright 2016 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
+
16
+ require "google/cloud/errors"
17
+ require "google/cloud/pubsub/credentials"
18
+ require "google/cloud/pubsub/convert"
19
+ require "google/cloud/pubsub/version"
20
+ require "google/cloud/pubsub/v1"
21
+ require "google/gax/errors"
22
+ require "securerandom"
23
+
24
+ module Google
25
+ module Cloud
26
+ module PubSub
27
+ ##
28
+ # @private Represents the GAX Pub/Sub service, including all the API
29
+ # methods.
30
+ class Service
31
+ attr_accessor :project, :credentials, :host, :timeout, :client_config
32
+ ###
33
+ # The same client_id is used across all streaming pull connections that are created by this client. This is
34
+ # intentional, as it indicates to the server that any guarantees, such as message ordering, made for a stream
35
+ # that is disconnected will be made for the stream that is created to replace it. The attr_accessor allows the
36
+ # value to be replaced for unit testing.
37
+ attr_accessor :client_id
38
+
39
+ ##
40
+ # Creates a new Service instance.
41
+ def initialize project, credentials, host: nil, timeout: nil,
42
+ client_config: nil
43
+ @project = project
44
+ @credentials = credentials
45
+ @host = host || V1::PublisherClient::SERVICE_ADDRESS
46
+ @timeout = timeout
47
+ @client_config = client_config || {}
48
+ @client_id = SecureRandom.uuid.freeze
49
+ end
50
+
51
+ def channel
52
+ require "grpc"
53
+ GRPC::Core::Channel.new host, chan_args, chan_creds
54
+ end
55
+
56
+ def chan_args
57
+ { "grpc.max_send_message_length" => -1,
58
+ "grpc.max_receive_message_length" => -1,
59
+ "grpc.keepalive_time_ms" => 300_000,
60
+ "grpc.service_config_disable_resolution" => 1 }
61
+ end
62
+
63
+ def chan_creds
64
+ return credentials if insecure?
65
+ require "grpc"
66
+ GRPC::Core::ChannelCredentials.new.compose GRPC::Core::CallCredentials.new credentials.client.updater_proc
67
+ end
68
+
69
+ def subscriber
70
+ return mocked_subscriber if mocked_subscriber
71
+ @subscriber ||= begin
72
+ V1::SubscriberClient.new(
73
+ credentials: channel,
74
+ timeout: timeout,
75
+ client_config: client_config,
76
+ lib_name: "gccl",
77
+ lib_version: Google::Cloud::PubSub::VERSION
78
+ )
79
+ end
80
+ end
81
+ attr_accessor :mocked_subscriber
82
+
83
+ def publisher
84
+ return mocked_publisher if mocked_publisher
85
+ @publisher ||= begin
86
+ V1::PublisherClient.new(
87
+ credentials: channel,
88
+ timeout: timeout,
89
+ client_config: client_config,
90
+ lib_name: "gccl",
91
+ lib_version: Google::Cloud::PubSub::VERSION
92
+ )
93
+ end
94
+ end
95
+ attr_accessor :mocked_publisher
96
+
97
+ def insecure?
98
+ credentials == :this_channel_is_insecure
99
+ end
100
+
101
+ ##
102
+ # Gets the configuration of a topic.
103
+ # Since the topic only has the name attribute,
104
+ # this method is only useful to check the existence of a topic.
105
+ # If other attributes are added in the future,
106
+ # they will be returned here.
107
+ def get_topic topic_name, options = {}
108
+ execute do
109
+ publisher.get_topic topic_path(topic_name, options),
110
+ options: default_options
111
+ end
112
+ end
113
+
114
+ ##
115
+ # Lists matching topics.
116
+ def list_topics options = {}
117
+ call_options = default_options
118
+ if (token = options[:token])
119
+ call_options = Google::Gax::CallOptions.new(
120
+ kwargs: default_headers,
121
+ page_token: token
122
+ )
123
+ end
124
+
125
+ execute do
126
+ paged_enum = publisher.list_topics project_path(options),
127
+ page_size: options[:max],
128
+ options: call_options
129
+
130
+ paged_enum.page.response
131
+ end
132
+ end
133
+
134
+ ##
135
+ # Creates the given topic with the given name.
136
+ def create_topic topic_name, labels: nil, kms_key_name: nil, persistence_regions: nil, options: {}
137
+ if persistence_regions
138
+ message_storage_policy = {
139
+ allowed_persistence_regions: Array(persistence_regions)
140
+ }
141
+ end
142
+
143
+ execute do
144
+ publisher.create_topic \
145
+ topic_path(topic_name, options),
146
+ labels: labels,
147
+ kms_key_name: kms_key_name,
148
+ message_storage_policy: message_storage_policy,
149
+ options: default_options
150
+ end
151
+ end
152
+
153
+ def update_topic topic_obj, *fields
154
+ mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
155
+ execute do
156
+ publisher.update_topic topic_obj, mask, options: default_options
157
+ end
158
+ end
159
+
160
+ ##
161
+ # Deletes the topic with the given name. All subscriptions to this topic
162
+ # are also deleted. Raises GRPC status code 5 if the topic does not
163
+ # exist. After a topic is deleted, a new topic may be created with the
164
+ # same name.
165
+ def delete_topic topic_name
166
+ execute do
167
+ publisher.delete_topic topic_path(topic_name),
168
+ options: default_options
169
+ end
170
+ end
171
+
172
+ ##
173
+ # Adds one or more messages to the topic.
174
+ # Raises GRPC status code 5 if the topic does not exist.
175
+ # The messages parameter is an array of arrays.
176
+ # The first element is the data, second is attributes hash.
177
+ def publish topic, messages
178
+ execute do
179
+ publisher.publish topic_path(topic), messages,
180
+ options: default_options
181
+ end
182
+ end
183
+
184
+ ##
185
+ # Gets the details of a subscription.
186
+ def get_subscription subscription_name, options = {}
187
+ subscription = subscription_path subscription_name, options
188
+ execute do
189
+ subscriber.get_subscription subscription, options: default_options
190
+ end
191
+ end
192
+
193
+ ##
194
+ # Lists matching subscriptions by project and topic.
195
+ def list_topics_subscriptions topic, options = {}
196
+ call_options = default_options
197
+ if (token = options[:token])
198
+ call_options = Google::Gax::CallOptions.new(
199
+ kwargs: default_headers,
200
+ page_token: token
201
+ )
202
+ end
203
+
204
+ execute do
205
+ paged_enum = publisher.list_topic_subscriptions \
206
+ topic_path(topic, options),
207
+ page_size: options[:max],
208
+ options: call_options
209
+
210
+ paged_enum.page.response
211
+ end
212
+ end
213
+
214
+ ##
215
+ # Lists matching subscriptions by project.
216
+ def list_subscriptions options = {}
217
+ call_options = default_options
218
+ if (token = options[:token])
219
+ call_options = Google::Gax::CallOptions.new(
220
+ kwargs: default_headers,
221
+ page_token: token
222
+ )
223
+ end
224
+
225
+ execute do
226
+ paged_enum = subscriber.list_subscriptions project_path(options),
227
+ page_size: options[:max],
228
+ options: call_options
229
+
230
+ paged_enum.page.response
231
+ end
232
+ end
233
+
234
+ ##
235
+ # Creates a subscription on a given topic for a given subscriber.
236
+ def create_subscription topic, subscription_name, options = {}
237
+ name = subscription_path subscription_name, options
238
+ topic = topic_path topic
239
+ push_config = if options[:endpoint]
240
+ Google::Cloud::PubSub::V1::PushConfig.new \
241
+ push_endpoint: options[:endpoint],
242
+ attributes: (options[:attributes] || {}).to_h
243
+ end
244
+ mrd = Convert.number_to_duration options[:retention]
245
+ execute do
246
+ subscriber.create_subscription \
247
+ name, topic,
248
+ push_config: push_config,
249
+ ack_deadline_seconds: options[:deadline],
250
+ retain_acked_messages: options[:retain_acked],
251
+ message_retention_duration: mrd,
252
+ labels: options[:labels],
253
+ enable_message_ordering: options[:message_ordering],
254
+ filter: options[:filter],
255
+ dead_letter_policy: dead_letter_policy(options),
256
+ retry_policy: options[:retry_policy],
257
+ options: default_options
258
+ end
259
+ end
260
+
261
+ def update_subscription subscription_obj, *fields
262
+ mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
263
+ execute do
264
+ subscriber.update_subscription subscription_obj, mask, options: default_options
265
+ end
266
+ end
267
+
268
+ ##
269
+ # Deletes an existing subscription.
270
+ # All pending messages in the subscription are immediately dropped.
271
+ def delete_subscription subscription
272
+ execute do
273
+ subscriber.delete_subscription subscription_path(subscription),
274
+ options: default_options
275
+ end
276
+ end
277
+
278
+ ##
279
+ # Pulls a single message from the server.
280
+ def pull subscription, options = {}
281
+ subscription = subscription_path subscription, options
282
+ max_messages = options.fetch(:max, 100).to_i
283
+ return_immediately = !(!options.fetch(:immediate, true))
284
+
285
+ execute do
286
+ subscriber.pull subscription,
287
+ max_messages,
288
+ return_immediately: return_immediately,
289
+ options: default_options
290
+ end
291
+ end
292
+
293
+ def streaming_pull request_enum
294
+ execute do
295
+ subscriber.streaming_pull request_enum, options: default_options
296
+ end
297
+ end
298
+
299
+ ##
300
+ # Acknowledges receipt of a message.
301
+ def acknowledge subscription, *ack_ids
302
+ execute do
303
+ subscriber.acknowledge subscription_path(subscription), ack_ids,
304
+ options: default_options
305
+ end
306
+ end
307
+
308
+ ##
309
+ # Modifies the PushConfig for a specified subscription.
310
+ def modify_push_config subscription, endpoint, attributes
311
+ subscription = subscription_path subscription
312
+ # Convert attributes to strings to match the protobuf definition
313
+ attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
314
+ push_config = Google::Cloud::PubSub::V1::PushConfig.new(
315
+ push_endpoint: endpoint,
316
+ attributes: attributes
317
+ )
318
+
319
+ execute do
320
+ subscriber.modify_push_config subscription, push_config,
321
+ options: default_options
322
+ end
323
+ end
324
+
325
+ ##
326
+ # Modifies the ack deadline for a specific message.
327
+ def modify_ack_deadline subscription, ids, deadline
328
+ execute do
329
+ subscriber.modify_ack_deadline subscription_path(subscription),
330
+ Array(ids),
331
+ deadline, options: default_options
332
+ end
333
+ end
334
+
335
+ ##
336
+ # Lists snapshots by project.
337
+ def list_snapshots options = {}
338
+ call_options = default_options
339
+ if (token = options[:token])
340
+ call_options = Google::Gax::CallOptions.new(
341
+ kwargs: default_headers,
342
+ page_token: token
343
+ )
344
+ end
345
+
346
+ execute do
347
+ paged_enum = subscriber.list_snapshots project_path(options),
348
+ page_size: options[:max],
349
+ options: call_options
350
+
351
+ paged_enum.page.response
352
+ end
353
+ end
354
+
355
+ ##
356
+ # Creates a snapshot on a given subscription.
357
+ def create_snapshot subscription, snapshot_name, labels: nil
358
+ name = snapshot_path snapshot_name
359
+ execute do
360
+ subscriber.create_snapshot name,
361
+ subscription_path(subscription),
362
+ labels: labels,
363
+ options: default_options
364
+ end
365
+ end
366
+
367
+ def update_snapshot snapshot_obj, *fields
368
+ mask = Google::Protobuf::FieldMask.new paths: fields.map(&:to_s)
369
+ execute do
370
+ subscriber.update_snapshot snapshot_obj, mask, options: default_options
371
+ end
372
+ end
373
+
374
+ ##
375
+ # Deletes an existing snapshot.
376
+ # All pending messages in the snapshot are immediately dropped.
377
+ def delete_snapshot snapshot
378
+ execute do
379
+ subscriber.delete_snapshot snapshot_path(snapshot),
380
+ options: default_options
381
+ end
382
+ end
383
+
384
+ ##
385
+ # Adjusts the given subscription to a time or snapshot.
386
+ def seek subscription, time_or_snapshot
387
+ subscription = subscription_path subscription
388
+ execute do
389
+ if a_time? time_or_snapshot
390
+ time = Convert.time_to_timestamp time_or_snapshot
391
+ subscriber.seek subscription, time: time, options: default_options
392
+ else
393
+ time_or_snapshot = time_or_snapshot.name if time_or_snapshot.is_a? Snapshot
394
+ subscriber.seek subscription,
395
+ snapshot: snapshot_path(time_or_snapshot),
396
+ options: default_options
397
+ end
398
+ end
399
+ end
400
+
401
+ def get_topic_policy topic_name, options = {}
402
+ execute do
403
+ publisher.get_iam_policy topic_path(topic_name, options),
404
+ options: default_options
405
+ end
406
+ end
407
+
408
+ def set_topic_policy topic_name, new_policy, options = {}
409
+ resource = topic_path topic_name, options
410
+
411
+ execute do
412
+ publisher.set_iam_policy resource, new_policy,
413
+ options: default_options
414
+ end
415
+ end
416
+
417
+ def test_topic_permissions topic_name, permissions, options = {}
418
+ resource = topic_path topic_name, options
419
+
420
+ execute do
421
+ publisher.test_iam_permissions resource, permissions,
422
+ options: default_options
423
+ end
424
+ end
425
+
426
+ def get_subscription_policy subscription_name, options = {}
427
+ resource = subscription_path subscription_name, options
428
+
429
+ execute do
430
+ subscriber.get_iam_policy resource, options: default_options
431
+ end
432
+ end
433
+
434
+ def set_subscription_policy subscription_name, new_policy, options = {}
435
+ resource = subscription_path subscription_name, options
436
+
437
+ execute do
438
+ subscriber.set_iam_policy resource, new_policy,
439
+ options: default_options
440
+ end
441
+ end
442
+
443
+ def test_subscription_permissions subscription_name,
444
+ permissions, options = {}
445
+ resource = subscription_path subscription_name, options
446
+
447
+ execute do
448
+ subscriber.test_iam_permissions resource, permissions,
449
+ options: default_options
450
+ end
451
+ end
452
+
453
+ def project_path options = {}
454
+ project_name = options[:project] || project
455
+ "projects/#{project_name}"
456
+ end
457
+
458
+ def topic_path topic_name, options = {}
459
+ return topic_name if topic_name.to_s.include? "/"
460
+ "#{project_path options}/topics/#{topic_name}"
461
+ end
462
+
463
+ def subscription_path subscription_name, options = {}
464
+ return subscription_name if subscription_name.to_s.include? "/"
465
+ "#{project_path options}/subscriptions/#{subscription_name}"
466
+ end
467
+
468
+ def snapshot_path snapshot_name, options = {}
469
+ return snapshot_name if snapshot_name.nil? || snapshot_name.to_s.include?("/")
470
+ "#{project_path options}/snapshots/#{snapshot_name}"
471
+ end
472
+
473
+ def inspect
474
+ "#<#{self.class.name} (#{@project})>"
475
+ end
476
+
477
+ protected
478
+
479
+ def a_time? obj
480
+ return false unless obj.respond_to? :to_time
481
+ # Rails' String#to_time returns nil if the string doesn't parse.
482
+ return false if obj.to_time.nil?
483
+ true
484
+ end
485
+
486
+ def dead_letter_policy options
487
+ return nil unless options[:dead_letter_topic_name]
488
+ policy = Google::Cloud::PubSub::V1::DeadLetterPolicy.new dead_letter_topic: options[:dead_letter_topic_name]
489
+ if options[:dead_letter_max_delivery_attempts]
490
+ policy.max_delivery_attempts = options[:dead_letter_max_delivery_attempts]
491
+ end
492
+ policy
493
+ end
494
+
495
+ def default_headers
496
+ { "google-cloud-resource-prefix" => "projects/#{@project}" }
497
+ end
498
+
499
+ def default_options
500
+ Google::Gax::CallOptions.new kwargs: default_headers
501
+ end
502
+
503
+ def execute
504
+ yield
505
+ rescue Google::Gax::GaxError => e
506
+ # GaxError wraps BadStatus, but exposes it as #cause
507
+ raise Google::Cloud::Error.from_error(e.cause)
508
+ end
509
+ end
510
+ end
511
+
512
+ Pubsub = PubSub unless const_defined? :Pubsub
513
+ end
514
+ end