amq-client 0.9.12 → 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -8
- data/.travis.yml +4 -8
- data/Gemfile +1 -0
- data/amq-client.gemspec +1 -1
- data/bin/ci/before_build.sh +24 -0
- data/bin/set_test_suite_realms_up.sh +24 -0
- data/lib/amq/client/async/adapter.rb +10 -45
- data/lib/amq/client/async/adapters/coolio.rb +0 -4
- data/lib/amq/client/async/adapters/event_machine.rb +8 -8
- data/lib/amq/client/async/channel.rb +5 -6
- data/lib/amq/client/exceptions.rb +1 -1
- data/lib/amq/client/extensions/rabbitmq/cancel.rb +2 -2
- data/lib/amq/client/queue.rb +1 -0
- data/lib/amq/client/settings.rb +5 -7
- data/lib/amq/client/version.rb +1 -1
- data/spec/integration/coolio/basic_return_spec.rb +4 -4
- data/spec/integration/coolio/exchange_declare_spec.rb +1 -0
- data/spec/integration/eventmachine/basic_publish_with_framing_spec.rb +54 -0
- data/spec/integration/eventmachine/basic_return_spec.rb +3 -3
- data/spec/integration/eventmachine/concurrent_basic_publish_spec.rb +2 -2
- data/spec/integration/eventmachine/connection_start_spec.rb +0 -63
- data/spec/integration/eventmachine/exchange_declare_spec.rb +1 -0
- metadata +76 -63
- data/lib/amq/client/async/auth_mechanism_adapter.rb +0 -69
- data/lib/amq/client/async/auth_mechanism_adapter/external.rb +0 -27
- data/lib/amq/client/async/auth_mechanism_adapter/plain.rb +0 -24
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -3,23 +3,19 @@ bundler_args: --without development
|
|
3
3
|
before_script: ./bin/ci/before_build.sh
|
4
4
|
script: "bundle exec rspec spec"
|
5
5
|
rvm:
|
6
|
-
- jruby-19mode
|
7
6
|
- jruby-head
|
8
|
-
- 1.8.7
|
9
7
|
- rbx-19mode
|
10
|
-
- 1.9.2
|
11
8
|
- 1.9.3
|
9
|
+
- 1.9.2
|
10
|
+
- 1.8.7
|
12
11
|
gemfile:
|
13
12
|
- Gemfile
|
14
13
|
- gemfiles/eventmachine-pre
|
15
14
|
notifications:
|
16
15
|
recipients:
|
17
|
-
-
|
16
|
+
- michael@novemberain.com
|
18
17
|
branches:
|
19
18
|
only:
|
20
19
|
- master
|
21
20
|
- 0.9.x-stable
|
22
|
-
- 0.8.x-stable
|
23
|
-
|
24
|
-
services:
|
25
|
-
- rabbitmq
|
21
|
+
- 0.8.x-stable
|
data/Gemfile
CHANGED
@@ -11,6 +11,7 @@ extend Module.new {
|
|
11
11
|
|
12
12
|
local_path = File.expand_path("../vendor/#{name}", __FILE__)
|
13
13
|
if File.exist?(local_path)
|
14
|
+
puts "Using #{name} from #{local_path}..."
|
14
15
|
super name, options.merge(:path => local_path).
|
15
16
|
delete_if { |key, _| [:git, :branch].include?(key) }
|
16
17
|
else
|
data/amq-client.gemspec
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
# guest:guest has full access to /
|
4
|
+
|
5
|
+
sudo rabbitmqctl add_vhost /
|
6
|
+
sudo rabbitmqctl add_user guest guest
|
7
|
+
sudo rabbitmqctl set_permissions -p / guest ".*" ".*" ".*"
|
8
|
+
|
9
|
+
|
10
|
+
# guest:guest has full access to amq_client_testbed
|
11
|
+
# amq_client_gem:amq_client_gem has full access to /amq_client_testbed
|
12
|
+
|
13
|
+
sudo rabbitmqctl delete_vhost "amq_client_testbed"
|
14
|
+
sudo rabbitmqctl add_vhost "amq_client_testbed"
|
15
|
+
sudo rabbitmqctl delete_user amq_client_gem
|
16
|
+
sudo rabbitmqctl add_user amq_client_gem amq_client_gem_password
|
17
|
+
sudo rabbitmqctl set_permissions -p amq_client_testbed guest ".*" ".*" ".*"
|
18
|
+
sudo rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem ".*" ".*" ".*"
|
19
|
+
|
20
|
+
|
21
|
+
# amqp_gem_reader:reader_password has read access to amq_client_testbed
|
22
|
+
|
23
|
+
sudo rabbitmqctl add_user amq_client_gem_reader reader_password
|
24
|
+
sudo rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem_reader "^---$" "^---$" ".*"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
# guest:guest has full access to /
|
4
|
+
|
5
|
+
rabbitmqctl add_vhost /
|
6
|
+
rabbitmqctl add_user guest guest
|
7
|
+
rabbitmqctl set_permissions -p / guest ".*" ".*" ".*"
|
8
|
+
|
9
|
+
|
10
|
+
# guest:guest has full access to amq_client_testbed
|
11
|
+
# amq_client_gem:amq_client_gem has full access to /amq_client_testbed
|
12
|
+
|
13
|
+
rabbitmqctl delete_vhost "amq_client_testbed"
|
14
|
+
rabbitmqctl add_vhost "amq_client_testbed"
|
15
|
+
rabbitmqctl delete_user amq_client_gem
|
16
|
+
rabbitmqctl add_user amq_client_gem amq_client_gem_password
|
17
|
+
rabbitmqctl set_permissions -p amq_client_testbed guest ".*" ".*" ".*"
|
18
|
+
rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem ".*" ".*" ".*"
|
19
|
+
|
20
|
+
|
21
|
+
# amqp_gem_reader:reader_password has read access to amq_client_testbed
|
22
|
+
|
23
|
+
rabbitmqctl add_user amq_client_gem_reader reader_password
|
24
|
+
rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem_reader "^---$" "^---$" ".*"
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "amq/client/logging"
|
4
4
|
require "amq/client/settings"
|
5
|
-
require "amq/client/async/auth_mechanism_adapter"
|
6
5
|
require "amq/client/async/entity"
|
7
6
|
require "amq/client/async/channel"
|
8
7
|
|
@@ -275,15 +274,9 @@ module AMQ
|
|
275
274
|
# @return [Fixnum] Heartbeat interval this client uses, in seconds.
|
276
275
|
# @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.6)
|
277
276
|
def heartbeat_interval
|
278
|
-
@heartbeat_interval
|
277
|
+
@settings[:heartbeat] || @settings[:heartbeat_interval] || 3
|
279
278
|
end # heartbeat_interval
|
280
279
|
|
281
|
-
# Returns true if heartbeats are enabled (heartbeat interval is greater than 0)
|
282
|
-
# @return [Boolean]
|
283
|
-
def heartbeats_enabled?
|
284
|
-
@heartbeat_interval && (@heartbeat_interval > 0)
|
285
|
-
end
|
286
|
-
|
287
280
|
|
288
281
|
# vhost this connection uses. Default is "/", a historically estabilished convention
|
289
282
|
# of RabbitMQ and amqp gem.
|
@@ -369,8 +362,6 @@ module AMQ
|
|
369
362
|
# @private
|
370
363
|
# @api plugin
|
371
364
|
def handle_connection_interruption
|
372
|
-
self.cancel_heartbeat_sender
|
373
|
-
|
374
365
|
@channels.each { |n, c| c.handle_connection_interruption }
|
375
366
|
self.exec_callback_yielding_self(:after_connection_interruption)
|
376
367
|
end # handle_connection_interruption
|
@@ -512,17 +503,9 @@ module AMQ
|
|
512
503
|
# @api plugin
|
513
504
|
# @see http://tools.ietf.org/rfc/rfc2595.txt RFC 2595
|
514
505
|
def encode_credentials(username, password)
|
515
|
-
|
506
|
+
"\0#{username}\0#{password}"
|
516
507
|
end # encode_credentials(username, password)
|
517
508
|
|
518
|
-
# Retrieves an AuthMechanismAdapter that will encode credentials for
|
519
|
-
# this Adapter.
|
520
|
-
#
|
521
|
-
# @api plugin
|
522
|
-
def auth_mechanism_adapter
|
523
|
-
@auth_mechanism_adapter ||= AuthMechanismAdapter.for_adapter(self)
|
524
|
-
end
|
525
|
-
|
526
509
|
|
527
510
|
# Processes a single frame.
|
528
511
|
#
|
@@ -546,16 +529,10 @@ module AMQ
|
|
546
529
|
# @param [Array<AMQ::Protocol::Frame>] frames
|
547
530
|
# @api plugin
|
548
531
|
def receive_frameset(frames)
|
549
|
-
if self.heartbeats_enabled?
|
550
|
-
# treat incoming traffic as heartbeats.
|
551
|
-
# this operation is pretty expensive under heavy traffic but heartbeats can be disabled
|
552
|
-
# (and are also disabled by default). MK.
|
553
|
-
@last_server_heartbeat = Time.now
|
554
|
-
end
|
555
532
|
frame = frames.first
|
556
533
|
|
557
|
-
if
|
558
|
-
|
534
|
+
if Protocol::HeartbeatFrame === frame
|
535
|
+
@last_server_heartbeat = Time.now
|
559
536
|
else
|
560
537
|
if callable = AMQ::Client::HandlersRegistry.find(frame.method_class)
|
561
538
|
f = frames.shift
|
@@ -578,7 +555,7 @@ module AMQ
|
|
578
555
|
# Sends a heartbeat frame if connection is open.
|
579
556
|
# @api plugin
|
580
557
|
def send_heartbeat
|
581
|
-
if tcp_connection_established? && !@handling_skipped_hearbeats
|
558
|
+
if tcp_connection_established? && !@handling_skipped_hearbeats && @last_server_heartbeat
|
582
559
|
if @last_server_heartbeat < (Time.now - (self.heartbeat_interval * 2)) && !reconnecting?
|
583
560
|
logger.error "[amqp] Detected missing server heartbeats"
|
584
561
|
self.handle_skipped_hearbeats
|
@@ -611,7 +588,7 @@ module AMQ
|
|
611
588
|
# @status undefined. So lets do this. MK.
|
612
589
|
opening!
|
613
590
|
|
614
|
-
self.send_frame(Protocol::Connection::StartOk.encode(@client_properties, mechanism, self.encode_credentials(username, password), @locale))
|
591
|
+
self.send_frame(Protocol::Connection::StartOk.encode(@client_properties, @mechanism, self.encode_credentials(username, password), @locale))
|
615
592
|
end
|
616
593
|
|
617
594
|
|
@@ -619,16 +596,12 @@ module AMQ
|
|
619
596
|
#
|
620
597
|
# @api plugin
|
621
598
|
# @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.6)
|
622
|
-
def handle_tune(
|
623
|
-
@channel_max =
|
624
|
-
@frame_max =
|
625
|
-
|
626
|
-
client_heartbeat = @settings[:heartbeat] || @settings[:heartbeat_interval] || 0
|
627
|
-
|
628
|
-
@heartbeat_interval = negotiate_heartbeat_value(client_heartbeat, connection_tune.heartbeat)
|
599
|
+
def handle_tune(tune_ok)
|
600
|
+
@channel_max = tune_ok.channel_max.freeze
|
601
|
+
@frame_max = tune_ok.frame_max.freeze
|
602
|
+
@heartbeat_interval = self.heartbeat_interval || tune_ok.heartbeat
|
629
603
|
|
630
604
|
self.send_frame(Protocol::Connection::TuneOk.encode(@channel_max, [settings[:frame_max], @frame_max].min, @heartbeat_interval))
|
631
|
-
self.initialize_heartbeat_sender if heartbeats_enabled?
|
632
605
|
end # handle_tune(method)
|
633
606
|
|
634
607
|
|
@@ -667,14 +640,6 @@ module AMQ
|
|
667
640
|
|
668
641
|
protected
|
669
642
|
|
670
|
-
def negotiate_heartbeat_value(client_value, server_value)
|
671
|
-
if client_value == 0 || server_value == 0
|
672
|
-
[client_value, server_value].max
|
673
|
-
else
|
674
|
-
[client_value, server_value].min
|
675
|
-
end
|
676
|
-
end
|
677
|
-
|
678
643
|
# Returns next frame from buffer whenever possible
|
679
644
|
#
|
680
645
|
# @api private
|
@@ -31,7 +31,6 @@ module AMQ
|
|
31
31
|
# @option settings [String] :vhost ("/") Virtual host to use.
|
32
32
|
# @option settings [String] :user ("guest") Username to use for authentication.
|
33
33
|
# @option settings [String] :pass ("guest") Password to use for authentication.
|
34
|
-
# @option settings [String] :auth_mechanism ("PLAIN") SASL authentication mechanism to use.
|
35
34
|
# @option settings [String] :ssl (false) Should be use TLS (SSL) for connection?
|
36
35
|
# @option settings [String] :timeout (nil) Connection timeout.
|
37
36
|
# @option settings [String] :logging (false) Turns logging on or off.
|
@@ -165,7 +164,7 @@ module AMQ
|
|
165
164
|
raise self.class.authentication_failure_exception_class.new(settings)
|
166
165
|
}
|
167
166
|
|
168
|
-
@mechanism =
|
167
|
+
@mechanism = "PLAIN"
|
169
168
|
@locale = @settings.fetch(:locale, "en_GB")
|
170
169
|
@client_properties = Settings.client_properties.merge(@settings.fetch(:client_properties, Hash.new))
|
171
170
|
|
@@ -173,6 +172,10 @@ module AMQ
|
|
173
172
|
|
174
173
|
self.reset
|
175
174
|
self.set_pending_connect_timeout((@settings[:timeout] || 3).to_f) unless defined?(JRUBY_VERSION)
|
175
|
+
|
176
|
+
if self.heartbeat_interval > 0
|
177
|
+
self.initialize_heartbeat_sender
|
178
|
+
end
|
176
179
|
end # initialize(*args)
|
177
180
|
|
178
181
|
|
@@ -266,6 +269,8 @@ module AMQ
|
|
266
269
|
@handling_skipped_hearbeats = false
|
267
270
|
@last_server_heartbeat = Time.now
|
268
271
|
|
272
|
+
self.initialize_heartbeat_sender if self.heartbeat_interval > 0
|
273
|
+
|
269
274
|
self.handshake
|
270
275
|
end
|
271
276
|
|
@@ -353,7 +358,7 @@ module AMQ
|
|
353
358
|
def handle_skipped_hearbeats
|
354
359
|
if !@handling_skipped_hearbeats && @tcp_connection_established && !@intentionally_closing_connection
|
355
360
|
@handling_skipped_hearbeats = true
|
356
|
-
|
361
|
+
@heartbeats_timer.cancel
|
357
362
|
|
358
363
|
self.run_skipped_heartbeats_callbacks
|
359
364
|
end
|
@@ -365,11 +370,6 @@ module AMQ
|
|
365
370
|
@heartbeats_timer = EventMachine::PeriodicTimer.new(self.heartbeat_interval, &method(:send_heartbeat))
|
366
371
|
end
|
367
372
|
|
368
|
-
# @private
|
369
|
-
def cancel_heartbeat_sender
|
370
|
-
@heartbeats_timer.cancel if @heartbeats_timer
|
371
|
-
end
|
372
|
-
|
373
373
|
|
374
374
|
|
375
375
|
self.handle(Protocol::Connection::Start) do |connection, frame|
|
@@ -133,7 +133,7 @@ module AMQ
|
|
133
133
|
# Acknowledge one or all messages on the channel.
|
134
134
|
#
|
135
135
|
# @api public
|
136
|
-
# @see
|
136
|
+
# @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.13.)
|
137
137
|
def acknowledge(delivery_tag, multiple = false)
|
138
138
|
@connection.send_frame(Protocol::Basic::Ack.encode(self.id, delivery_tag, multiple))
|
139
139
|
|
@@ -143,7 +143,7 @@ module AMQ
|
|
143
143
|
# Reject a message with given delivery tag.
|
144
144
|
#
|
145
145
|
# @api public
|
146
|
-
# @see
|
146
|
+
# @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.14.)
|
147
147
|
def reject(delivery_tag, requeue = true)
|
148
148
|
@connection.send_frame(Protocol::Basic::Reject.encode(self.id, delivery_tag, requeue))
|
149
149
|
|
@@ -156,7 +156,7 @@ module AMQ
|
|
156
156
|
# @return [Channel] self
|
157
157
|
#
|
158
158
|
# @note RabbitMQ as of 2.3.1 does not support basic.recover with requeue = false.
|
159
|
-
# @see
|
159
|
+
# @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.16.)
|
160
160
|
# @api public
|
161
161
|
def recover(requeue = true, &block)
|
162
162
|
@connection.send_frame(Protocol::Basic::Recover.encode(@id, requeue))
|
@@ -181,7 +181,7 @@ module AMQ
|
|
181
181
|
|
182
182
|
self.redefine_callback :qos, &block
|
183
183
|
self
|
184
|
-
end # qos
|
184
|
+
end # qos(prefetch_size = 4096, prefetch_count = 32, global = false, &block)
|
185
185
|
|
186
186
|
# Asks the peer to pause or restart the flow of content data sent to a consumer.
|
187
187
|
# This is a simple flowcontrol mechanism that a peer can use to avoid overflowing its
|
@@ -191,7 +191,7 @@ module AMQ
|
|
191
191
|
#
|
192
192
|
# @param [Boolean] active Desired flow state.
|
193
193
|
#
|
194
|
-
# @see
|
194
|
+
# @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.5.2.3.)
|
195
195
|
# @api public
|
196
196
|
def flow(active = false, &block)
|
197
197
|
@connection.send_frame(Protocol::Channel::Flow.encode(@id, active))
|
@@ -413,7 +413,6 @@ module AMQ
|
|
413
413
|
def handle_close(channel_close)
|
414
414
|
self.status = :closed
|
415
415
|
self.connection.clear_frames_on(self.id)
|
416
|
-
|
417
416
|
self.exec_callback_yielding_self(:error, channel_close)
|
418
417
|
|
419
418
|
self.handle_connection_interruption(channel_close)
|
@@ -18,7 +18,7 @@ module AMQ
|
|
18
18
|
def initialize(settings)
|
19
19
|
@settings = settings
|
20
20
|
|
21
|
-
super("Could not
|
21
|
+
super("Could not establish TCP connection to #{@settings[:host]}:#{@settings[:port]}")
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
require "amq/client/async/extensions/rabbitmq/cancel"
|
4
4
|
|
5
|
-
# Basic.
|
5
|
+
# Basic.Nack
|
6
6
|
module AMQ
|
7
7
|
module Client
|
8
8
|
# backwards compatibility
|
9
9
|
# @private
|
10
10
|
Extensions = Async::Extensions unless defined?(Extensions)
|
11
|
-
|
11
|
+
|
12
12
|
module Settings
|
13
13
|
CLIENT_PROPERTIES[:capabilities] ||= {}
|
14
14
|
CLIENT_PROPERTIES[:capabilities][:consumer_cancel_notify] = true
|
data/lib/amq/client/queue.rb
CHANGED
data/lib/amq/client/settings.rb
CHANGED
@@ -23,10 +23,9 @@ module AMQ
|
|
23
23
|
:port => AMQ::Protocol::DEFAULT_PORT,
|
24
24
|
|
25
25
|
# login
|
26
|
-
:user
|
27
|
-
:pass
|
28
|
-
:
|
29
|
-
:vhost => "/",
|
26
|
+
:user => "guest",
|
27
|
+
:pass => "guest",
|
28
|
+
:vhost => "/",
|
30
29
|
|
31
30
|
# connection timeout
|
32
31
|
:timeout => nil,
|
@@ -41,8 +40,7 @@ module AMQ
|
|
41
40
|
# if you want to load broker-specific extensions
|
42
41
|
:broker => nil,
|
43
42
|
|
44
|
-
:frame_max => 131072
|
45
|
-
:heartbeat => 0
|
43
|
+
:frame_max => 131072
|
46
44
|
}
|
47
45
|
end
|
48
46
|
|
@@ -52,7 +50,7 @@ module AMQ
|
|
52
50
|
:information => "http://github.com/ruby-amqp/amq-client",
|
53
51
|
:version => AMQ::Client::VERSION
|
54
52
|
}
|
55
|
-
|
53
|
+
|
56
54
|
def self.client_properties
|
57
55
|
@client_properties ||= CLIENT_PROPERTIES
|
58
56
|
end
|
data/lib/amq/client/version.rb
CHANGED
@@ -15,7 +15,7 @@ describe "AMQ::Client::CoolioClient", "Basic.Return", :nojruby => true do
|
|
15
15
|
coolio_amqp_connect do |client|
|
16
16
|
channel = AMQ::Client::Channel.new(client, 1)
|
17
17
|
channel.open do
|
18
|
-
queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false,
|
18
|
+
queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true)
|
19
19
|
|
20
20
|
# need to delete the queue manually because we don't start consumption,
|
21
21
|
# hence, no auto-delete
|
@@ -26,14 +26,14 @@ describe "AMQ::Client::CoolioClient", "Basic.Return", :nojruby => true do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
messages.each do |message|
|
29
|
-
exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {},
|
29
|
+
exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {}, false, true)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
done(0.6) { @returned_messages.size == messages.size }
|
34
34
|
end
|
35
35
|
|
36
|
-
@returned_messages.should == ["
|
36
|
+
@returned_messages.should == ["NO_CONSUMERS"] * messages.size
|
37
37
|
end
|
38
38
|
end
|
39
|
-
end
|
39
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'integration/eventmachine/spec_helper'
|
5
|
+
|
6
|
+
require "multi_json"
|
7
|
+
|
8
|
+
describe AMQ::Client::EventMachineClient, "Basic.Publish" do
|
9
|
+
include EventedSpec::SpecHelper
|
10
|
+
default_timeout 21.0
|
11
|
+
|
12
|
+
context "when message size exceeds negotiated frame size" do
|
13
|
+
let(:message) { "z" * 1024 * 1024 * 8 }
|
14
|
+
|
15
|
+
it "correctly frames things" do
|
16
|
+
@received_messages = []
|
17
|
+
|
18
|
+
@received_messages = []
|
19
|
+
em_amqp_connect do |client|
|
20
|
+
client.on_error do |conn, connection_close|
|
21
|
+
fail "Handling a connection-level exception: #{connection_close.reply_text}"
|
22
|
+
end
|
23
|
+
|
24
|
+
channel = AMQ::Client::Channel.new(client, 1)
|
25
|
+
channel.open do
|
26
|
+
queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true)
|
27
|
+
queue.bind("amq.fanout")
|
28
|
+
|
29
|
+
queue.consume(true) do |amq_method|
|
30
|
+
queue.on_delivery do |method, header, payload|
|
31
|
+
@received_messages << payload
|
32
|
+
end
|
33
|
+
|
34
|
+
exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout)
|
35
|
+
EventMachine.add_timer(2.0) do
|
36
|
+
30.times do
|
37
|
+
Thread.new do
|
38
|
+
exchange.publish(message, queue.name, {}, false, true)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
done(14.0) {
|
45
|
+
# we don't care about the exact number, just the fact that there are
|
46
|
+
# no UNEXPECTED_FRAME connection-level exceptions. MK.
|
47
|
+
@received_messages.size.should > 10
|
48
|
+
@received_messages.all? {|m| m == message}.should be_true
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end # em_amqp_connect
|
52
|
+
end # it
|
53
|
+
end # context
|
54
|
+
end # describe
|
@@ -25,7 +25,7 @@ describe AMQ::Client::EventMachineClient, "Basic.Return" do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
messages.each do |message|
|
28
|
-
exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {},
|
28
|
+
exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {}, false, true)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -34,7 +34,7 @@ describe AMQ::Client::EventMachineClient, "Basic.Return" do
|
|
34
34
|
}
|
35
35
|
end
|
36
36
|
|
37
|
-
@returned_messages.should == ["
|
37
|
+
@returned_messages.should == ["NO_CONSUMERS"] * messages.size
|
38
38
|
end
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|
@@ -57,7 +57,7 @@ if mri?
|
|
57
57
|
30.times do
|
58
58
|
Thread.new do
|
59
59
|
messages.each do |message|
|
60
|
-
exchange.publish(message, queue.name, {}, false,
|
60
|
+
exchange.publish(message, queue.name, {}, false, true)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
@@ -76,4 +76,4 @@ if mri?
|
|
76
76
|
end # it
|
77
77
|
end # context
|
78
78
|
end # describe
|
79
|
-
end
|
79
|
+
end
|
@@ -10,69 +10,6 @@ describe AMQ::Client::EventMachineClient, "Connection.Start" do
|
|
10
10
|
include EventedSpec::SpecHelper
|
11
11
|
default_timeout 0.5
|
12
12
|
|
13
|
-
it "uses PLAIN authentication by default" do
|
14
|
-
em do
|
15
|
-
AMQ::Client::EventMachineClient.new(0).mechanism.should eq "PLAIN"
|
16
|
-
done
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
it "uses PLAIN authentication when explicitly set" do
|
21
|
-
em do
|
22
|
-
AMQ::Client::EventMachineClient.new(0, :auth_mechanism => "PLAIN").mechanism.should eq "PLAIN"
|
23
|
-
done
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
it "properly encodes username and password for PLAIN authentication" do
|
28
|
-
em do
|
29
|
-
client = AMQ::Client::EventMachineClient.new 0, :auth_mechanism => "PLAIN"
|
30
|
-
client.encode_credentials("user", "pass").should eq "\0user\0pass"
|
31
|
-
done
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
it "uses EXTERNAL authentication when explicitly set" do
|
36
|
-
em do
|
37
|
-
AMQ::Client::EventMachineClient.new(0, :auth_mechanism => "EXTERNAL").mechanism.should eq "EXTERNAL"
|
38
|
-
done
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
it "skips encoding username and password for EXTERNAL authentication" do
|
43
|
-
em do
|
44
|
-
client = AMQ::Client::EventMachineClient.new 0, :auth_mechanism => "EXTERNAL"
|
45
|
-
client.encode_credentials("user", "pass").should eq ""
|
46
|
-
done
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
it "allows user-defined authentication mechanisms" do
|
51
|
-
Class.new AMQ::Client::Async::AuthMechanismAdapter do
|
52
|
-
auth_mechanism "FOO"
|
53
|
-
|
54
|
-
def encode_credentials(username, password)
|
55
|
-
"foo"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
em do
|
60
|
-
client = AMQ::Client::EventMachineClient.new 0, :auth_mechanism => "FOO"
|
61
|
-
client.encode_credentials("user", "pass").should eq "foo"
|
62
|
-
done
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
it "fails for unimplemented authentication mechanisms" do
|
67
|
-
em do
|
68
|
-
client = AMQ::Client::EventMachineClient.new 0, :auth_mechanism => "BAR"
|
69
|
-
expect do
|
70
|
-
client.encode_credentials("user", "pass")
|
71
|
-
end.to raise_error(NotImplementedError)
|
72
|
-
done
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
13
|
context "with valid credentials" do
|
77
14
|
it "should trigger the callback" do
|
78
15
|
em do
|
metadata
CHANGED
@@ -1,68 +1,73 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: amq-client
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: -2724271480
|
5
|
+
prerelease: 6
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
- pre
|
11
|
+
- 1
|
12
|
+
version: 1.0.0.pre1
|
6
13
|
platform: ruby
|
7
|
-
authors:
|
14
|
+
authors:
|
8
15
|
- Jakub Stastny
|
9
16
|
- Michael S. Klishin
|
10
17
|
- Theo Hultberg
|
11
18
|
- Mark Abramov
|
12
|
-
autorequire:
|
19
|
+
autorequire:
|
13
20
|
bindir: bin
|
14
21
|
cert_chain: []
|
15
|
-
|
16
|
-
|
17
|
-
|
22
|
+
|
23
|
+
date: 2012-06-22 00:00:00 Z
|
24
|
+
dependencies:
|
25
|
+
- !ruby/object:Gem::Dependency
|
18
26
|
name: eventmachine
|
19
|
-
|
20
|
-
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: !binary |-
|
24
|
-
MA==
|
27
|
+
prerelease: false
|
28
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
29
|
none: false
|
26
|
-
|
27
|
-
requirements:
|
30
|
+
requirements:
|
28
31
|
- - ">="
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
hash: 3
|
34
|
+
segments:
|
35
|
+
- 0
|
36
|
+
version: "0"
|
34
37
|
type: :runtime
|
35
|
-
|
38
|
+
version_requirements: *id001
|
39
|
+
- !ruby/object:Gem::Dependency
|
36
40
|
name: amq-protocol
|
37
|
-
|
38
|
-
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: 1.2.0
|
41
|
+
prerelease: false
|
42
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
43
|
none: false
|
43
|
-
|
44
|
-
requirements:
|
44
|
+
requirements:
|
45
45
|
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
hash: 59
|
48
|
+
segments:
|
49
|
+
- 0
|
50
|
+
- 9
|
51
|
+
- 0
|
52
|
+
version: 0.9.0
|
50
53
|
type: :runtime
|
54
|
+
version_requirements: *id002
|
51
55
|
description: amq-client is a fully-featured, low-level AMQP 0.9.1 client with pluggable networking I/O adapters (EventMachine, cool.io, Eventpanda and so on) and supposed to back more opinionated AMQP clients (such as amqp gem) or be used directly in cases when access to more advanced AMQP 0.9.1 features is more important that convenient APIs
|
52
|
-
email:
|
53
|
-
-
|
54
|
-
c3Rhc3RueUAxMDFpZGVhcy5jeg==
|
56
|
+
email:
|
57
|
+
- stastny@101ideas.cz
|
55
58
|
- michael@novemberain.com
|
56
59
|
executables: []
|
60
|
+
|
57
61
|
extensions: []
|
58
|
-
|
62
|
+
|
63
|
+
extra_rdoc_files:
|
59
64
|
- README.textile
|
60
|
-
files:
|
61
|
-
-
|
62
|
-
-
|
63
|
-
-
|
64
|
-
-
|
65
|
-
-
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- .gitmodules
|
68
|
+
- .rspec
|
69
|
+
- .travis.yml
|
70
|
+
- .yardopts
|
66
71
|
- Gemfile
|
67
72
|
- LICENSE
|
68
73
|
- README.textile
|
@@ -148,9 +153,6 @@ files:
|
|
148
153
|
- lib/amq/client/async/adapters/coolio.rb
|
149
154
|
- lib/amq/client/async/adapters/event_machine.rb
|
150
155
|
- lib/amq/client/async/adapters/eventmachine.rb
|
151
|
-
- lib/amq/client/async/auth_mechanism_adapter.rb
|
152
|
-
- lib/amq/client/async/auth_mechanism_adapter/external.rb
|
153
|
-
- lib/amq/client/async/auth_mechanism_adapter/plain.rb
|
154
156
|
- lib/amq/client/async/callbacks.rb
|
155
157
|
- lib/amq/client/async/channel.rb
|
156
158
|
- lib/amq/client/async/consumer.rb
|
@@ -201,6 +203,7 @@ files:
|
|
201
203
|
- spec/integration/eventmachine/basic_cancel_spec.rb
|
202
204
|
- spec/integration/eventmachine/basic_consume_spec.rb
|
203
205
|
- spec/integration/eventmachine/basic_get_spec.rb
|
206
|
+
- spec/integration/eventmachine/basic_publish_with_framing_spec.rb
|
204
207
|
- spec/integration/eventmachine/basic_return_spec.rb
|
205
208
|
- spec/integration/eventmachine/channel_close_spec.rb
|
206
209
|
- spec/integration/eventmachine/channel_flow_spec.rb
|
@@ -224,29 +227,39 @@ files:
|
|
224
227
|
- tasks.rb
|
225
228
|
homepage: http://github.com/ruby-amqp/amq-client
|
226
229
|
licenses: []
|
227
|
-
|
230
|
+
|
231
|
+
post_install_message:
|
228
232
|
rdoc_options: []
|
229
|
-
|
233
|
+
|
234
|
+
require_paths:
|
230
235
|
- lib
|
231
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
232
|
-
requirements:
|
233
|
-
- - ">="
|
234
|
-
- !ruby/object:Gem::Version
|
235
|
-
version: !binary |-
|
236
|
-
MA==
|
236
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
237
237
|
none: false
|
238
|
-
|
239
|
-
requirements:
|
238
|
+
requirements:
|
240
239
|
- - ">="
|
241
|
-
- !ruby/object:Gem::Version
|
242
|
-
|
243
|
-
|
240
|
+
- !ruby/object:Gem::Version
|
241
|
+
hash: 3
|
242
|
+
segments:
|
243
|
+
- 0
|
244
|
+
version: "0"
|
245
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
244
246
|
none: false
|
247
|
+
requirements:
|
248
|
+
- - ">"
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
hash: 25
|
251
|
+
segments:
|
252
|
+
- 1
|
253
|
+
- 3
|
254
|
+
- 1
|
255
|
+
version: 1.3.1
|
245
256
|
requirements: []
|
257
|
+
|
246
258
|
rubyforge_project: amq-client
|
247
|
-
rubygems_version: 1.8.
|
248
|
-
signing_key:
|
259
|
+
rubygems_version: 1.8.15
|
260
|
+
signing_key:
|
249
261
|
specification_version: 3
|
250
262
|
summary: amq-client is a fully-featured, low-level AMQP 0.9.1 client
|
251
263
|
test_files: []
|
252
|
-
|
264
|
+
|
265
|
+
has_rdoc:
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module AMQ::Client::Async
|
4
|
-
# Provides a flexible method for encoding AMQP credentials. PLAIN and
|
5
|
-
# EXTERNAL are provided by this gem. In order to implement a new
|
6
|
-
# authentication mechanism, create a subclass like so:
|
7
|
-
#
|
8
|
-
# class MyAuthMechanism < AMQ::Client::Async::AuthMechanismAdapter
|
9
|
-
# auth_mechanism "X-MYAUTH"
|
10
|
-
#
|
11
|
-
# def encode_credentials(username, password)
|
12
|
-
# # ...
|
13
|
-
# end
|
14
|
-
# end
|
15
|
-
class AuthMechanismAdapter
|
16
|
-
|
17
|
-
# Find and instantiate an AuthMechanismAdapter.
|
18
|
-
#
|
19
|
-
# @param [Adapter] adapter The Adapter for which to encode credentials.
|
20
|
-
# @return [AuthMechanismAdapter] An AuthMechanismAdapter that can encode
|
21
|
-
# credentials for the Adapter.
|
22
|
-
# @raise [NotImplementedError] The Adapter's mechanism does not
|
23
|
-
# correspond to any known AuthMechanismAdapter.
|
24
|
-
def self.for_adapter(adapter)
|
25
|
-
registry[adapter.mechanism].new adapter
|
26
|
-
end
|
27
|
-
|
28
|
-
protected
|
29
|
-
|
30
|
-
# Used by subclasses to declare the mechanisms that an
|
31
|
-
# AuthMechanismAdapter understands.
|
32
|
-
#
|
33
|
-
# @param [Array<String>] mechanisms One or more mechanisms that can be
|
34
|
-
# handled by the subclass.
|
35
|
-
def self.auth_mechanism(*mechanisms)
|
36
|
-
mechanisms.each {|mechanism| registry[mechanism] = self}
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
# Accesses the registry of AuthMechanismAdapter subclasses. Keys in
|
42
|
-
# this hash are the names of the authentication mechanisms; values are
|
43
|
-
# the classes that handle them. Referencing an unknown mechanism from
|
44
|
-
# this Hash will raise NotImplementedError.
|
45
|
-
def self.registry
|
46
|
-
@@registry ||= Hash.new {raise NotImplementedError}
|
47
|
-
end
|
48
|
-
|
49
|
-
public
|
50
|
-
|
51
|
-
# The Adapter that this AuthMechanismAdapter operates on behalf of.
|
52
|
-
attr_reader :adapter
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
# Create a new AuthMechanismAdapter. Users of this class should instead
|
57
|
-
# retrieve an instance through for_adapter.
|
58
|
-
def initialize(adapter)
|
59
|
-
@adapter = adapter
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# pre-require builtin auth mechanisms
|
65
|
-
Dir[File.join(File.dirname(__FILE__),
|
66
|
-
File.basename(__FILE__, '.rb'),
|
67
|
-
'*')].each do |f|
|
68
|
-
require f
|
69
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module AMQ::Client::Async
|
4
|
-
|
5
|
-
# Manages the encoding of credentials for the EXTERNAL authentication
|
6
|
-
# mechanism.
|
7
|
-
class AuthMechanismAdapter::External < AuthMechanismAdapter
|
8
|
-
|
9
|
-
auth_mechanism "EXTERNAL"
|
10
|
-
|
11
|
-
# Encodes a username and password for the EXTERNAL mechanism. Since
|
12
|
-
# authentication is handled by an encapsulating protocol like SSL or
|
13
|
-
# UNIX domain sockets, EXTERNAL doesn't pass along any username or
|
14
|
-
# password information at all and this method always returns the
|
15
|
-
# empty string.
|
16
|
-
#
|
17
|
-
# @param [String] username The username to encode. This parameter is
|
18
|
-
# ignored.
|
19
|
-
# @param [String] password The password to encode. This parameter is
|
20
|
-
# ignored.
|
21
|
-
# @return [String] The username and password, encoded for the
|
22
|
-
# EXTERNAL mechanism. This is always the empty string.
|
23
|
-
def encode_credentials(username, password)
|
24
|
-
""
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module AMQ::Client::Async
|
4
|
-
|
5
|
-
# Manages the encoding of credentials for the PLAIN authentication
|
6
|
-
# mechanism.
|
7
|
-
class AuthMechanismAdapter::Plain < AuthMechanismAdapter
|
8
|
-
|
9
|
-
auth_mechanism "PLAIN"
|
10
|
-
|
11
|
-
# Encodes credentials for the given username and password. This
|
12
|
-
# involves sending the password across the wire in plaintext, so
|
13
|
-
# PLAIN authentication should only be used over a secure transport
|
14
|
-
# layer.
|
15
|
-
#
|
16
|
-
# @param [String] username The username to encode.
|
17
|
-
# @param [String] password The password to encode.
|
18
|
-
# @return [String] The username and password, encoded for the PLAIN
|
19
|
-
# mechanism.
|
20
|
-
def encode_credentials(username, password)
|
21
|
-
"\0#{username}\0#{password}"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|