redaranj-right_aws 1.10.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,388 @@
1
+ #
2
+ # Copyright (c) 2007-2008 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ module RightAws
25
+
26
+ #
27
+ # = RightAws::Sqs -- RightScale's Amazon SQS interface
28
+ # The RightAws::Sqs class provides a complete interface to Amazon's Simple
29
+ # Queue Service.
30
+ # For explanations of the semantics
31
+ # of each call, please refer to Amazon's documentation at
32
+ # http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=31
33
+ #
34
+ # Error handling: all operations raise an RightAws::AwsError in case
35
+ # of problems. Note that transient errors are automatically retried.
36
+ #
37
+ # sqs = RightAws::Sqs.new(aws_access_key_id, aws_secret_access_key)
38
+ # queue1 = sqs.queue('my_awesome_queue')
39
+ # ...
40
+ # queue2 = RightAws::Sqs::Queue.create(sqs, 'my_cool_queue', true)
41
+ # puts queue2.size
42
+ # ...
43
+ # message1 = queue2.receive
44
+ # message1.visibility = 0
45
+ # puts message1
46
+ # ...
47
+ # queue2.clear(true)
48
+ # queue2.send_message('Ola-la!')
49
+ # message2 = queue2.pop
50
+ # ...
51
+ # grantee1 = RightAws::Sqs::Grantee.create(queue2,'one_cool_guy@email.address')
52
+ # grantee1.grant('FULLCONTROL')
53
+ # grantee1.drop
54
+ # ...
55
+ # grantee2 = queue.grantees('another_cool_guy@email.address')
56
+ # grantee2.revoke('SENDMESSAGE')
57
+ #
58
+ # Params is a hash:
59
+ #
60
+ # {:server => 'queue.amazonaws.com' # Amazon service host: 'queue.amazonaws.com' (default)
61
+ # :port => 443 # Amazon service port: 80 or 443 (default)
62
+ # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false (default)
63
+ # :signature_version => '0' # The signature version : '0' or '1'(default)
64
+ # :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
65
+ #
66
+ class Sqs
67
+ attr_reader :interface
68
+
69
+ def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
70
+ @interface = SqsInterface.new(aws_access_key_id, aws_secret_access_key, params)
71
+ end
72
+
73
+ # Retrieves a list of queues.
74
+ # Returns an +array+ of +Queue+ instances.
75
+ #
76
+ # RightAws::Sqs.queues #=> array of queues
77
+ #
78
+ def queues(prefix=nil)
79
+ @interface.list_queues(prefix).map do |url|
80
+ Queue.new(self, url)
81
+ end
82
+ end
83
+
84
+ # Returns Queue instance by queue name.
85
+ # If the queue does not exist at Amazon SQS and +create+ is true, the method creates it.
86
+ #
87
+ # RightAws::Sqs.queue('my_awesome_queue') #=> #<RightAws::Sqs::Queue:0xb7b626e4 ... >
88
+ #
89
+ def queue(queue_name, create=true, visibility=nil)
90
+ url = @interface.queue_url_by_name(queue_name)
91
+ url = (create ? @interface.create_queue(queue_name, visibility) : nil) unless url
92
+ url ? Queue.new(self, url) : nil
93
+ end
94
+
95
+
96
+ class Queue
97
+ attr_reader :name, :url, :sqs
98
+
99
+ # Returns Queue instance by queue name.
100
+ # If the queue does not exist at Amazon SQS and +create+ is true, the method creates it.
101
+ #
102
+ # RightAws::Sqs::Queue.create(sqs, 'my_awesome_queue') #=> #<RightAws::Sqs::Queue:0xb7b626e4 ... >
103
+ #
104
+ def self.create(sqs, url_or_name, create=true, visibility=nil)
105
+ sqs.queue(url_or_name, create, visibility)
106
+ end
107
+
108
+ # Creates new Queue instance.
109
+ # Does not create a queue at Amazon.
110
+ #
111
+ # queue = RightAws::Sqs::Queue.new(sqs, 'my_awesome_queue')
112
+ #
113
+ def initialize(sqs, url_or_name)
114
+ @sqs = sqs
115
+ @url = @sqs.interface.queue_url_by_name(url_or_name)
116
+ @name = @sqs.interface.queue_name_by_url(@url)
117
+ end
118
+
119
+ # Retrieves queue size.
120
+ #
121
+ # queue.size #=> 1
122
+ #
123
+ def size
124
+ @sqs.interface.get_queue_length(@url)
125
+ end
126
+
127
+ # Clears queue.
128
+ # Deletes only the visible messages unless +force+ is +true+.
129
+ #
130
+ # queue.clear(true) #=> true
131
+ #
132
+ # P.S. when <tt>force==true</tt> the queue deletes then creates again. This is
133
+ # the quickest method to clear a big queue or a queue with 'locked' messages. All queue
134
+ # attributes are restored. But there is no way to restore grantees' permissions to
135
+ # this queue. If you have no grantees except 'root' then you have no problems.
136
+ # Otherwise, it's better to use <tt>queue.clear(false)</tt>.
137
+ #
138
+ # PS This function is no longer supported. Amazon has changed the SQS semantics to require at least 60 seconds between
139
+ # queue deletion and creation. Hence this method will fail with an exception.
140
+ #
141
+ def clear(force=false)
142
+ ## if force
143
+ ## @sqs.interface.force_clear_queue(@url)
144
+ ## else
145
+ @sqs.interface.clear_queue(@url)
146
+ ## end
147
+ end
148
+
149
+ # Deletes queue.
150
+ # Queue must be empty or +force+ must be set to +true+.
151
+ # Returns +true+.
152
+ #
153
+ # queue.delete(true) #=> true
154
+ #
155
+ def delete(force=false)
156
+ @sqs.interface.delete_queue(@url, force)
157
+ end
158
+
159
+ # Sends new message to queue.
160
+ # Returns new Message instance that has been sent to queue.
161
+ def send_message(message)
162
+ message = message.to_s
163
+ msg = Message.new(self, @sqs.interface.send_message(@url, message), message)
164
+ msg.sent_at = Time.now
165
+ msg
166
+ end
167
+ alias_method :push, :send_message
168
+
169
+ # Retrieves several messages from queue.
170
+ # Returns an array of Message instances.
171
+ #
172
+ # queue.receive_messages(2,10) #=> array of messages
173
+ #
174
+ def receive_messages(number_of_messages=1, visibility=nil)
175
+ list = @sqs.interface.receive_messages(@url, number_of_messages, visibility)
176
+ list.map! do |entry|
177
+ msg = Message.new(self, entry[:id], entry[:body], visibility)
178
+ msg.received_at = Time.now
179
+ msg
180
+ end
181
+ end
182
+
183
+ # Retrieves first accessible message from queue.
184
+ # Returns Message instance or +nil+ it the queue is empty.
185
+ #
186
+ # queue.receive #=> #<RightAws::Sqs::Message:0xb7bf0884 ... >
187
+ #
188
+ def receive(visibility=nil)
189
+ list = receive_messages(1, visibility)
190
+ list.empty? ? nil : list[0]
191
+ end
192
+
193
+ # Peeks message body.
194
+ #
195
+ # queue.peek #=> #<RightAws::Sqs::Message:0xb7bf0884 ... >
196
+ #
197
+ def peek(message_id)
198
+ entry = @sqs.interface.peek_message(@url, message_id)
199
+ msg = Message.new(self, entry[:id], entry[:body])
200
+ msg.received_at = Time.now
201
+ msg
202
+ end
203
+
204
+ # Pops (and deletes) first accessible message from queue.
205
+ # Returns Message instance or +nil+ it the queue is empty.
206
+ #
207
+ # queue.pop #=> #<RightAws::Sqs::Message:0xb7bf0884 ... >
208
+ #
209
+ def pop
210
+ msg = receive
211
+ msg.delete if msg
212
+ msg
213
+ end
214
+
215
+ # Retrieves +VisibilityTimeout+ value for the queue.
216
+ # Returns new timeout value.
217
+ #
218
+ # queue.visibility #=> 30
219
+ #
220
+ def visibility
221
+ @sqs.interface.get_visibility_timeout(@url)
222
+ end
223
+
224
+ # Sets new +VisibilityTimeout+ for the queue.
225
+ # Returns new timeout value.
226
+ #
227
+ # queue.visibility #=> 30
228
+ # queue.visibility = 33
229
+ # queue.visibility #=> 33
230
+ #
231
+ def visibility=(visibility_timeout)
232
+ @sqs.interface.set_visibility_timeout(@url, visibility_timeout)
233
+ visibility_timeout
234
+ end
235
+
236
+ # Sets new queue attribute value.
237
+ # Not all attributes may be changed: +ApproximateNumberOfMessages+ (for example) is a read only attribute.
238
+ # Returns a value to be assigned to attribute.
239
+ #
240
+ # queue.set_attribute('VisibilityTimeout', '100') #=> '100'
241
+ # queue.get_attribute('VisibilityTimeout') #=> '100'
242
+ #
243
+ def set_attribute(attribute, value)
244
+ @sqs.interface.set_queue_attributes(@url, attribute, value)
245
+ value
246
+ end
247
+
248
+ # Retrieves queue attributes.
249
+ # At this moment Amazon supports +VisibilityTimeout+ and +ApproximateNumberOfMessages+ only.
250
+ # If the name of attribute is set, returns its value. Otherwise, returns a hash of attributes.
251
+ #
252
+ # queue.get_attribute('VisibilityTimeout') #=> '100'
253
+ #
254
+ def get_attribute(attribute='All')
255
+ attributes = @sqs.interface.get_queue_attributes(@url, attribute)
256
+ attribute=='All' ? attributes : attributes[attribute]
257
+ end
258
+
259
+ # Retrieves a list of grantees.
260
+ # Returns an +array+ of Grantee instances if the +grantee_email_address+ is unset.
261
+ # Otherwise returns a Grantee instance that points to +grantee_email_address+ or +nil+.
262
+ #
263
+ # grantees = queue.grantees #=> [#<RightAws::Sqs::Grantee:0xb7bf0888 ... >, ...]
264
+ # ...
265
+ # grantee = queue.grantees('cool_guy@email.address') #=> nil | #<RightAws::Sqs::Grantee:0xb7bf0888 ... >
266
+ #
267
+ def grantees(grantee_email_address=nil, permission = nil)
268
+ hash = @sqs.interface.list_grants(@url, grantee_email_address, permission)
269
+ grantees = []
270
+ hash.each do |key, value|
271
+ grantees << Grantee.new(self, grantee_email_address, key, value[:name], value[:perms])
272
+ end
273
+ if grantee_email_address
274
+ grantees.blank? ? nil : grantees.shift
275
+ else
276
+ grantees
277
+ end
278
+ end
279
+ end
280
+
281
+
282
+ class Message
283
+ attr_reader :queue, :id, :body, :visibility
284
+ attr_accessor :sent_at, :received_at
285
+
286
+ def initialize(queue, id=nil, body=nil, visibility=nil)
287
+ @queue = queue
288
+ @id = id
289
+ @body = body
290
+ @visibility = visibility
291
+ @sent_at = nil
292
+ @received_at = nil
293
+ end
294
+
295
+ # Returns +Message+ instance body.
296
+ def to_s
297
+ @body
298
+ end
299
+
300
+ # Changes +VisibilityTimeout+ for current message.
301
+ # Returns new +VisibilityTimeout+ value.
302
+ def visibility=(visibility_timeout)
303
+ @queue.sqs.interface.change_message_visibility(@queue.url, @id, visibility_timeout)
304
+ @visibility = visibility_timeout
305
+ end
306
+
307
+ # Removes message from queue.
308
+ # Returns +true+.
309
+ def delete
310
+ @queue.sqs.interface.delete_message(@queue.url, @id)
311
+ end
312
+ end
313
+
314
+
315
+ class Grantee
316
+ attr_accessor :queue, :id, :name, :perms, :email
317
+
318
+ # Creates new Grantee instance.
319
+ # To create new grantee for queue use:
320
+ #
321
+ # grantee = Grantee.new(queue, grantee@email.address)
322
+ # grantee.grant('FULLCONTROL')
323
+ #
324
+ def initialize(queue, email=nil, id=nil, name=nil, perms=[])
325
+ @queue = queue
326
+ @id = id
327
+ @name = name
328
+ @perms = perms
329
+ @email = email
330
+ retrieve unless id
331
+ end
332
+
333
+ # Retrieves security information for grantee identified by email.
334
+ # Returns +nil+ if the named user has no privileges on this queue, or
335
+ # +true+ if perms updated successfully.
336
+ def retrieve # :nodoc:
337
+ @id = nil
338
+ @name = nil
339
+ @perms = []
340
+
341
+ hash = @queue.sqs.interface.list_grants(@queue.url, @email)
342
+ return nil if hash.empty?
343
+
344
+ grantee = hash.shift
345
+ @id = grantee[0]
346
+ @name = grantee[1][:name]
347
+ @perms = grantee[1][:perms]
348
+ true
349
+ end
350
+
351
+ # Adds permissions for grantee.
352
+ # Permission: 'FULLCONTROL' | 'RECEIVEMESSAGE' | 'SENDMESSAGE'.
353
+ # The caller must have set the email instance variable.
354
+ def grant(permission=nil)
355
+ raise "You can't grant permission without defining a grantee email address!" unless @email
356
+ @queue.sqs.interface.add_grant(@queue.url, @email, permission)
357
+ retrieve
358
+ end
359
+
360
+ # Revokes permissions for grantee.
361
+ # Permission: 'FULLCONTROL' | 'RECEIVEMESSAGE' | 'SENDMESSAGE'.
362
+ # Default value is 'FULLCONTROL'.
363
+ # User must have +@email+ or +@id+ set.
364
+ # Returns +true+.
365
+ def revoke(permission='FULLCONTROL')
366
+ @queue.sqs.interface.remove_grant(@queue.url, @email || @id, permission)
367
+ unless @email # if email is unknown - just remove permission from local perms list...
368
+ @perms.delete(permission)
369
+ else # ... else retrieve updated information from Amazon
370
+ retrieve
371
+ end
372
+ true
373
+ end
374
+
375
+ # Revokes all permissions for this grantee.
376
+ # Returns +true+
377
+ def drop
378
+ @perms.each do |permission|
379
+ @queue.sqs.interface.remove_grant(@queue.url, @email || @id, permission)
380
+ end
381
+ retrieve
382
+ true
383
+ end
384
+
385
+ end
386
+
387
+ end
388
+ end