amqp 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -1
- data/.travis.yml +9 -0
- data/CHANGELOG +7 -0
- data/Gemfile +16 -5
- data/Rakefile +6 -0
- data/amqp.gemspec +2 -12
- data/bin/set_test_suite_realms_up.sh +2 -16
- data/examples/automatic_binding_for_default_direct_exchange.rb +5 -5
- data/examples/default_channel.rb +19 -0
- data/examples/immediately_bind_a_server_named_queue.rb +38 -0
- data/examples/issues/issue_75.rb +21 -0
- data/gemfiles/eventmachine-pre +24 -0
- data/lib/amqp/channel.rb +52 -7
- data/lib/amqp/client.rb +76 -9
- data/lib/amqp/connection.rb +6 -1
- data/lib/amqp/queue.rb +15 -4
- data/lib/amqp/version.rb +1 -1
- data/lib/mq.rb +1 -2
- data/spec/integration/authentication_spec.rb +18 -16
- data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +7 -5
- data/spec/integration/channel_close_spec.rb +1 -1
- data/spec/integration/exchange_declaration_spec.rb +54 -7
- data/spec/integration/queue_declaration_spec.rb +18 -15
- data/spec/integration/queue_exclusivity_spec.rb +14 -12
- data/spec/integration/reply_queue_communication_spec.rb +2 -2
- data/spec/integration/store_and_forward_spec.rb +3 -3
- data/spec/integration/topic_subscription_spec.rb +1 -2
- data/spec/integration/workload_distribution_spec.rb +1 -2
- data/spec/spec_helper.rb +7 -2
- data/spec/unit/amqp/basic_spec.rb +1 -1
- data/spec/unit/amqp/client_spec.rb +102 -0
- data/spec/unit/amqp/connection_spec.rb +4 -2
- metadata +73 -13
- data/bin/jenkins.sh +0 -25
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
= Version 0.7.2
|
2
|
+
|
3
|
+
* [BUG] Server-named queues declared en masse now get their unique names instead of all beign assigned the first generated name
|
4
|
+
* [API] Connection URI (string) format for vhosts no longer assumes that vhosts begin with a slash (/), learn more at http://bit.ly/mfzwcB
|
5
|
+
* [BUG] Heartbeats broken for long running tasks [#43]
|
6
|
+
* [BUG] Queue#reset leaks consumer tags [#40].
|
7
|
+
|
1
8
|
= Version 0.7.1
|
2
9
|
|
3
10
|
* [BUG] AMQP gem no longer conflicts with Builder 2.1.2 on Ruby 1.9.
|
data/Gemfile
CHANGED
@@ -1,13 +1,24 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
source
|
3
|
+
source :rubygems
|
4
|
+
|
5
|
+
# Use local clones if possible.
|
6
|
+
# If you want to use your local copy, just symlink it to vendor.
|
7
|
+
def custom_gem(name, options = Hash.new)
|
8
|
+
local_path = File.expand_path("../vendor/#{name}", __FILE__)
|
9
|
+
if File.exist?(local_path)
|
10
|
+
gem name, options.merge(:path => local_path).delete_if { |key, _| [:git, :branch].include?(key) }
|
11
|
+
else
|
12
|
+
gem name, options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
4
16
|
|
5
17
|
gem "eventmachine"
|
6
|
-
gem "json" if RUBY_VERSION < "1.9" || ARGV.first == "install"
|
7
|
-
gem "amq-client", :git => "git://github.com/ruby-amqp/amq-client.git", :branch => "master"
|
8
18
|
|
9
19
|
group(:test) do
|
10
20
|
gem "rspec", ">=2.0.0"
|
11
|
-
|
12
|
-
gem "amqp-spec", :git => "git://github.com/ruby-amqp/amqp-spec.git", :branch => "master"
|
21
|
+
gem "rake"
|
22
|
+
# gem "amqp-spec", :git => "git://github.com/ruby-amqp/amqp-spec.git", :branch => "master"
|
23
|
+
custom_gem "evented-spec", :git => "git://github.com/ruby-amqp/evented-spec.git", :branch => "master"
|
13
24
|
end
|
data/Rakefile
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
+
require 'fileutils'
|
1
2
|
require 'rspec/core/rake_task'
|
2
3
|
|
3
4
|
desc "Run spec suite (uses Rspec2)"
|
4
5
|
RSpec::Core::RakeTask.new(:spec) { |t|}
|
5
6
|
|
7
|
+
namespace :spec do
|
8
|
+
desc "Clean up rbx compiled files and run spec suite"
|
9
|
+
RSpec::Core::RakeTask.new(:ci) { |t| Dir.glob("**/*.rbc").each {|f| FileUtils.rm_f(f) } }
|
10
|
+
end
|
11
|
+
|
6
12
|
desc "Run specs with RCov"
|
7
13
|
RSpec::Core::RakeTask.new(:rcov) do |t|
|
8
14
|
t.rcov = true
|
data/amqp.gemspec
CHANGED
@@ -10,8 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.authors = ["Aman Gupta", "Jakub Stastny aka botanicus", "Michael S. Klishin"]
|
11
11
|
s.homepage = "http://github.com/ruby-amqp/amqp"
|
12
12
|
s.summary = "AMQP client implementation in Ruby/EventMachine."
|
13
|
-
s.description = "
|
14
|
-
s.cert_chain = nil
|
13
|
+
s.description = "Asynchronous AMQP 0.9.1 client for Ruby. Built on top of Eventmachine."
|
15
14
|
s.email = ["bWljaGFlbEBub3ZlbWJlcmFpbi5jb20=\n", "c3Rhc3RueUAxMDFpZGVhcy5jeg==\n"].map { |i| Base64.decode64(i) }
|
16
15
|
|
17
16
|
# files
|
@@ -19,20 +18,11 @@ Gem::Specification.new do |s|
|
|
19
18
|
s.require_paths = ["lib"]
|
20
19
|
|
21
20
|
# RDoc
|
22
|
-
s.has_rdoc = true
|
23
21
|
s.rdoc_options = '--include=examples --main README.md'
|
24
22
|
s.extra_rdoc_files = ["README.md"] + Dir.glob("doc/*")
|
25
23
|
|
26
24
|
# Dependencies
|
27
|
-
s.add_dependency "eventmachine"
|
28
|
-
|
29
|
-
begin
|
30
|
-
require "changelog"
|
31
|
-
rescue LoadError
|
32
|
-
warn "You have to have changelog gem installed for post install message"
|
33
|
-
else
|
34
|
-
s.post_install_message = CHANGELOG.new.version_changes
|
35
|
-
end
|
25
|
+
s.add_dependency "eventmachine"
|
36
26
|
|
37
27
|
# RubyForge
|
38
28
|
s.rubyforge_project = "amqp"
|
@@ -1,21 +1,7 @@
|
|
1
1
|
#!/bin/sh
|
2
2
|
|
3
|
-
# guest:guest has full access to /
|
3
|
+
# guest:guest has full access to /amqp_gem_07x_stable_testbed
|
4
4
|
|
5
|
-
rabbitmqctl add_vhost /
|
5
|
+
rabbitmqctl add_vhost /amqp_gem_07x_stable_testbed
|
6
6
|
rabbitmqctl add_user guest guest
|
7
7
|
rabbitmqctl set_permissions -p / guest ".*" ".*" ".*"
|
8
|
-
|
9
|
-
|
10
|
-
# amqp_gem:amqp_gem_password has full access to /amqp_gem_testbed
|
11
|
-
|
12
|
-
rabbitmqctl add_vhost /amqp_gem_testbed
|
13
|
-
rabbitmqctl add_user amqp_gem amqp_gem_password
|
14
|
-
rabbitmqctl set_permissions -p /amqp_gem_testbed amqp_gem ".*" ".*" ".*"
|
15
|
-
|
16
|
-
|
17
|
-
# amqp_gem_reader:reader_password has read access to /amqp_gem_testbed
|
18
|
-
|
19
|
-
rabbitmqctl add_user amqp_gem_reader reader_password
|
20
|
-
rabbitmqctl clear_permissions -p /amqp_gem_testbed guest
|
21
|
-
rabbitmqctl set_permissions -p /amqp_gem_testbed amqp_gem_reader "^---$" "^---$" ".*"
|
@@ -20,7 +20,7 @@ end
|
|
20
20
|
|
21
21
|
EM.run do
|
22
22
|
connection = AMQP.connect
|
23
|
-
|
23
|
+
ch = AMQP::Channel.new(connection)
|
24
24
|
|
25
25
|
show_stopper = Proc.new do
|
26
26
|
$stdout.puts "Stopping..."
|
@@ -35,14 +35,14 @@ EM.run do
|
|
35
35
|
|
36
36
|
$stdout.puts "Bound! Running #{AMQP::VERSION} version of the gem."
|
37
37
|
|
38
|
-
queue1 =
|
39
|
-
queue2 =
|
40
|
-
queue3 =
|
38
|
+
queue1 = ch.queue("queue1")
|
39
|
+
queue2 = ch.queue("queue2")
|
40
|
+
queue3 = ch.queue("queue3")
|
41
41
|
|
42
42
|
queues = [queue1, queue2, queue3]
|
43
43
|
|
44
44
|
# Rely on default direct exchange binding, see section 2.1.2.4 Automatic Mode in AMQP 0.9.1 spec.
|
45
|
-
exchange =
|
45
|
+
exchange = ch.default_exchange
|
46
46
|
|
47
47
|
queue1.subscribe do |payload|
|
48
48
|
puts "Got #{payload} for #{queue1.name}"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
4
|
+
require 'amqp'
|
5
|
+
|
6
|
+
AMQP.start(:host => 'localhost') do |connection|
|
7
|
+
|
8
|
+
# Send Connection.Close on Ctrl+C
|
9
|
+
trap(:INT) do
|
10
|
+
AMQP.stop do
|
11
|
+
puts "Closing and AMQP.channel is #{AMQP.channel.open? ? 'open' : 'closed'}"
|
12
|
+
exit
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
puts "AMQP.connection is #{AMQP.connection}"
|
17
|
+
puts "AMQP.channel is #{AMQP.channel}"
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
8
|
+
|
9
|
+
require 'amqp'
|
10
|
+
|
11
|
+
|
12
|
+
puts "=> AMQP gem #{AMQP::VERSION}"
|
13
|
+
puts
|
14
|
+
AMQP.start do |connection|
|
15
|
+
channel = AMQP::Channel.new
|
16
|
+
puts "Channel ##{channel.channel} is now open!"
|
17
|
+
|
18
|
+
xchange = channel.fanout("amq.fanout")
|
19
|
+
q = AMQP::Queue.new(channel, "", :auto_delete => true).bind(xchange).subscribe do |header, payload|
|
20
|
+
puts "Got a payload: #{payload}"
|
21
|
+
end
|
22
|
+
|
23
|
+
EventMachine.add_periodic_timer(0.5) {
|
24
|
+
xchange.publish("à bientôt!", :key => q.name)
|
25
|
+
}
|
26
|
+
|
27
|
+
|
28
|
+
show_stopper = Proc.new do
|
29
|
+
$stdout.puts "Stopping..."
|
30
|
+
|
31
|
+
connection.close {
|
32
|
+
EM.stop { exit }
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
Signal.trap "INT", show_stopper
|
37
|
+
EM.add_timer(3, show_stopper)
|
38
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup
|
6
|
+
|
7
|
+
$:.unshift(File.expand_path("../../../lib", __FILE__))
|
8
|
+
|
9
|
+
require 'amqp'
|
10
|
+
|
11
|
+
AMQP.start(:host => "localhost") do |connection|
|
12
|
+
channel = AMQP::Channel.new(connection)
|
13
|
+
channel.fanout("logs.nad", :auto_delete => false)
|
14
|
+
channel.fanout("logs.ad", :auto_delete => true)
|
15
|
+
|
16
|
+
EM.add_timer(1) do
|
17
|
+
connection.close do
|
18
|
+
EM.stop { exit }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
source :rubygems
|
4
|
+
|
5
|
+
# Use local clones if possible.
|
6
|
+
# If you want to use your local copy, just symlink it to vendor.
|
7
|
+
def custom_gem(name, options = Hash.new)
|
8
|
+
local_path = File.expand_path("../vendor/#{name}", __FILE__)
|
9
|
+
if File.exist?(local_path)
|
10
|
+
gem name, options.merge(:path => local_path).delete_if { |key, _| [:git, :branch].include?(key) }
|
11
|
+
else
|
12
|
+
gem name, options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
gem "eventmachine", "~> 1.0.0.beta3"
|
18
|
+
|
19
|
+
group(:test) do
|
20
|
+
gem "rspec", ">=2.0.0"
|
21
|
+
gem "rake"
|
22
|
+
# gem "amqp-spec", :git => "git://github.com/ruby-amqp/amqp-spec.git", :branch => "master"
|
23
|
+
custom_gem "evented-spec", :git => "git://github.com/ruby-amqp/evented-spec.git", :branch => "master"
|
24
|
+
end
|
data/lib/amqp/channel.rb
CHANGED
@@ -138,6 +138,8 @@ module AMQP
|
|
138
138
|
|
139
139
|
@connection = connection || AMQP.start
|
140
140
|
|
141
|
+
@queues_awaiting_declare_ok = Array.new
|
142
|
+
|
141
143
|
conn.callback { |c|
|
142
144
|
@channel = c.add_channel(self)
|
143
145
|
send Protocol::Channel::Open.new
|
@@ -147,6 +149,10 @@ module AMQP
|
|
147
149
|
attr_reader :channel, :connection, :status
|
148
150
|
alias :conn :connection
|
149
151
|
|
152
|
+
attr_reader :queues_awaiting_declare_ok
|
153
|
+
|
154
|
+
|
155
|
+
|
150
156
|
def closed?
|
151
157
|
@status.eql?(:closed)
|
152
158
|
end
|
@@ -240,6 +246,18 @@ module AMQP
|
|
240
246
|
end
|
241
247
|
end
|
242
248
|
|
249
|
+
# Returns exchange object with the same name as default (aka unnamed) exchange.
|
250
|
+
# Default exchange is a direct exchange and automatically routes messages to
|
251
|
+
# queues when routing key matches queue name exactly. This feature is known as
|
252
|
+
# "automatic binding" (of queues to default exchange).
|
253
|
+
#
|
254
|
+
# *Use default exchange when you want to route messages directly to specific queues*
|
255
|
+
# (queue names are known, you don't mind this kind of coupling between applications).
|
256
|
+
def default_exchange
|
257
|
+
Exchange.default(self)
|
258
|
+
end
|
259
|
+
|
260
|
+
|
243
261
|
# Defines, intializes and returns an Exchange to act as an ingress
|
244
262
|
# point for all published messages.
|
245
263
|
#
|
@@ -609,14 +627,19 @@ module AMQP
|
|
609
627
|
# method it will raise a channel or connection exception.
|
610
628
|
#
|
611
629
|
def queue(name, opts = {}, &block)
|
612
|
-
|
630
|
+
raise ArgumentError, "queue name must not be nil. Use '' (empty string) for server-named queues." if name.nil?
|
631
|
+
|
632
|
+
if name && !name.empty? && (queue = self.queues.find { |queue| queue.name == name })
|
613
633
|
extended_opts = Queue.add_default_options(name, opts, block)
|
614
634
|
|
615
635
|
validate_parameters_match!(queue, extended_opts)
|
616
636
|
|
617
637
|
queue
|
618
638
|
else
|
619
|
-
|
639
|
+
q = Queue.new(self, name, opts, &block)
|
640
|
+
self.queues << q
|
641
|
+
|
642
|
+
q
|
620
643
|
end
|
621
644
|
end
|
622
645
|
|
@@ -746,6 +769,9 @@ module AMQP
|
|
746
769
|
def reset
|
747
770
|
@deferred_status = nil
|
748
771
|
@channel = nil
|
772
|
+
|
773
|
+
@queues_awaiting_declare_ok = Array.new
|
774
|
+
|
749
775
|
initialize @connection
|
750
776
|
|
751
777
|
@consumers = {}
|
@@ -857,12 +883,9 @@ module AMQP
|
|
857
883
|
exchange.receive_response method
|
858
884
|
|
859
885
|
when Protocol::Queue::DeclareOk
|
860
|
-
|
861
|
-
# be an empty string, then AMQP broker generated a random one.
|
862
|
-
queues = self.queues.select { |queue| queue.opts[:nowait].eql?(false) }
|
863
|
-
queue = queues.reverse.find { |queue| queue.status.eql?(:unfinished) }
|
864
|
-
queue.receive_status method
|
886
|
+
queue = @queues_awaiting_declare_ok.shift
|
865
887
|
|
888
|
+
queue.receive_status method
|
866
889
|
when Protocol::Queue::BindOk
|
867
890
|
# We can't use queues[method.queue] because if the name would
|
868
891
|
# be an empty string, then AMQP broker generated a random one.
|
@@ -935,3 +958,25 @@ end # AMQP
|
|
935
958
|
|
936
959
|
|
937
960
|
MQ = AMQP::Channel
|
961
|
+
|
962
|
+
#
|
963
|
+
# Backwards compatibility with 0.6.x
|
964
|
+
#
|
965
|
+
|
966
|
+
class MQ
|
967
|
+
# unique identifier
|
968
|
+
def MQ.id
|
969
|
+
Thread.current[:mq_id] ||= "#{`hostname`.strip}-#{Process.pid}-#{Thread.current.object_id}"
|
970
|
+
end
|
971
|
+
|
972
|
+
def MQ.default
|
973
|
+
# TODO: clear this when connection is closed
|
974
|
+
Thread.current[:mq] ||= MQ.new
|
975
|
+
end
|
976
|
+
|
977
|
+
# Allows for calls to all MQ instance methods. This implicitly calls
|
978
|
+
# MQ.new so that a new channel is allocated for subsequent operations.
|
979
|
+
def MQ.method_missing(meth, *args, &blk)
|
980
|
+
MQ.default.__send__(meth, *args, &blk)
|
981
|
+
end
|
982
|
+
end
|
data/lib/amqp/client.rb
CHANGED
@@ -14,9 +14,28 @@ module AMQP
|
|
14
14
|
@client = mod
|
15
15
|
end
|
16
16
|
|
17
|
+
def self.mutex
|
18
|
+
@mutex ||= Mutex.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.channel
|
22
|
+
self.mutex.synchronize { @channel }
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.channel=(value)
|
26
|
+
self.mutex.synchronize { @channel = value }
|
27
|
+
end
|
28
|
+
|
29
|
+
|
17
30
|
module Client
|
18
31
|
include EM::Deferrable
|
19
32
|
|
33
|
+
#
|
34
|
+
# API
|
35
|
+
#
|
36
|
+
|
37
|
+
attr_reader :settings
|
38
|
+
|
20
39
|
def initialize(opts = {})
|
21
40
|
@settings = opts
|
22
41
|
extend AMQP.client
|
@@ -27,6 +46,7 @@ module AMQP
|
|
27
46
|
|
28
47
|
timeout @settings[:timeout] if @settings[:timeout]
|
29
48
|
errback { @on_disconnect.call } unless @reconnecting
|
49
|
+
@connection_status = @settings[:connection_status]
|
30
50
|
|
31
51
|
# TCP connection "openness"
|
32
52
|
@tcp_connection_established = false
|
@@ -61,13 +81,15 @@ module AMQP
|
|
61
81
|
def init_heartbeat
|
62
82
|
@last_server_heartbeat = Time.now
|
63
83
|
|
64
|
-
@timer
|
84
|
+
@timer.cancel if @timer
|
85
|
+
@timer = EM::PeriodicTimer.new(@settings[:heartbeat]) do
|
65
86
|
if connected?
|
66
87
|
if @last_server_heartbeat < (Time.now - (@settings[:heartbeat] * 2))
|
67
88
|
log "Reconnecting due to missing server heartbeats"
|
68
89
|
reconnect(true)
|
69
90
|
else
|
70
|
-
|
91
|
+
@last_server_heartbeat = Time.now
|
92
|
+
send AMQP::Frame::Heartbeat.new, :channel => 0
|
71
93
|
end
|
72
94
|
end
|
73
95
|
end
|
@@ -207,18 +229,63 @@ module AMQP
|
|
207
229
|
|
208
230
|
private
|
209
231
|
|
232
|
+
AMQP_PORTS = Hash["amqp" => 5672, "amqps" => 5671].freeze
|
233
|
+
|
234
|
+
# Parses AMQP connection URI and returns its components as a hash.
|
235
|
+
#
|
236
|
+
# h2. vhost naming schemes
|
237
|
+
#
|
238
|
+
# It is convenient to be able to specify the AMQP connection
|
239
|
+
# parameters as a URI string, and various "amqp" URI schemes
|
240
|
+
# exist. Unfortunately, there is no standard for these URIs, so
|
241
|
+
# while the schemes share the basic idea, they differ in some
|
242
|
+
# details. This implementation aims to encourage URIs that work
|
243
|
+
# as widely as possible.
|
244
|
+
#
|
245
|
+
# The URI scheme should be "amqp", or "amqps" if SSL is required.
|
246
|
+
#
|
247
|
+
# The host, port, username and password are represented in the
|
248
|
+
# authority component of the URI in the same way as in http URIs.
|
249
|
+
#
|
250
|
+
# The vhost is obtained from the first segment of the path, with the
|
251
|
+
# leading slash removed. The path should contain only a single
|
252
|
+
# segment (i.e, the only slash in it should be the leading one).
|
253
|
+
# If the vhost is to include slashes or other reserved URI
|
254
|
+
# characters, these should be percent-escaped.
|
255
|
+
#
|
256
|
+
# @example How vhost is parsed
|
257
|
+
#
|
258
|
+
# AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com") # => vhost is nil, so default (/) will be used
|
259
|
+
# AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/") # => vhost is an empty string
|
260
|
+
# AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/%2Fvault") # => vhost is /vault
|
261
|
+
# AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/production") # => vhost is production
|
262
|
+
# AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/a.b.c") # => vhost is a.b.c
|
263
|
+
# AMQP::Client.parse_connection_uri("amqp://dev.rabbitmq.com/foo/bar") # => ArgumentError
|
264
|
+
#
|
265
|
+
#
|
266
|
+
# @param [String] connection_string AMQP connection URI, à la JDBC connection string. For example: amqp://bus.megacorp.internal:5877.
|
267
|
+
# @return [Hash] Connection parameters (:username, :password, :vhost, :host, :port, :ssl)
|
268
|
+
#
|
269
|
+
# @raise [ArgumentError] When connection URI schema is not amqp or amqps, or the path contains multiple segments
|
270
|
+
#
|
271
|
+
# @see http://bit.ly/ks8MXK Connecting to The Broker documentation guide
|
272
|
+
# @api public
|
210
273
|
def self.parse_connection_uri(connection_string)
|
211
274
|
uri = URI.parse(connection_string)
|
212
|
-
raise("amqp://
|
275
|
+
raise ArgumentError.new("Connection URI must use amqp or amqps schema (example: amqp://bus.megacorp.internal:5766), learn more at http://bit.ly/ks8MXK") unless %w{amqp amqps}.include?(uri.scheme)
|
213
276
|
|
214
277
|
opts = {}
|
215
278
|
|
216
|
-
opts[:
|
217
|
-
opts[:
|
218
|
-
opts[:
|
219
|
-
opts[:host]
|
220
|
-
opts[:port]
|
221
|
-
opts[:ssl]
|
279
|
+
opts[:scheme] = uri.scheme
|
280
|
+
opts[:user] = URI.unescape(uri.user) if uri.user
|
281
|
+
opts[:pass] = URI.unescape(uri.password) if uri.password
|
282
|
+
opts[:host] = uri.host if uri.host
|
283
|
+
opts[:port] = uri.port || AMQP_PORTS[uri.scheme]
|
284
|
+
opts[:ssl] = uri.scheme == "amqps"
|
285
|
+
if uri.path =~ %r{^/(.*)}
|
286
|
+
raise ArgumentError.new("#{uri} has multiple-segment path; please percent-encode any slashes in the vhost name (e.g. /production => %2Fproduction). Learn more at http://bit.ly/amqp-gem-and-connection-uris") if $1.index('/')
|
287
|
+
opts[:vhost] = URI.unescape($1)
|
288
|
+
end
|
222
289
|
|
223
290
|
opts
|
224
291
|
end
|