google-cloud-pubsub 1.9.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 +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