activemessaging 0.13.4 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,6 +24,8 @@ matrix:
24
24
  - rvm: rbx-19mode
25
25
  - rvm: ruby-head
26
26
  exclude:
27
+ - rvm: 1.9.2
28
+ gemfile: gemfiles/activesupport23.gemfile
27
29
  - rvm: 1.9.3
28
30
  gemfile: gemfiles/activesupport23.gemfile
29
31
  - rvm: ruby-head
data/Appraisals CHANGED
@@ -1,6 +1,7 @@
1
1
  appraise "activesupport23" do
2
2
  gem "activesupport", "~> 2.3.11"
3
3
  gem "rake", "~> 0.8.7"
4
+ gem "test-unit", "~> 1.2.3"
4
5
  end
5
6
 
6
7
  appraise "activesupport30" do
@@ -21,8 +21,8 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler"
23
23
  spec.add_development_dependency "test-unit"
24
- spec.add_development_dependency "stomp"
25
24
  spec.add_development_dependency "appraisal"
25
+ spec.add_development_dependency "stomp", "< 1.4"
26
26
 
27
27
  spec.add_runtime_dependency "activesupport"
28
28
  spec.add_runtime_dependency "rake"
@@ -4,5 +4,6 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "activesupport", "~> 2.3.11"
6
6
  gem "rake", "~> 0.8.7"
7
+ gem "test-unit", "~> 1.2.3"
7
8
 
8
9
  gemspec :development_group => :test, :path => "../"
@@ -0,0 +1,110 @@
1
+ # https://github.com/cmdrkeene/aws4
2
+ #
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) 2013 Brandon Keene
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
+ #
9
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+ #
11
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
+
13
+ # encoding: UTF-8
14
+ require "openssl"
15
+ require "time"
16
+ require "uri"
17
+ require "pathname"
18
+
19
+ class AWS4Signer
20
+ RFC8601BASIC = "%Y%m%dT%H%M%SZ"
21
+ attr_reader :access_key, :secret_key, :region
22
+ attr_reader :date, :method, :uri, :headers, :body, :service
23
+
24
+ def initialize(config)
25
+ @access_key = config[:access_key] || config["access_key"]
26
+ @secret_key = config[:secret_key] || config["secret_key"]
27
+ @region = config[:region] || config["region"]
28
+ end
29
+
30
+ def sign(method, uri, headers, body = nil, debug = false, service_name=nil)
31
+ @method = method.upcase
32
+ @uri = uri
33
+ @headers = headers
34
+ @body = body
35
+ @service = service_name || @uri.host.split(".", 2)[0]
36
+ date_header = headers["Date"] || headers["DATE"] || headers["date"]
37
+ @date = (date_header ? Time.parse(date_header) : Time.now).utc.strftime(RFC8601BASIC)
38
+ dump if debug
39
+ signed = headers.dup
40
+ signed['Authorization'] = authorization(headers)
41
+ signed
42
+ end
43
+
44
+ private
45
+
46
+ def authorization(headers)
47
+ [
48
+ "AWS4-HMAC-SHA256 Credential=#{access_key}/#{credential_string}",
49
+ "SignedHeaders=#{headers.keys.map(&:downcase).sort.join(";")}",
50
+ "Signature=#{signature}"
51
+ ].join(', ')
52
+ end
53
+
54
+ def signature
55
+ k_date = hmac("AWS4" + secret_key, date[0,8])
56
+ k_region = hmac(k_date, region)
57
+ k_service = hmac(k_region, service)
58
+ k_credentials = hmac(k_service, "aws4_request")
59
+ hexhmac(k_credentials, string_to_sign)
60
+ end
61
+
62
+ def string_to_sign
63
+ [
64
+ 'AWS4-HMAC-SHA256',
65
+ date,
66
+ credential_string,
67
+ hexdigest(canonical_request)
68
+ ].join("\n")
69
+ end
70
+
71
+ def credential_string
72
+ [
73
+ date[0,8],
74
+ region,
75
+ service,
76
+ "aws4_request"
77
+ ].join("/")
78
+ end
79
+
80
+ def canonical_request
81
+ [
82
+ method,
83
+ Pathname.new(uri.path).cleanpath.to_s,
84
+ uri.query,
85
+ headers.sort.map {|k, v| [k.downcase,v.strip].join(':')}.join("\n") + "\n",
86
+ headers.sort.map {|k, v| k.downcase}.join(";"),
87
+ hexdigest(body || '')
88
+ ].join("\n")
89
+ end
90
+
91
+ def hexdigest(value)
92
+ Digest::SHA256.new.update(value).hexdigest
93
+ end
94
+
95
+ def hmac(key, value)
96
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, value)
97
+ end
98
+
99
+ def hexhmac(key, value)
100
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, value)
101
+ end
102
+
103
+ def dump
104
+ puts "string to sign"
105
+ puts string_to_sign
106
+ puts "canonical_request"
107
+ puts canonical_request
108
+ puts "authorization"
109
+ end
110
+ end
@@ -0,0 +1,479 @@
1
+ require 'rubygems'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'openssl'
5
+ require 'base64'
6
+ require 'cgi'
7
+ require 'time'
8
+ require 'uri'
9
+ require 'rexml/document'
10
+ require 'erb'
11
+
12
+ require 'activemessaging/adapters/base'
13
+ require 'activemessaging/adapters/aws4_signer'
14
+
15
+ module ActiveMessaging
16
+ module Adapters
17
+ module Sqs
18
+
19
+ class Connection < ActiveMessaging::Adapters::BaseConnection
20
+ register :sqs
21
+
22
+ QUEUE_NAME_LENGTH = 1..80
23
+ VISIBILITY_TIMEOUT = 0..(24 * 60 * 60)
24
+ NUMBER_OF_MESSAGES = 1..255
25
+ GET_QUEUE_ATTRIBUTES = ['All', 'ApproximateNumberOfMessages', 'ApproximateNumberOfMessagesDelayed', 'ApproximateNumberOfMessagesNotVisible', 'CreatedTimestamp', 'DelaySeconds', 'LastModifiedTimestamp', 'MaximumMessageSize', 'MessageRetentionPeriod', 'Policy', 'QueueArn', 'ReceiveMessageWaitTimeSeconds', 'RedrivePolicy', 'VisibilityTimeout', 'KmsMasterKeyId', 'KmsDataKeyReusePeriodSeconds', 'FifoQueue', 'ContentBasedDeduplication']
26
+ SET_QUEUE_ATTRIBUTES = ['DelaySeconds', 'MaximumMessageSize', 'MessageRetentionPeriod', 'Policy', 'ReceiveMessageWaitTimeSeconds', 'RedrivePolicy', 'VisibilityTimeout', 'KmsMasterKeyId', 'KmsDataKeyReusePeriodSeconds', 'ContentBasedDeduplication']
27
+
28
+ #configurable params
29
+ attr_accessor :reconnect_delay, :access_key_id, :secret_access_key, :aws_version, :content_type, :host, :port, :poll_interval, :cache_queue_list, :max_message_size
30
+
31
+ #generic init method needed by a13g
32
+ def initialize cfg
33
+ raise "Must specify a access_key_id" if (cfg[:access_key_id].nil? || cfg[:access_key_id].empty?)
34
+ raise "Must specify a secret_access_key" if (cfg[:secret_access_key].nil? || cfg[:secret_access_key].empty?)
35
+
36
+ @access_key_id = cfg[:access_key_id]
37
+ @secret_access_key = cfg[:secret_access_key]
38
+ @region = cfg[:region] || 'us-east-1'
39
+ @request_expires = cfg[:requestExpires] || 10
40
+ @request_retry_count = cfg[:requestRetryCount] || 5
41
+ @aws_version = cfg[:aws_version] || '2012-11-05'
42
+ @content_type = cfg[:content_type] || 'text/plain'
43
+ @host = cfg[:host] || "sqs.#{@region}.amazonaws.com"
44
+ @port = cfg[:port] || 80
45
+ @protocol = cfg[:protocol] || 'http'
46
+ @poll_interval = cfg[:poll_interval] || 1
47
+ @reconnect_delay = cfg[:reconnectDelay] || 5
48
+
49
+ @max_message_size = cfg[:max_message_size].to_i > 0 ? cfg[:max_message_size].to_i : 8
50
+
51
+ @aws_url = "#{@protocol}://#{@host}/"
52
+
53
+ @cache_queue_list = cfg[:cache_queue_list].nil? ? true : cfg[:cache_queue_list]
54
+ @reliable = cfg[:reliable].nil? ? true : cfg[:reliable]
55
+
56
+ #initialize the subscriptions and queues
57
+ @subscriptions = {}
58
+ @queues_by_priority = {}
59
+ @current_subscription = 0
60
+ queues
61
+ end
62
+
63
+ def disconnect
64
+ return true
65
+ end
66
+
67
+ # queue_name string, headers hash
68
+ # for sqs, make sure queue exists, if not create, then add to list of polled queues
69
+ def subscribe queue_name, message_headers={}
70
+ # look at the existing queues, create any that are missing
71
+ queue = get_or_create_queue queue_name
72
+ if @subscriptions.has_key? queue.name
73
+ @subscriptions[queue.name].add
74
+ else
75
+ @subscriptions[queue.name] = Subscription.new(queue.name, message_headers)
76
+ end
77
+ priority = @subscriptions[queue.name].priority
78
+
79
+ @queues_by_priority[priority] = [] unless @queues_by_priority.has_key?(priority)
80
+ @queues_by_priority[priority] << queue.name unless @queues_by_priority[priority].include?(queue.name)
81
+ end
82
+
83
+ # queue_name string, headers hash
84
+ # for sqs, attempt delete the queues, won't work if not empty, that's ok
85
+ def unsubscribe queue_name, message_headers={}
86
+ if @subscriptions[queue_name]
87
+ @subscriptions[queue_name].remove
88
+ if @subscriptions[queue_name].count <= 0
89
+ sub = @subscriptions.delete(queue_name)
90
+ @queues_by_priority[sub.priority].delete(queue_name)
91
+ end
92
+ end
93
+ end
94
+
95
+ # queue_name string, body string, headers hash
96
+ # send a single message to a queue
97
+ def send(queue_name, message_body, message_headers = {})
98
+ queue = get_or_create_queue(queue_name)
99
+ send_messsage queue, message_body
100
+ end
101
+
102
+ # new receive respects priorities
103
+ def receive(options = {})
104
+ message = nil
105
+
106
+ only_priorities = options[:priorities]
107
+
108
+ # loop through the priorities
109
+ @queues_by_priority.keys.sort.each do |priority|
110
+
111
+ # skip this priority if there is a list, and it is not in the list
112
+ next if only_priorities && !only_priorities.include?(priority.to_i)
113
+
114
+ # loop through queues for the same priority in random order each time
115
+ @queues_by_priority[priority].shuffle.each do |queue_name|
116
+ queue = queues[queue_name]
117
+ subscription = @subscriptions[queue_name]
118
+
119
+ next if queue.nil? || subscription.nil?
120
+ messages = retrieve_messsages(queue, 1, subscription.headers[:visibility_timeout])
121
+
122
+ if (messages && !messages.empty?)
123
+ message = messages[0]
124
+ end
125
+
126
+ break if message
127
+ end
128
+
129
+ break if message
130
+ end
131
+ message
132
+ end
133
+
134
+ def received(message, headers={})
135
+ begin
136
+ delete_message(message)
137
+ rescue Object => exception
138
+ logger.error "Exception in ActiveMessaging::Adapters::AmazonSWS::Connection.received() logged and ignored: "
139
+ logger.error exception
140
+ end
141
+ end
142
+
143
+ # do nothing; by not deleting the message will eventually become visible again
144
+ def unreceive(message, headers = {})
145
+ return true
146
+ end
147
+
148
+ def create_queue(name)
149
+ validate_new_queue name
150
+ response = make_request('CreateQueue', nil, { 'QueueName' => name }, {
151
+ 'DelaySeconds' => 0,
152
+ 'MaximumMessageSize' => 262144,
153
+ 'MessageRetentionPeriod' => 4 * 24 * 60 * 60,
154
+ 'ReceiveMessageWaitTimeSeconds' => 0,
155
+ 'VisibilityTimeout' => 90 * 60
156
+ })
157
+ add_queue(response.get_text("/CreateQueueResponse/CreateQueueResult/QueueUrl")) unless response.nil?
158
+ end
159
+
160
+ def delete_queue(queue)
161
+ validate_queue queue
162
+ response = make_request('DeleteQueue', queue.queue_url)
163
+ queues.delete(queue.name)
164
+ end
165
+
166
+ def list_queues(queue_name_prefix = nil)
167
+ validate_queue_name queue_name_prefix unless queue_name_prefix.nil?
168
+ params = queue_name_prefix.nil? ? {} : { "QueueNamePrefix" => queue_name_prefix }
169
+ response = make_request('ListQueues', nil, params)
170
+ response.nil? ? [] : response.nodes("/ListQueuesResponse/ListQueuesResult/QueueUrl").collect{ |n| add_queue(n.text) }
171
+ end
172
+
173
+ def get_queue_attributes(queue, attributes = ['All'])
174
+ params = {}
175
+ attributes.each_with_index do |attribute, i|
176
+ validate_get_queue_attribute(attribute)
177
+ params["AttributeName.#{i+1}"] = attribute
178
+ end
179
+ response = make_request('GetQueueAttributes', queue.queue_url, params)
180
+ attributes = {}
181
+ response.each_node('/GetQueueAttributesResponse/GetQueueAttributesResult/Attribute') { |n|
182
+ name = n.elements['Name'].text
183
+ value = n.elements['Value'].text
184
+ attributes[name] = value
185
+ }
186
+ attributes
187
+ end
188
+
189
+ def set_queue_attributes(queue, attributes)
190
+ attributes.keys.each { |a| validate_set_queue_attribute(a) }
191
+ response = make_request('SetQueueAttributes', queue.queue_url, {}, attributes)
192
+ end
193
+
194
+ def delete_queue(queue)
195
+ validate_queue queue
196
+ response = make_request('DeleteQueue', queue.queue_url)
197
+ end
198
+
199
+ def send_messsage(queue, message)
200
+ validate_queue queue
201
+ validate_message message
202
+ response = make_request('SendMessage', queue.queue_url, { 'MessageBody' => message })
203
+ response.get_text('/SendMessageResponse/SendMessageResult/MessageId') unless response.nil?
204
+ end
205
+
206
+ def retrieve_messsages(queue, num_messages = 1, timeout = nil, waittime = nil)
207
+ validate_queue queue
208
+ validate_number_of_messages num_messages
209
+ validate_timeout timeout if timeout
210
+
211
+ params = { 'MaxNumberOfMessages' => num_messages.to_s, 'AttributeName' => 'All' }
212
+ params['VisibilityTimeout'] = timeout.to_s if timeout
213
+ params['WaitTimeSeconds'] = waittime.to_s if waittime
214
+
215
+ response = make_request('ReceiveMessage', queue.queue_url, params)
216
+ response.nodes('/ReceiveMessageResponse/ReceiveMessageResult/Message').map do |n|
217
+ Message.from_element(n, response, queue)
218
+ end unless response.nil?
219
+ end
220
+
221
+ def delete_message message
222
+ response = make_request('DeleteMessage', message.queue.queue_url, { 'ReceiptHandle' => message.receipt_handle })
223
+ end
224
+
225
+ def make_request(action, url=nil, params = {}, attributes = {})
226
+ url ||= @aws_url
227
+
228
+ params['Action'] = action
229
+ params['Version'] = @aws_version
230
+ params['Expires']= (Time.now + @request_expires).utc.iso8601
231
+
232
+ attributes.keys.sort.each_with_index do |k, i|
233
+ params["Attributes.#{i + 1}.Name"] = k
234
+ params["Attributes.#{i + 1}.Value"] = attributes[k]
235
+ end
236
+
237
+ # Sort and encode query params
238
+ query_params = params.keys.sort.map do |key|
239
+ key + "=" + ERB::Util.url_encode(params[key].to_s)
240
+ end
241
+
242
+ # Put these together with the uri to get the request query string
243
+ request_url = "#{url}?#{query_params.join("&")}"
244
+
245
+ # Create the request
246
+ init_headers = {
247
+ "Date" => Time.now.utc.iso8601,
248
+ "Host" => @host
249
+ }
250
+ request = Net::HTTP::Get.new(request_url, init_headers)
251
+
252
+ # Sign the request
253
+ signer = AWS4Signer.new({
254
+ :access_key => @access_key_id,
255
+ :secret_key => @secret_access_key,
256
+ :region => @region
257
+ })
258
+
259
+ headers = {}
260
+ request.canonical_each { |k, v| headers[k] = v }
261
+
262
+ signature = signer.sign('GET', URI.parse(request_url), headers)
263
+ signature.each { |k, v| request[k] = v }
264
+
265
+ # Make the request
266
+ retry_count = 0
267
+ while retry_count < @request_retry_count.to_i
268
+ retry_count = retry_count + 1
269
+ begin
270
+ http_response = http_request(host,port,request)
271
+ response = SQSResponse.new(http_response)
272
+ check_errors(response)
273
+ return response
274
+ rescue Object=>ex
275
+ raise ex unless reliable
276
+ sleep(@reconnect_delay)
277
+ end
278
+ end
279
+ end
280
+
281
+ def http_request h, p, r
282
+ http = Net::HTTP.new(h, p)
283
+ # http.set_debug_output(STDOUT)
284
+
285
+ http.use_ssl = true if "https" == @protocol
286
+
287
+ # Don't carp about SSL cert verification
288
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
289
+ return http.request(r)
290
+ end
291
+
292
+ def check_errors(response)
293
+ raise "http response was nil" if (response.nil?)
294
+ raise response.errors if (response && response.errors?)
295
+ response
296
+ end
297
+
298
+ def queues
299
+ return @queues if (@queues && cache_queue_list)
300
+ @queues = {}
301
+ list_queues.each { |q| @queues[q.name] = q }
302
+ return @queues
303
+ end
304
+
305
+ # internal data structure methods
306
+
307
+ def add_queue(url)
308
+ q = Queue.from_url url
309
+ queues[q.name] = q if self.cache_queue_list
310
+ return q
311
+ end
312
+
313
+ def get_or_create_queue queue_name
314
+ qs = queues
315
+ q = qs.has_key?(queue_name) ? qs[queue_name] : create_queue(queue_name)
316
+ raise "could not get or create queue: #{queue_name}" unless q
317
+ q
318
+ end
319
+
320
+ # validation methods
321
+ def validate_queue_name qn
322
+ raise "Queue name, '#{qn}', must be between #{QUEUE_NAME_LENGTH.min} and #{QUEUE_NAME_LENGTH.max} characters." unless QUEUE_NAME_LENGTH.include?(qn.length)
323
+ raise "Queue name, '#{qn}', must be alphanumeric only." if (qn =~ /[^\w\-\_]/ )
324
+ end
325
+
326
+ def validate_new_queue qn
327
+ validate_queue_name qn
328
+ raise "Queue already exists: #{qn}" if queues.has_key? qn
329
+ end
330
+
331
+ def validate_queue q
332
+ raise "Never heard of queue, can't use it: #{q.name}" unless queues.has_key? q.name
333
+ end
334
+
335
+ def validate_message m
336
+ raise "Message cannot be nil." if m.nil?
337
+ raise "Message length, #{m.length}, must be between #{message_size_range.min} and #{message_size_range.max}." unless message_size_range.include?(m.length)
338
+ end
339
+
340
+ def message_size_range
341
+ @_message_size_range ||= 1..(max_message_size * 1024)
342
+ end
343
+
344
+ def validate_timeout to
345
+ raise "Timeout, #{to}, must be between #{VISIBILITY_TIMEOUT.min} and #{VISIBILITY_TIMEOUT.max}." unless VISIBILITY_TIMEOUT.include?(to)
346
+ end
347
+
348
+ def validate_get_queue_attribute qa
349
+ raise "Queue Attribute name, #{qa}, not in list of valid attributes to get: #{GET_QUEUE_ATTRIBUTES.to_sentence}." unless GET_QUEUE_ATTRIBUTES.include?(qa)
350
+ end
351
+
352
+ def validate_set_queue_attribute qa
353
+ raise "Queue Attribute name, #{qa}, not in list of valid attributes to set: #{SET_QUEUE_ATTRIBUTES.to_sentence}." unless SET_QUEUE_ATTRIBUTES.include?(qa)
354
+ end
355
+
356
+ def validate_number_of_messages nom
357
+ raise "Number of messages, #{nom}, must be between #{NUMBER_OF_MESSAGES.min} and #{NUMBER_OF_MESSAGES.max}." unless NUMBER_OF_MESSAGES.include?(nom)
358
+ end
359
+ end
360
+
361
+ class SQSResponse
362
+ attr_accessor :headers, :doc, :http_response
363
+
364
+ def initialize response
365
+ # puts "response.body = #{response.body}"
366
+ @http_response = response
367
+ @headers = response.to_hash()
368
+ @doc = REXML::Document.new(response.body)
369
+ end
370
+
371
+ def message_type
372
+ return doc ? doc.root.name : ''
373
+ end
374
+
375
+ def errors?
376
+ (not http_response.kind_of?(Net::HTTPSuccess)) or (message_type == 'ErrorResponse')
377
+ end
378
+
379
+ def errors
380
+ return "HTTP Error: #{http_response.code} : #{http_response.message}" unless http_response.kind_of?(Net::HTTPSuccess)
381
+
382
+ msg = nil
383
+ each_node('//Error') { |n|
384
+ msg ||= ""
385
+ c = n.elements['Code'].text
386
+ m = n.elements['Message'].text
387
+ msg << ", " if msg != ""
388
+ msg << "#{c} : #{m}"
389
+ }
390
+
391
+ return msg
392
+ end
393
+
394
+ def get_text(xpath,default='')
395
+ e = REXML::XPath.first( doc, xpath)
396
+ e.nil? ? default : e.text
397
+ end
398
+
399
+ def each_node(xp)
400
+ REXML::XPath.each(doc.root, xp) {|n| yield n}
401
+ end
402
+
403
+ def nodes(xp)
404
+ doc.elements.to_a(xp)
405
+ end
406
+ end
407
+
408
+ class Subscription
409
+ attr_accessor :destination, :headers, :count, :priority
410
+
411
+ def initialize(destination, headers={}, count=1)
412
+ @priority = headers.delete(:priority) || 1001
413
+ @destination, @headers, @count = destination, headers, count
414
+ end
415
+
416
+ def add
417
+ @count += 1
418
+ end
419
+
420
+ def remove
421
+ @count -= 1
422
+ end
423
+ end
424
+
425
+ class Queue
426
+ attr_accessor :url, :name, :pathinfo, :domain, :visibility_timeout
427
+
428
+ def self.from_url url
429
+ uri = URI.parse(url)
430
+ name = uri.path.split('/').last
431
+ domain = uri.host
432
+ return Queue.new(name, uri)
433
+ end
434
+
435
+ def queue_url
436
+ url.to_s
437
+ end
438
+
439
+ def initialize name, url, vt=nil
440
+ @name, @url, @visibility_timeout = name, url, vt
441
+ end
442
+
443
+ def to_s
444
+ "<AmazonSQS::Queue name='#{name}' url='#{url}' visibility_timeout='#{visibility_timeout}'>"
445
+ end
446
+ end
447
+
448
+ # based on stomp message, has pointer to the SQSResponseObject
449
+ class Message < ActiveMessaging::BaseMessage
450
+ attr_accessor :response, :queue, :md5_of_body, :receipt_handle, :request_id, :attributes
451
+
452
+ def self.from_element(e, response, queue)
453
+ attributes = {}
454
+ e.elements.each('Attribute') { |n| attributes[n.elements['Name'].text] = n.elements['Value'].text }
455
+
456
+ Message.new(
457
+ e.elements['Body'].text,
458
+ response.headers,
459
+ e.elements['MessageId'].text,
460
+ e.elements['MD5OfBody'].text,
461
+ e.elements['ReceiptHandle'].text,
462
+ attributes,
463
+ response,
464
+ queue)
465
+ end
466
+
467
+ def initialize body, headers, id, md5_of_body, receipt_handle, attributes, response, queue
468
+ super(body, id, headers, queue.name)
469
+ @md5_of_body, @receipt_handle, @response, @queue = md5_of_body, receipt_handle, response, queue
470
+ end
471
+
472
+ def to_s
473
+ "<AmazonSQS::Message id='#{id}' body='#{body}' headers='#{headers.inspect}' attributes='#{attributes.inspect}' response='#{response}'>"
474
+ end
475
+ end
476
+
477
+ end
478
+ end
479
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveMessaging
2
- VERSION = "0.13.4"
2
+ VERSION = "0.14.1"
3
3
  end
metadata CHANGED
@@ -1,9 +1,15 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: activemessaging
3
- version: !ruby/object:Gem::Version
4
- version: 0.13.4
3
+ version: !ruby/object:Gem::Version
4
+ hash: 37
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 14
9
+ - 1
10
+ version: 0.14.1
5
11
  platform: ruby
6
- authors:
12
+ authors:
7
13
  - Jon Tirsen
8
14
  - Andrew Kuklewicz
9
15
  - Olle Jonsson
@@ -15,105 +21,106 @@ authors:
15
21
  autorequire:
16
22
  bindir: exe
17
23
  cert_chain: []
18
- date: 2018-03-26 00:00:00.000000000 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: bundler
22
- requirement: !ruby/object:Gem::Requirement
23
- requirements:
24
+
25
+ date: 2018-06-05 00:00:00 Z
26
+ dependencies:
27
+ - !ruby/object:Gem::Dependency
28
+ version_requirements: &id001 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
24
31
  - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- type: :development
32
+ - !ruby/object:Gem::Version
33
+ hash: 3
34
+ segments:
35
+ - 0
36
+ version: "0"
28
37
  prerelease: false
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
38
+ requirement: *id001
39
+ type: :development
40
+ name: bundler
41
+ - !ruby/object:Gem::Dependency
42
+ version_requirements: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
31
45
  - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- - !ruby/object:Gem::Dependency
46
+ - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
50
+ version: "0"
51
+ prerelease: false
52
+ requirement: *id002
53
+ type: :development
35
54
  name: test-unit
36
- requirement: !ruby/object:Gem::Requirement
37
- requirements:
55
+ - !ruby/object:Gem::Dependency
56
+ version_requirements: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
38
59
  - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- type: :development
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
42
65
  prerelease: false
43
- version_requirements: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- - !ruby/object:Gem::Dependency
49
- name: stomp
50
- requirement: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
66
+ requirement: *id003
55
67
  type: :development
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- - !ruby/object:Gem::Dependency
63
68
  name: appraisal
64
- requirement: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- type: :development
69
+ - !ruby/object:Gem::Dependency
70
+ version_requirements: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - <
74
+ - !ruby/object:Gem::Version
75
+ hash: 7
76
+ segments:
77
+ - 1
78
+ - 4
79
+ version: "1.4"
70
80
  prerelease: false
71
- version_requirements: !ruby/object:Gem::Requirement
72
- requirements:
81
+ requirement: *id004
82
+ type: :development
83
+ name: stomp
84
+ - !ruby/object:Gem::Dependency
85
+ version_requirements: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
73
88
  - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- - !ruby/object:Gem::Dependency
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ prerelease: false
95
+ requirement: *id005
96
+ type: :runtime
77
97
  name: activesupport
78
- requirement: !ruby/object:Gem::Requirement
79
- requirements:
98
+ - !ruby/object:Gem::Dependency
99
+ version_requirements: &id006 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
80
102
  - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- type: :runtime
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
84
108
  prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- - !ruby/object:Gem::Dependency
91
- name: rake
92
- requirement: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
109
+ requirement: *id006
97
110
  type: :runtime
98
- prerelease: false
99
- version_requirements: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- description: ActiveMessaging is an attempt to bring the simplicity and elegance of
105
- rails development to the world of messaging. Messaging, (or event-driven architecture)
106
- is widely used for enterprise integration, with frameworks such as Java's JMS, and
107
- products such as ActiveMQ, Tibco, IBM MQSeries, etc. Now supporting Rails 3 as of
108
- version 0.8.0.
109
- email:
111
+ name: rake
112
+ description: ActiveMessaging is an attempt to bring the simplicity and elegance of rails development to the world of messaging. Messaging, (or event-driven architecture) is widely used for enterprise integration, with frameworks such as Java's JMS, and products such as ActiveMQ, Tibco, IBM MQSeries, etc. Now supporting Rails 3 as of version 0.8.0.
113
+ email:
110
114
  - activemessaging-discuss@googlegroups.com
111
115
  executables: []
116
+
112
117
  extensions: []
118
+
113
119
  extra_rdoc_files: []
114
- files:
115
- - ".gitignore"
116
- - ".travis.yml"
120
+
121
+ files:
122
+ - .gitignore
123
+ - .travis.yml
117
124
  - Appraisals
118
125
  - Gemfile
119
126
  - README.md
@@ -152,10 +159,12 @@ files:
152
159
  - lib/activemessaging/adapter.rb
153
160
  - lib/activemessaging/adapters/amqp.rb
154
161
  - lib/activemessaging/adapters/asqs.rb
162
+ - lib/activemessaging/adapters/aws4_signer.rb
155
163
  - lib/activemessaging/adapters/base.rb
156
164
  - lib/activemessaging/adapters/beanstalk.rb
157
165
  - lib/activemessaging/adapters/jms.rb
158
166
  - lib/activemessaging/adapters/reliable_msg.rb
167
+ - lib/activemessaging/adapters/sqs.rb
159
168
  - lib/activemessaging/adapters/stomp.rb
160
169
  - lib/activemessaging/adapters/synch.rb
161
170
  - lib/activemessaging/adapters/test.rb
@@ -186,28 +195,37 @@ files:
186
195
  - lib/generators/active_messaging/processor/templates/processor_test.rb
187
196
  - lib/tasks/start_consumers.rake
188
197
  homepage: http://github.com/kookster/activemessaging
189
- licenses:
198
+ licenses:
190
199
  - MIT
191
- metadata: {}
192
200
  post_install_message:
193
201
  rdoc_options: []
194
- require_paths:
202
+
203
+ require_paths:
195
204
  - lib
196
- required_ruby_version: !ruby/object:Gem::Requirement
197
- requirements:
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ none: false
207
+ requirements:
198
208
  - - ">="
199
- - !ruby/object:Gem::Version
200
- version: '0'
201
- required_rubygems_version: !ruby/object:Gem::Requirement
202
- requirements:
209
+ - !ruby/object:Gem::Version
210
+ hash: 3
211
+ segments:
212
+ - 0
213
+ version: "0"
214
+ required_rubygems_version: !ruby/object:Gem::Requirement
215
+ none: false
216
+ requirements:
203
217
  - - ">="
204
- - !ruby/object:Gem::Version
205
- version: '0'
218
+ - !ruby/object:Gem::Version
219
+ hash: 3
220
+ segments:
221
+ - 0
222
+ version: "0"
206
223
  requirements: []
224
+
207
225
  rubyforge_project:
208
- rubygems_version: 2.7.3
226
+ rubygems_version: 1.8.15
209
227
  signing_key:
210
- specification_version: 4
211
- summary: Official activemessaging gem, now hosted on github.com/kookster. (kookster
212
- prefix temporary)
228
+ specification_version: 3
229
+ summary: Official activemessaging gem, now hosted on github.com/kookster. (kookster prefix temporary)
213
230
  test_files: []
231
+
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA256:
3
- metadata.gz: 32e4a6d354a60e3eb51a79ca91a496658fffe39f7e1d5191d4448fed8156f956
4
- data.tar.gz: 2be0c55eb42ce095f81ae2167136523056c92f93bb79dd3e76ba4bc3a3ce483d
5
- SHA512:
6
- metadata.gz: 0b88f4edea3a07ae4af816d587820a0aed25e597404b18a54d97cdae73107ae8c23c78e9a3c6c8ac404fde38d5130f2aa1f623a7ec0143b339c58cd619099d8a
7
- data.tar.gz: 848bcf35b46f70a54e4bfcf36c04778038df439d080f189bffe0f582b098ba7314e2b777f906f1ed20c4e7f13bf4eea25b0b428293ae0510cb3490cbb1bfd639