google-cloud-pubsub 0.20.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.
@@ -0,0 +1,162 @@
1
+ # Copyright 2015 Google Inc. All rights reserved.
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
+ # http://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"
29
+ #
30
+ # gcloud = Google::Cloud.new
31
+ # pubsub = gcloud.pubsub
32
+ #
33
+ # sub = pubsub.subscription "my-topic-sub"
34
+ # received_message = sub.pull.first
35
+ # if received_message
36
+ # puts received_message.message.data
37
+ # received_message.acknowledge!
38
+ # end
39
+ #
40
+ class ReceivedMessage
41
+ ##
42
+ # @private The {Subscription} object.
43
+ attr_accessor :subscription
44
+
45
+ ##
46
+ # @private The gRPC Google::Pubsub::V1::ReceivedMessage object.
47
+ attr_accessor :grpc
48
+
49
+ ##
50
+ # @private Create an empty {Subscription} object.
51
+ def initialize
52
+ @subscription = nil
53
+ @grpc = Google::Pubsub::V1::ReceivedMessage.new
54
+ end
55
+
56
+ ##
57
+ # The acknowledgment ID for the message.
58
+ def ack_id
59
+ @grpc.ack_id
60
+ end
61
+
62
+ ##
63
+ # The received message.
64
+ def message
65
+ Message.from_grpc @grpc.message
66
+ end
67
+ alias_method :msg, :message
68
+
69
+ ##
70
+ # The received message's data.
71
+ def data
72
+ message.data
73
+ end
74
+
75
+ ##
76
+ # The received message's attributes.
77
+ def attributes
78
+ message.attributes
79
+ end
80
+
81
+ ##
82
+ # The ID of the received message, assigned by the server at publication
83
+ # time. Guaranteed to be unique within the topic.
84
+ def message_id
85
+ message.message_id
86
+ end
87
+ alias_method :msg_id, :message_id
88
+
89
+ ##
90
+ # Acknowledges receipt of the message.
91
+ #
92
+ # @example
93
+ # require "google/cloud"
94
+ #
95
+ # gcloud = Google::Cloud.new
96
+ # pubsub = gcloud.pubsub
97
+ #
98
+ # sub = pubsub.subscription "my-topic-sub"
99
+ # received_message = sub.pull.first
100
+ # if received_message
101
+ # puts received_message.message.data
102
+ # received_message.acknowledge!
103
+ # end
104
+ #
105
+ def acknowledge!
106
+ ensure_subscription!
107
+ subscription.acknowledge ack_id
108
+ end
109
+ alias_method :ack!, :acknowledge!
110
+
111
+ ##
112
+ # Modifies the acknowledge deadline for the message.
113
+ #
114
+ # This indicates that more time is needed to process the message, or to
115
+ # make the message available for redelivery.
116
+ #
117
+ # @param [Integer] new_deadline The new ack deadline in seconds from the
118
+ # time this request is sent to the Pub/Sub system. Must be >= 0. For
119
+ # example, if the value is `10`, the new ack deadline will expire 10
120
+ # seconds after the call is made. Specifying `0` may immediately make
121
+ # the message available for another pull request.
122
+ #
123
+ # @example
124
+ # require "google/cloud"
125
+ #
126
+ # gcloud = Google::Cloud.new
127
+ # pubsub = gcloud.pubsub
128
+ #
129
+ # sub = pubsub.subscription "my-topic-sub"
130
+ # received_message = sub.pull.first
131
+ # if received_message
132
+ # puts received_message.message.data
133
+ # # Delay for 2 minutes
134
+ # received_message.delay! 120
135
+ # end
136
+ #
137
+ def delay! new_deadline
138
+ ensure_subscription!
139
+ subscription.delay new_deadline, ack_id
140
+ end
141
+
142
+ ##
143
+ # @private New ReceivedMessage from a
144
+ # Google::Pubsub::V1::ReceivedMessage object.
145
+ def self.from_grpc grpc, subscription
146
+ new.tap do |rm|
147
+ rm.grpc = grpc
148
+ rm.subscription = subscription
149
+ end
150
+ end
151
+
152
+ protected
153
+
154
+ ##
155
+ # Raise an error unless an active subscription is available.
156
+ def ensure_subscription!
157
+ fail "Must have active subscription" unless subscription
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,340 @@
1
+ # Copyright 2016 Google Inc. All rights reserved.
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
+ # http://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/core/grpc_backoff"
18
+ require "google/pubsub/v1/pubsub_services_pb"
19
+ require "google/iam/v1/iam_policy_services"
20
+ require "google/cloud/core/grpc_utils"
21
+ require "json"
22
+
23
+ module Google
24
+ module Cloud
25
+ module Pubsub
26
+ ##
27
+ # @private Represents the gRPC Pub/Sub service, including all the API
28
+ # methods.
29
+ class Service
30
+ attr_accessor :project, :credentials, :host, :retries, :timeout
31
+
32
+ ##
33
+ # Creates a new Service instance.
34
+ def initialize project, credentials, host: nil, retries: nil,
35
+ timeout: nil
36
+ @project = project
37
+ @credentials = credentials
38
+ @host = host || "pubsub.googleapis.com"
39
+ @retries = retries
40
+ @timeout = timeout
41
+ end
42
+
43
+ def creds
44
+ return credentials if insecure?
45
+ GRPC::Core::ChannelCredentials.new.compose \
46
+ GRPC::Core::CallCredentials.new credentials.client.updater_proc
47
+ end
48
+
49
+ def subscriber
50
+ return mocked_subscriber if mocked_subscriber
51
+ @subscriber ||= Google::Pubsub::V1::Subscriber::Stub.new(
52
+ host, creds, timeout: timeout)
53
+ end
54
+ attr_accessor :mocked_subscriber
55
+
56
+ def publisher
57
+ return mocked_publisher if mocked_publisher
58
+ @publisher ||= Google::Pubsub::V1::Publisher::Stub.new(
59
+ host, creds, timeout: timeout)
60
+ end
61
+ attr_accessor :mocked_publisher
62
+
63
+ def iam
64
+ return mocked_iam if mocked_iam
65
+ @iam ||= Google::Iam::V1::IAMPolicy::Stub.new(
66
+ host, creds, timeout: timeout)
67
+ end
68
+ attr_accessor :mocked_iam
69
+
70
+ def insecure?
71
+ credentials == :this_channel_is_insecure
72
+ end
73
+
74
+ ##
75
+ # Gets the configuration of a topic.
76
+ # Since the topic only has the name attribute,
77
+ # this method is only useful to check the existence of a topic.
78
+ # If other attributes are added in the future,
79
+ # they will be returned here.
80
+ def get_topic topic_name, options = {}
81
+ topic_req = Google::Pubsub::V1::GetTopicRequest.new.tap do |r|
82
+ r.topic = topic_path(topic_name, options)
83
+ end
84
+
85
+ execute { publisher.get_topic topic_req }
86
+ end
87
+
88
+ ##
89
+ # Lists matching topics.
90
+ def list_topics options = {}
91
+ topics_req = Google::Pubsub::V1::ListTopicsRequest.new.tap do |r|
92
+ r.project = project_path(options)
93
+ r.page_token = options[:token] if options[:token]
94
+ r.page_size = options[:max] if options[:max]
95
+ end
96
+
97
+ execute { publisher.list_topics topics_req }
98
+ end
99
+
100
+ ##
101
+ # Creates the given topic with the given name.
102
+ def create_topic topic_name, options = {}
103
+ topic_req = Google::Pubsub::V1::Topic.new.tap do |r|
104
+ r.name = topic_path(topic_name, options)
105
+ end
106
+
107
+ execute { publisher.create_topic topic_req }
108
+ end
109
+
110
+ ##
111
+ # Deletes the topic with the given name. All subscriptions to this topic
112
+ # are also deleted. Raises GRPC status code 5 if the topic does not
113
+ # exist. After a topic is deleted, a new topic may be created with the
114
+ # same name.
115
+ def delete_topic topic_name
116
+ topic_req = Google::Pubsub::V1::DeleteTopicRequest.new.tap do |r|
117
+ r.topic = topic_path(topic_name)
118
+ end
119
+
120
+ execute { publisher.delete_topic topic_req }
121
+ end
122
+
123
+ ##
124
+ # Adds one or more messages to the topic.
125
+ # Raises GRPC status code 5 if the topic does not exist.
126
+ # The messages parameter is an array of arrays.
127
+ # The first element is the data, second is attributes hash.
128
+ def publish topic, messages
129
+ publish_req = Google::Pubsub::V1::PublishRequest.new(
130
+ topic: topic_path(topic),
131
+ messages: messages.map do |data, attributes|
132
+ Google::Pubsub::V1::PubsubMessage.new(
133
+ data: data, attributes: attributes)
134
+ end
135
+ )
136
+
137
+ execute { publisher.publish publish_req }
138
+ end
139
+
140
+ ##
141
+ # Gets the details of a subscription.
142
+ def get_subscription subscription_name, options = {}
143
+ sub_req = Google::Pubsub::V1::GetSubscriptionRequest.new(
144
+ subscription: subscription_path(subscription_name, options)
145
+ )
146
+
147
+ execute { subscriber.get_subscription sub_req }
148
+ end
149
+
150
+ ##
151
+ # Lists matching subscriptions by project and topic.
152
+ def list_topics_subscriptions topic, options = {}
153
+ list_params = { topic: topic_path(topic, options),
154
+ page_token: options[:token],
155
+ page_size: options[:max]
156
+ }.delete_if { |_, v| v.nil? }
157
+ list_req = Google::Pubsub::V1::ListTopicSubscriptionsRequest.new \
158
+ list_params
159
+
160
+ execute { publisher.list_topic_subscriptions list_req }
161
+ end
162
+
163
+ ##
164
+ # Lists matching subscriptions by project.
165
+ def list_subscriptions options = {}
166
+ list_params = { project: project_path(options),
167
+ page_token: options[:token],
168
+ page_size: options[:max]
169
+ }.delete_if { |_, v| v.nil? }
170
+ list_req = Google::Pubsub::V1::ListSubscriptionsRequest.new(
171
+ list_params)
172
+
173
+ execute { subscriber.list_subscriptions list_req }
174
+ end
175
+
176
+ ##
177
+ # Creates a subscription on a given topic for a given subscriber.
178
+ def create_subscription topic, subscription_name, options = {}
179
+ sub_params = { name: subscription_path(subscription_name, options),
180
+ topic: topic_path(topic),
181
+ ack_deadline_seconds: options[:deadline]
182
+ }.delete_if { |_, v| v.nil? }
183
+ sub_req = Google::Pubsub::V1::Subscription.new sub_params
184
+ if options[:endpoint]
185
+ sub_req.push_config = Google::Pubsub::V1::PushConfig.new(
186
+ push_endpoint: options[:endpoint],
187
+ attributes: (options[:attributes] || {}).to_h)
188
+ end
189
+
190
+ execute { subscriber.create_subscription sub_req }
191
+ end
192
+
193
+ ##
194
+ # Deletes an existing subscription.
195
+ # All pending messages in the subscription are immediately dropped.
196
+ def delete_subscription subscription
197
+ del_req = Google::Pubsub::V1::DeleteSubscriptionRequest.new(
198
+ subscription: subscription_path(subscription)
199
+ )
200
+
201
+ execute { subscriber.delete_subscription del_req }
202
+ end
203
+
204
+ ##
205
+ # Pulls a single message from the server.
206
+ def pull subscription, options = {}
207
+ pull_req = Google::Pubsub::V1::PullRequest.new(
208
+ subscription: subscription_path(subscription, options),
209
+ return_immediately: !(!options.fetch(:immediate, true)),
210
+ max_messages: options.fetch(:max, 100).to_i
211
+ )
212
+
213
+ execute { subscriber.pull pull_req }
214
+ end
215
+
216
+ ##
217
+ # Acknowledges receipt of a message.
218
+ def acknowledge subscription, *ack_ids
219
+ ack_req = Google::Pubsub::V1::AcknowledgeRequest.new(
220
+ subscription: subscription_path(subscription),
221
+ ack_ids: ack_ids
222
+ )
223
+
224
+ execute { subscriber.acknowledge ack_req }
225
+ end
226
+
227
+ ##
228
+ # Modifies the PushConfig for a specified subscription.
229
+ def modify_push_config subscription, endpoint, attributes
230
+ # Convert attributes to strings to match the protobuf definition
231
+ attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]
232
+
233
+ mpc_req = Google::Pubsub::V1::ModifyPushConfigRequest.new(
234
+ subscription: subscription_path(subscription),
235
+ push_config: Google::Pubsub::V1::PushConfig.new(
236
+ push_endpoint: endpoint,
237
+ attributes: attributes
238
+ )
239
+ )
240
+
241
+ execute { subscriber.modify_push_config mpc_req }
242
+ end
243
+
244
+ ##
245
+ # Modifies the ack deadline for a specific message.
246
+ def modify_ack_deadline subscription, ids, deadline
247
+ mad_req = Google::Pubsub::V1::ModifyAckDeadlineRequest.new(
248
+ subscription: subscription_path(subscription),
249
+ ack_ids: Array(ids),
250
+ ack_deadline_seconds: deadline
251
+ )
252
+
253
+ execute { subscriber.modify_ack_deadline mad_req }
254
+ end
255
+
256
+ def get_topic_policy topic_name, options = {}
257
+ get_req = Google::Iam::V1::GetIamPolicyRequest.new(
258
+ resource: topic_path(topic_name, options)
259
+ )
260
+
261
+ execute { iam.get_iam_policy get_req }
262
+ end
263
+
264
+ def set_topic_policy topic_name, new_policy, options = {}
265
+ set_req = Google::Iam::V1::SetIamPolicyRequest.new(
266
+ resource: topic_path(topic_name, options),
267
+ policy: new_policy
268
+ )
269
+
270
+ execute { iam.set_iam_policy set_req }
271
+ end
272
+
273
+ def test_topic_permissions topic_name, permissions, options = {}
274
+ test_req = Google::Iam::V1::TestIamPermissionsRequest.new(
275
+ resource: topic_path(topic_name, options),
276
+ permissions: permissions
277
+ )
278
+
279
+ execute { iam.test_iam_permissions test_req }
280
+ end
281
+
282
+ def get_subscription_policy subscription_name, options = {}
283
+ get_req = Google::Iam::V1::GetIamPolicyRequest.new(
284
+ resource: subscription_path(subscription_name, options)
285
+ )
286
+
287
+ execute { iam.get_iam_policy get_req }
288
+ end
289
+
290
+ def set_subscription_policy subscription_name, new_policy, options = {}
291
+ set_req = Google::Iam::V1::SetIamPolicyRequest.new(
292
+ resource: subscription_path(subscription_name, options),
293
+ policy: new_policy
294
+ )
295
+
296
+ execute { iam.set_iam_policy set_req }
297
+ end
298
+
299
+ def test_subscription_permissions subscription_name,
300
+ permissions, options = {}
301
+ test_req = Google::Iam::V1::TestIamPermissionsRequest.new(
302
+ resource: subscription_path(subscription_name, options),
303
+ permissions: permissions
304
+ )
305
+
306
+ execute { iam.test_iam_permissions test_req }
307
+ end
308
+
309
+ def project_path options = {}
310
+ project_name = options[:project] || project
311
+ "projects/#{project_name}"
312
+ end
313
+
314
+ def topic_path topic_name, options = {}
315
+ return topic_name if topic_name.to_s.include? "/"
316
+ "#{project_path(options)}/topics/#{topic_name}"
317
+ end
318
+
319
+ def subscription_path subscription_name, options = {}
320
+ return subscription_name if subscription_name.to_s.include? "/"
321
+ "#{project_path(options)}/subscriptions/#{subscription_name}"
322
+ end
323
+
324
+ def inspect
325
+ "#{self.class}(#{@project})"
326
+ end
327
+
328
+ protected
329
+
330
+ def execute
331
+ Google::Cloud::Core::GrpcBackoff.new(retries: retries).execute do
332
+ yield
333
+ end
334
+ rescue GRPC::BadStatus => e
335
+ raise Error.from_error(e)
336
+ end
337
+ end
338
+ end
339
+ end
340
+ end