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