google-cloud-pubsub 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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