amq-client-0.9.3/0000755000175000017500000000000011771004303013055 5ustar tfheentfheenamq-client-0.9.3/README.textile0000644000175000017500000000625411771004303015421 0ustar tfheentfheenh2. About amq-client amq-client is a fully-featured, low-level AMQP 0.9.1 client that runs on Ruby 1.8.7, 1.9.2, REE, Rubinius and JRuby. It's sweet spot is in serving as foundation for higher-level, more opinionated AMQP libraries. It can be used directly by applications code when performance and access to advanced AMQP protocol features is more important that API convenience. h2(#amqp_gems_family). How does amq-client relate to amqp gem, amq-protocol and libraries like bunny?
|--------------|      |-----------------------|      |----------------------|
| amq-protocol |      | amq-client            |      | amqp gem, bunny, etc |
|  - Encoding  | ===> |  - IO abstraction     | ===> |  - high-level API    |
|  - Decoding  |      |  - Low-level AMQP API |      |  - opinionated       |
|              |      |  - Framing            |      |                      |
|--------------|      |-----------------------|      |----------------------|

* At the lowest level, "amq-protocol gem":http://github.com/ruby-amqp/amq-protocol takes care of encoding, decoding and framing. * One level above is "amq-client gem":http://github.com/ruby-amqp/amq-client that takes care of network I/O, provides uniform interface for various I/O libraries like "EventMachine":http://rubyeventmachine.com/, "cool.io":http://coolio.github.com/ or good old TCP sockets and implements AMQP protocol entities (queues, exchanges, channels and so on) with emphasis on access to every feature available over API convenience or conciseness. * Finally, end applications use libraries like "amqp gem":http://github.com/ruby-amqp/amqp or "bunny AMQP client":http://github.com/ruby-amqp/bunny h2. Adapters Currently implemented adapters: * "EventMachine":http://github.com/eventmachine/eventmachine * "cool.io":http://coolio.github.com/ h3. EventMachine adapter At this point EventMachine adapter is feature-complete, well-tested, supports 5 Ruby implementations (1.8.7, 1.9.2, JRuby, Rubinius, Ruby Enterprise Edition) plus Microsoft Windows(tm) and is used by amqp gem starting with version 0.8.0. h3. cool.io adapter cool.io adapter is on par with EventMachine but is not used by any popular libraries (that we know of). Note that cool.io doesn't work on JRuby and Microsoft Windows(tm). h2. Installation amq-client is available from rubygems.org:
gem install amq-client
If you use Bundler and want to use the very latest version, add this to your Gemfile:

gem "amq-client", :git => "https://github.com/ruby-amqp/amq-client.git"

h2. Pre-prelease versions Pre-release versions are available from rubygems.org:
gem install amq-client --pre
h2. See also * "API documentation":http://rdoc.info/github/ruby-amqp/amq-client/master/frames * "Examples":https://github.com/ruby-amqp/amq-client/tree/master/examples/ * Stop by #rabbitmq on irc.freenode.net. You can use "Web IRC client":http://webchat.freenode.net?channels=rabbitmq if you don't have IRC client installed. * "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp * "Issue tracker":http://github.com/ruby-amqp/amq-client/issues * "Continous integration server":http://travis-ci.org/#!/ruby-amqp/amq-client amq-client-0.9.3/amq-client.gemspec0000755000175000017500000000233111771004303016456 0ustar tfheentfheen#!/usr/bin/env gem build # encoding: utf-8 require "base64" require File.expand_path("../lib/amq/client/version", __FILE__) Gem::Specification.new do |s| s.name = "amq-client" s.version = AMQ::Client::VERSION.dup s.authors = ["Jakub Stastny", "Michael S. Klishin", "Theo Hultberg", "Mark Abramov"] s.email = [Base64.decode64("c3Rhc3RueUAxMDFpZGVhcy5jeg==\n"), "michael@novemberain.com"] s.homepage = "http://github.com/ruby-amqp/amq-client" s.summary = "amq-client is a fully-featured, low-level AMQP 0.9.1 client" s.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" # files s.files = `git ls-files`.split("\n").reject { |file| file =~ /^vendor\// || file =~ /^gemfiles\// } s.require_paths = ["lib"] s.extra_rdoc_files = ["README.textile"] + Dir.glob("doc/*") # Dependencies s.add_dependency "eventmachine" s.add_dependency "amq-protocol", ">= 0.9.1" # RubyForge s.rubyforge_project = "amq-client" end amq-client-0.9.3/spec/0000755000175000017500000000000011771004303014007 5ustar tfheentfheenamq-client-0.9.3/spec/benchmarks/0000755000175000017500000000000011771004303016124 5ustar tfheentfheenamq-client-0.9.3/spec/benchmarks/adapters.rb0000644000175000017500000000436411771004303020263 0ustar tfheentfheen# encoding: utf-8 Bundler.setup Bundler.require(:default) $LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__)) require "amq/client/adapters/coolio" require "amq/client/adapters/event_machine" require "amq/client/queue" require "amq/client/exchange" TOTAL_MESSAGES = 10000 # Short messages # Cool.io coolio_start = Time.now AMQ::Client::CoolioClient.connect(:port => 5672, :vhost => "/amq_client_testbed") do |client| received_messages = 0 channel = AMQ::Client::Channel.new(client, 1) channel.open { } queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) { } queue.bind("amq.fanout") { } queue.consume(true) do |_, consumer_tag| queue.on_delivery do |_, header, payload, consumer_tag, delivery_tag, redelivered, exchange, routing_key| received_messages += 1 if received_messages == TOTAL_MESSAGES client.disconnect do Coolio::Loop.default.stop end end end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) TOTAL_MESSAGES.times do |i| exchange.publish("Message ##{i}") end end end cool.io.run coolio_finish = Time.now # Eventmachine em_start = Time.now EM.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "/amq_client_testbed") do |client| received_messages = 0 channel = AMQ::Client::Channel.new(client, 1) channel.open { } queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) { } queue.bind("amq.fanout") { } queue.consume(true) do |_, consumer_tag| queue.on_delivery do |_, header, payload, consumer_tag, delivery_tag, redelivered, exchange, routing_key| received_messages += 1 if received_messages == TOTAL_MESSAGES client.disconnect do EM.stop end end end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) TOTAL_MESSAGES.times do |i| exchange.publish("Message ##{i}") end end end end em_finish = Time.now puts "Results for #{TOTAL_MESSAGES} messages:" puts "\tcool.io adapter: #{sprintf("%.3f", coolio_finish - coolio_start)}s" puts "\teventmachine adapter: #{sprintf("%.3f", em_finish - em_start)}s"amq-client-0.9.3/spec/regression/0000755000175000017500000000000011771004303016167 5ustar tfheentfheenamq-client-0.9.3/spec/regression/bad_frame_slicing_in_adapters_spec.rb0000644000175000017500000000336211771004303025513 0ustar tfheentfheen# encoding: binary require 'spec_helper' require 'integration/coolio/spec_helper' require 'integration/eventmachine/spec_helper' describe "AMQ::Client::CoolioClient", :nojruby => true do include EventedSpec::SpecHelper default_timeout 1 let(:message) { "Message with xCE \xCE" } it "should receive the message with xCE byte in it without errors" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do end queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) queue.bind("amq.fanout") queue.consume(true) do |_, consumer_tag| queue.on_delivery do |method, header, payload| @received_message = payload done end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) exchange.publish(message) end end @received_message.should == message end end describe AMQ::Client::EventMachineClient do include EventedSpec::SpecHelper default_timeout 1 let(:message) { "Message with xCE \xCE" } it "should receive the message with xCE byte in it without errors" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do end queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) queue.bind("amq.fanout") queue.consume(true) do |_, consumer_tag| queue.on_delivery do |method, header, payload| @received_message = payload done end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) exchange.publish(message) end end @received_message.should == message end end amq-client-0.9.3/spec/unit/0000755000175000017500000000000011771004303014766 5ustar tfheentfheenamq-client-0.9.3/spec/unit/client_spec.rb0000644000175000017500000000316211771004303017605 0ustar tfheentfheen# encoding: utf-8 require "ostruct" require "spec_helper" require "amq/client" describe AMQ::Client do if RUBY_PLATFORM =~ /java/ ADAPTERS = { :event_machine => "Async::EventMachineClient" } else ADAPTERS = { :event_machine => "Async::EventMachineClient", :coolio => "Async::CoolioClient" } end it "should have VERSION" do AMQ::Client::const_defined?(:VERSION).should be_true end ADAPTERS.each do |adapter_name, adapter_const_name| describe ".adapters" do before(:all) do @meta = AMQ::Client.adapters[adapter_name] end it "should provide info about path to the adapter" do require @meta[:path] end it "should provide info about const_name" do @meta[:const_name].should eql(adapter_const_name) end end end describe ".connect(settings = nil, &block)" do include EventedSpec::SpecHelper default_timeout 1 context "with specified adapter" do it "should connect using event_machine adapter" do em do AMQ::Client.connect(:adapter => :event_machine) do |client| client.class.name.should eql("AMQ::Client::Async::EventMachineClient") done end end end # it it "should connect using coolio adapter", :nojruby => true do coolio do AMQ::Client.connect(:adapter => :coolio) do |client| client.class.name.should eql("AMQ::Client::Async::CoolioClient") done end end end # it end # context "with specified adapter" end # describe .connect end # describe AMQ::Client amq-client-0.9.3/spec/unit/client/0000755000175000017500000000000011771004303016244 5ustar tfheentfheenamq-client-0.9.3/spec/unit/client/mixins/0000755000175000017500000000000011771004303017553 5ustar tfheentfheenamq-client-0.9.3/spec/unit/client/mixins/status_spec.rb0000644000175000017500000000337111771004303022441 0ustar tfheentfheen# encoding: utf-8 require "spec_helper" require "amq/client/openable" describe AMQ::Client::Openable do subject do Class.new { include AMQ::Client::Openable }.new end describe "#status=" do context "if it is in the permitted values" do it "should be able to store status" do lambda { subject.status = :opened }.should_not raise_error end end context "when given value isn't in the permitted values" do it "should raise ImproperStatusError" do lambda { subject.status = :sleepy }.should raise_error(AMQ::Client::Openable::ImproperStatusError) end end end describe "#opened?" do it "should be true if the status is :opened" do subject.status = :opened subject.should be_opened end it "should be false if the status isn't :opened" do subject.status = :opening subject.should_not be_opened end end describe "#closed?" do it "should be true if the status is :closed" do subject.status = :closed subject.should be_closed end it "should be false if the status isn't :closed" do subject.status = :closing subject.should_not be_closed end end describe "#opening?" do it "should be true if the status is :opening" do subject.status = :opening subject.should be_opening end it "should be false if the status isn't :opening" do subject.status = :opened subject.should_not be_opening end end describe "#closing?" do it "should be true if the status is :closing" do subject.status = :closing subject.should be_closing end it "should be false if the status isn't :closing" do subject.status = :opening subject.should_not be_closing end end end amq-client-0.9.3/spec/unit/client/adapter_spec.rb0000644000175000017500000000246711771004303021234 0ustar tfheentfheen# encoding: utf-8 require "ostruct" require "spec_helper" require "amq/client/adapter" class SampleAdapter include AMQ::Client::Adapter end describe SampleAdapter do before(:all) do load "amq/client.rb" end describe ".settings" do it "should provide some default values" do described_class.settings.should_not be_nil described_class.settings[:host].should_not be_nil end end describe ".logger" do it "should provide a default logger" do described_class.logger.should respond_to(:debug) described_class.logger.should respond_to(:info) described_class.logger.should respond_to(:error) described_class.logger.should respond_to(:fatal) end end describe ".logger=(logger)" do context "when new logger doesn't respond to all the necessary methods" do it "should raise an exception" do lambda { described_class.logger = Object.new }.should raise_error(AMQ::Client::Logging::IncompatibleLoggerError) end it "should pass if the object provides all the necessary methods" do described_class.logging = true mock = OpenStruct.new(:debug => nil, :info => nil, :error => nil, :fatal => nil) described_class.logger = mock described_class.logger.should eql(mock) end end end end amq-client-0.9.3/spec/unit/client/settings_spec.rb0000644000175000017500000000722611771004303021452 0ustar tfheentfheen# encoding: utf-8 require "spec_helper" require "amq/client/settings" describe AMQ::Client::Settings do describe ".default" do it "should provide some default values" do AMQ::Client::Settings.default.should_not be_nil AMQ::Client::Settings.default[:host].should_not be_nil end end describe ".configure(&block)" do it "should merge custom settings with default settings" do settings = AMQ::Client::Settings.configure(:host => "tagadab") settings[:host].should eql("tagadab") end it "should merge custom settings from AMQP URL with default settings" do settings = AMQ::Client::Settings.configure("amqp://tagadab") settings[:host].should eql("tagadab") end end describe ".parse_amqp_url(connection_string)" do context "when schema is not one of [amqp, amqps]" do it "raises ArgumentError" do expect { described_class.parse_amqp_url("http://dev.rabbitmq.com") }.to raise_error(ArgumentError, /amqp or amqps schema/) end end it "handles amqp:// URIs w/o path part" do val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com") val[:vhost].should be_nil # in this case, default / will be used val[:host].should == "dev.rabbitmq.com" val[:port].should == 5672 val[:scheme].should == "amqp" val[:ssl].should be_false end it "handles amqps:// URIs w/o path part" do val = described_class.parse_amqp_url("amqps://dev.rabbitmq.com") val[:vhost].should be_nil val[:host].should == "dev.rabbitmq.com" val[:port].should == 5671 val[:scheme].should == "amqps" val[:ssl].should be_true end context "when URI ends in a slash" do it "parses vhost as an empty string" do val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/") val[:host].should == "dev.rabbitmq.com" val[:port].should == 5672 val[:scheme].should == "amqp" val[:ssl].should be_false val[:vhost].should == "" end end context "when URI ends in /%2Fvault" do it "parses vhost as /vault" do val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/%2Fvault") val[:host].should == "dev.rabbitmq.com" val[:port].should == 5672 val[:scheme].should == "amqp" val[:ssl].should be_false val[:vhost].should == "/vault" end end context "when URI is amqp://dev.rabbitmq.com/a.path.without.slashes" do it "parses vhost as a.path.without.slashes" do val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/a.path.without.slashes") val[:host].should == "dev.rabbitmq.com" val[:port].should == 5672 val[:scheme].should == "amqp" val[:ssl].should be_false val[:vhost].should == "a.path.without.slashes" end end context "when URI is amqp://dev.rabbitmq.com/a/path/with/slashes" do it "raises an ArgumentError" do lambda { described_class.parse_amqp_url("amqp://dev.rabbitmq.com/a/path/with/slashes") }.should raise_error(ArgumentError) end end context "when URI has username:password, for instance, amqp://hedgehog:t0ps3kr3t@hub.megacorp.internal" do it "parses them out" do val = described_class.parse_amqp_url("amqp://hedgehog:t0ps3kr3t@hub.megacorp.internal") val[:host].should == "hub.megacorp.internal" val[:port].should == 5672 val[:scheme].should == "amqp" val[:ssl].should be_false val[:user].should == "hedgehog" val[:pass].should == "t0ps3kr3t" val[:vhost].should be_nil # in this case, default / will be used end end end end amq-client-0.9.3/spec/unit/client/entity_spec.rb0000644000175000017500000000261011771004303021116 0ustar tfheentfheen# encoding: utf-8 require "spec_helper" require "amq/client/entity" describe AMQ::Client::Entity do let(:klazz) do Class.new do include AMQ::Client::Entity end end subject do klazz.new(Object.new) end it "should maintain an associative array of callbacks" do subject.callbacks.should be_kind_of(Hash) end describe "#has_callback?" do it "should return true if entity has at least one callback with given name" do subject.define_callback(:init, proc {}) subject.has_callback?(:init).should be_true end it "should return false if entity doesn't have callbacks with given name" do subject.has_callback?(:init).should be_false end end describe "#exec_callback" do it "executes callback for given event" do proc = Proc.new { |*args, &block| @called = true } expect { subject.define_callback(:init, proc) subject.define_callback :init do @called2 = true end }.to change(subject.callbacks, :size).from(0).to(1) subject.callbacks[:init].size.should == 2 subject.exec_callback(:init) @called.should be_true @called2.should be_true end it "should pass arguments to the callback" do f = Proc.new { |*args| args.first } subject.define_callback :init, f subject.exec_callback(:init, 1).should eql([f]) end end end amq-client-0.9.3/spec/unit/client/logging_spec.rb0000644000175000017500000000247211771004303021236 0ustar tfheentfheen# encoding: utf-8 require "spec_helper" class TestLogger def log(message) message end alias_method :debug, :log alias_method :info, :log alias_method :error, :log alias_method :fatal, :log end class LoggingTestClass attr_accessor :logging def client OpenStruct.new(:logger => TestLogger.new) end include AMQ::Client::Logging end describe AMQ::Client::Logging do # We have to use Kernel#load so extensions to the # Logging module from client.rb will be overridden. before(:all) do load "amq/client/logging.rb" AMQ::Client::Logging.logging = true end after(:all) do AMQ::Client::Logging.logging = false end context "including to an incompatible class" do it "should raise an NotImplementedError if the class doesn't define method client" do lambda { Class.new { include AMQ::Client::Logging } }.should raise_error(NotImplementedError) end end context "including to a compatible class" do subject { LoggingTestClass.new } it "should be able to log via #client#logger of given class" do subject.logging = true subject.debug("message").should eql("message") end it "should not log anything if subject#logging is false" do subject.logging = false subject.debug("message").should be_nil end end end amq-client-0.9.3/spec/integration/0000755000175000017500000000000011771004303016332 5ustar tfheentfheenamq-client-0.9.3/spec/integration/coolio/0000755000175000017500000000000011771004303017616 5ustar tfheentfheenamq-client-0.9.3/spec/integration/coolio/basic_cancel_spec.rb0000644000175000017500000000252011771004303023542 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Basic.Cancel", :nojruby => true do include EventedSpec::SpecHelper default_timeout 4 let(:messages) { (0..99).map {|i| "Message #{i}" } } it "should stop receiving messages after receiving cancel-ok" do @received_messages = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) queue.consume(true) do |amq_method| queue.on_delivery do |method, header, payload| @received_messages << payload end messages.each do |message| exchange.publish(message) end end delayed(1.5) { @received_messages.should =~ messages queue.cancel do exchange.publish("Extra message, should not be received") end } done(2.5) { @received_messages.should =~ messages } end end end # it "should stop receiving messages after receiving cancel-ok" end # describe AMQ::Client::CoolioClient, "Basic.Consume" amq-client-0.9.3/spec/integration/coolio/connection_close_spec.rb0000644000175000017500000000102511771004303024477 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Connection.Close", :nojruby => true do include EventedSpec::SpecHelper default_timeout 0.5 it "should issue a callback and close connection" do coolio do AMQ::Client::CoolioClient.connect do |connection| @connection = connection connection.should be_opened connection.disconnect do done end end end @connection.should be_closed end end amq-client-0.9.3/spec/integration/coolio/tx_rollback_spec.rb0000644000175000017500000000213111771004303023456 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Tx.Rollback", :nojruby => true do include EventedSpec::SpecHelper default_timeout 4 let(:message) { "Hello, world!" } # # Examples # it "should cancel all the changes done during transaction" do pending("Need to figure out details with AMQP protocol on that matter") received_messages = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) do queue.bind(exchange) end channel.tx_select do done(0.1) queue.consume(true) do |method, header, message| received_messages << message unless message.nil? end exchange.publish(message) channel.tx_rollback end end end received_messages.should == [] end end amq-client-0.9.3/spec/integration/coolio/basic_ack_spec.rb0000644000175000017500000000232411771004303023055 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Basic.Ack", :nojruby => true do include EventedSpec::SpecHelper default_timeout 1 context "sending 100 messages" do let(:messages) { (0..99).map {|i| "Message #{i}" } } it "should receive & acknowledge all the messages" do @received_messages = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") queue.consume do |_, consumer_tag| queue.on_delivery do |method, header, payload| queue.acknowledge(method.delivery_tag) @received_messages << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) end end # consume end # open done(0.8) { @received_messages.should =~ messages } end # coolio_amqp_connect end # it end # context end # describe amq-client-0.9.3/spec/integration/coolio/tx_commit_spec.rb0000644000175000017500000000204011771004303023154 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Tx.Commit", :nojruby => true do include EventedSpec::SpecHelper default_timeout 4 let(:message) { "Hello, world!" } # # Examples # it "should confirm transaction completeness" do received_messages = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) do queue.bind(exchange) end channel.tx_select do queue.consume(true) do |header, payload, delivery_tag, redelivered, exchange, routing_key, message_count| received_messages << message done end exchange.publish(message) channel.tx_commit end end end received_messages.should == [message] end endamq-client-0.9.3/spec/integration/coolio/channel_close_spec.rb0000644000175000017500000000124411771004303023753 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Channel.Close", :nojruby => true do include EventedSpec::SpecHelper default_timeout 1 it "should close the channel" do @events = [] coolio_amqp_connect do |client| @events << :connect channel = AMQ::Client::Channel.new(client, 1) channel.open do @events << :open channel.close do @events << :close client.disconnect do @events << :disconnect done end end end end @events.should == [:connect, :open, :close, :disconnect] end endamq-client-0.9.3/spec/integration/coolio/basic_get_spec.rb0000644000175000017500000000432211771004303023076 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Basic.Get", :nojruby => true do include EventedSpec::SpecHelper default_timeout 1 context "when set two messages beforehand" do let(:messages) { ["message 1", "message 2"] } it "synchronously fetches all the messages" do @received_messages = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) do queue.bind("amq.fanout") exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) do puts "Published a message: #{message}" end end queue.get(true) do |method, header, payload| puts "Got #{payload}" @received_messages << payload end queue.get(true) do |method, header, payload| puts "Got #{payload}" @received_messages << payload end delayed(0.5) { # need to delete the queue manually because #get doesn't count as consumption, # hence, no auto-delete queue.delete } done(0.75) { @received_messages.should =~ messages } end end end end end context "when sent no messages beforehand" do it "should receive nils" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) queue.bind("amq.fanout") exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) queue.get(true) do |method, header, payload| header.should be_nil payload.should be_nil queue.delete done(0.5) end # get end end # em_amqp_connect end # it end # context endamq-client-0.9.3/spec/integration/coolio/exchange_declare_spec.rb0000644000175000017500000001050611771004303024420 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Exchange.Declare", :nojruby => true do include EventedSpec::SpecHelper default_timeout 2 let(:exchange_name) { "amq-client.testexchange.#{Time.now.to_i}" } it "should create an exchange and trigger a callback" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare do exchange.delete done(0.5) end end end end # it "should create an exchange and trigger a callback" context "options" do context "passive" do context "when set" do it "should trigger channel level error if given exchange doesn't exist" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.on_error do @error_fired = true end exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare(true, false, false, false) do @callback_fired = true end delayed(0.1) { exchange.delete } done(0.5) end end @callback_fired.should be_false @error_fired.should be_true end # it "should trigger channel level error if given exchange doesn't exist" it "should raise no error and fire the callback if given exchange exists" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.on_error do @error_fired = true end exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare(false, false, false, false) do # initial declaration AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout).declare(true) do @callback_fired = true end end delayed(0.1) { exchange.delete } done(0.5) end end @callback_fired.should be_true @error_fired.should be_false end # it "should raise no error and fire the callback if given exchange exists" end # context "when set" context "when unset" do it "should raise no error and fire the callback if given exchange doesn't exist" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.on_error do @error_fired = true end exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare(false, false, false, false) do @callback_fired = true end delayed(0.1) { exchange.delete } done(0.5) end end @callback_fired.should be_true @error_fired.should be_false end # it "should raise no error and fire the callback if given exchange doesn't exist" it "should raise no error and fire the callback if given exchange exists" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.on_error do @error_fired = true end exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare(false, false, false, false) do # initial declaration AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout).declare(false) do @callback_fired = true end end delayed(0.1) { exchange.delete } done(0.5) end end @callback_fired.should be_true @error_fired.should be_false end # it "should raise no error and fire the callback if given exchange exists" end # context "when unset" end # context "passive" # Other options make little sense to test end # context "options" end # describe amq-client-0.9.3/spec/integration/coolio/channel_flow_spec.rb0000644000175000017500000000223011771004303023611 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Channel.Flow", :nojruby => true do include EventedSpec::SpecHelper default_timeout 1 it "should control the flow of channel" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.flow_is_active?.should be_true channel.flow(false) do |_, flow_active| flow_active.should be_false channel.flow(true) do |_, flow_active| flow_active.should be_true end end done end end end it "should not raise errors when no state change occurs" do coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) expect { channel.open do channel.flow_is_active?.should be_true channel.flow(false) do |_, flow_active| flow_active.should be_false channel.flow(false) do |_, flow_active| flow_active.should be_false end end done end }.to_not raise_error end end endamq-client-0.9.3/spec/integration/coolio/connection_start_spec.rb0000644000175000017500000000245711771004303024541 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' # # We assume that default connection settings (amqp://guest:guest@localhost:5672/) should work # describe "AMQ::Client::CoolioClient", "Connection.Start", :nojruby => true do include EventedSpec::SpecHelper default_timeout 0.5 context "with valid credentials" do it "should trigger the callback" do coolio do AMQ::Client::CoolioClient.connect do |client| client.should be_opened done end end end end context "with invalid credentials" do context "when given an errback" do it "should trigger the errback" do coolio do AMQ::Client::CoolioClient.connect(:port => 12938, :on_tcp_connection_failure => proc { done }) do |client| raise "This callback should never happen" end end end end context "when given no errback" do it "should raise an error" do expect { coolio do begin AMQ::Client::CoolioClient.connect(:port => 12938) { } done rescue Exception => e done(0.5) end end }.to raise_error(AMQ::Client::TCPConnectionFailed) end end # context end # context end # describe amq-client-0.9.3/spec/integration/coolio/basic_consume_spec.rb0000644000175000017500000001150511771004303023771 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' # # Note that this spec doesn't test acknowledgements. # See basic_ack_spec for example with acks # describe "AMQ::Client::CoolioClient", "Basic.Consume", :nojruby => true do include EventedSpec::SpecHelper default_timeout 4 context "sending 100 messages" do let(:messages) { (0..99).map {|i| "Message #{i}" } } it "should receive all the messages" do @received_messages = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") queue.consume(true) do |amq_method| queue.on_delivery do |method, header, payload| @received_messages << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) end end done(1.5) { @received_messages.should =~ messages } end end end # it "should receive all the messages" it "should not leave messages in the queues with noack=true" do @received_messages = [] @rereceived_messages = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.qos(0, 1) # Maximum prefetch size = 1 queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") # Change noack to false and watch spec fail queue.consume(true) do |amq_method| queue.on_delivery do |method, header, payload| @received_messages << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) end end # We're opening another channel and starting consuming the same queue, # assuming 1.5 secs was enough to receive all the messages delayed(1.5) do other_channel = AMQ::Client::Channel.new(client, 2) other_channel.open do other_channel.qos(0, 1) # Maximum prefetch size = 1 other_queue = AMQ::Client::Queue.new(client, other_channel, queue.name) other_queue.consume(true) do |amq_method| other_queue.on_delivery do |method, header, payload| @rereceived_messages << payload end end end end end done(2.5) { @rereceived_messages.should == [] @received_messages.should =~ messages } end end # it "should not leave messages in the queues with noack=true" end # context "sending 100 messages" end # describe AMQ::Client::CoolioClient, "Basic.Consume" describe "Multiple", AMQ::Client::Async::Consumer, :nojruby => true do include EventedSpec::SpecHelper default_timeout 4 context "sharing the same queue with equal prefetch levels" do let(:messages) { (0..99).map {|i| "Message #{i}" } } it "have messages distributed to them in the round-robin manner" do @consumer1_mailbox = [] @consumer2_mailbox = [] @consumer3_mailbox = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") consumer1 = AMQ::Client::Async::Consumer.new(channel, queue, "#{queue.name}-consumer-#{Time.now}") consumer2 = AMQ::Client::Async::Consumer.new(channel, queue) consumer3 = AMQ::Client::Async::Consumer.new(channel, queue, "#{queue.name}-consumer-#{rand}-#{Time.now}", false, true) consumer1.consume.on_delivery do |method, header, payload| @consumer1_mailbox << payload end consumer2.consume(true).on_delivery do |method, header, payload| @consumer2_mailbox << payload end consumer3.consume(false) do puts "Consumer 3 is ready" end consumer3.on_delivery do |method, header, payload| @consumer3_mailbox << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) end end done(1.5) { @consumer1_mailbox.size.should == 34 @consumer2_mailbox.size.should == 33 @consumer3_mailbox.size.should == 33 } end end # it end # context end # describe amq-client-0.9.3/spec/integration/coolio/spec_helper.rb0000644000175000017500000000133311771004303022434 0ustar tfheentfheen# encoding: utf-8 begin require "amq/client/adapters/coolio" rescue LoadError => e if RUBY_PLATFORM =~ /java/ puts "WARNING: Cool.io specs will not run on jruby" else # reraise, cause unknown raise e end end require "amq/client/queue" require "amq/client/exchange" require "evented-spec" case RUBY_VERSION when "1.8.7" then class Array alias sample choice end when /^1.9/ then Encoding.default_internal = Encoding::UTF_8 Encoding.default_external = Encoding::UTF_8 end def coolio_amqp_connect(&block) coolio do AMQ::Client::CoolioClient.connect(:port => 5672, :vhost => "amq_client_testbed", :frame_max => 2**16-1, :heartbeat_interval => 1) do |client| yield client end end end amq-client-0.9.3/spec/integration/coolio/basic_return_spec.rb0000644000175000017500000000242511771004303023640 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/coolio/spec_helper' describe "AMQ::Client::CoolioClient", "Basic.Return", :nojruby => true do include EventedSpec::SpecHelper default_timeout 1.0 context "when messages are sent to a direct exchange not bound to a queue" do let(:messages) { (0..9).map {|i| "Message #{i}" } } it "should return all the messages" do @returned_messages = [] coolio_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) # need to delete the queue manually because we don't start consumption, # hence, no auto-delete delayed(0.4) { queue.delete } exchange = AMQ::Client::Exchange.new(client, channel, "direct-exchange", :direct).declare.on_return do |method, header, body| @returned_messages << method.reply_text end messages.each do |message| exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {}, false, true) end end done(0.6) { @returned_messages.size == messages.size } end @returned_messages.should == ["NO_CONSUMERS"] * messages.size end end endamq-client-0.9.3/spec/integration/eventmachine/0000755000175000017500000000000011771004303021000 5ustar tfheentfheenamq-client-0.9.3/spec/integration/eventmachine/basic_cancel_spec.rb0000644000175000017500000000272711771004303024735 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Basic.Cancel" do include EventedSpec::SpecHelper default_timeout 4 let(:messages) { (0..99).map {|i| "Message #{i}" } } it "should stop receiving messages after receiving cancel-ok" do @received_messages = [] @received_basic_cancel_ok = false em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) queue.consume(true) do |amq_method| queue.on_delivery do |method, header, payload| @received_messages << payload end messages.each do |message| exchange.publish(message) end end delayed(1.5) { @received_messages.should =~ messages queue.cancel do @received_basic_cancel_ok = true exchange.publish("Extra message, should not be received") end } done(2.5) { @received_messages.should =~ messages @received_basic_cancel_ok.should be_true } end end end # it "should stop receiving messages after receiving cancel-ok" end # describe AMQ::Client::EventMachineClient, "Basic.Consume" amq-client-0.9.3/spec/integration/eventmachine/connection_close_spec.rb0000644000175000017500000000101711771004303025662 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Connection.Close" do include EventedSpec::SpecHelper default_timeout 0.5 it "should issue a callback and close connection" do em do AMQ::Client::EventMachineClient.connect do |connection| @connection = connection connection.should be_opened connection.disconnect do done end end end @connection.should be_closed end end amq-client-0.9.3/spec/integration/eventmachine/regressions/0000755000175000017500000000000011771004303023343 5ustar tfheentfheenamq-client-0.9.3/spec/integration/eventmachine/regressions/amqp_gem_issue66_spec.rb0000644000175000017500000000103411771004303030052 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "handling immediate disconnection" do include EventedSpec::SpecHelper default_timeout 4 after :all do done end it "successfully disconnects" do em_amqp_connect do EventMachine.run do c = described_class.connect c.disconnect do puts "Disconnection callback has fired!" done end end end # em_amqp_connect end # it end # describeamq-client-0.9.3/spec/integration/eventmachine/tx_rollback_spec.rb0000644000175000017500000000212511771004303024643 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Tx.Rollback" do include EventedSpec::SpecHelper default_timeout 4 let(:message) { "Hello, world!" } it "should cancel all the changes done during transaction" do pending("Need to figure out details with AMQP protocol on that matter") received_messages = [] em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) do queue.bind(exchange) end channel.tx_select do done(0.1) queue.consume(true) do |header, payload, delivery_tag, redelivered, exchange, routing_key, message_count| received_messages << message end exchange.publish(message) channel.tx_rollback end end end received_messages.should == [] end endamq-client-0.9.3/spec/integration/eventmachine/basic_ack_spec.rb0000644000175000017500000000216311771004303024240 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Basic.Ack" do include EventedSpec::SpecHelper default_timeout 4 context "sending 100 messages" do let(:messages) { (0..99).map {|i| "Message #{i}" } } it "should receive all the messages" do @received_messages = [] em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") queue.consume do |amq_method| queue.on_delivery do |method, header, payload| queue.acknowledge(method.delivery_tag) @received_messages << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) end end done(3.5) { @received_messages =~ messages } end end end end end amq-client-0.9.3/spec/integration/eventmachine/tx_commit_spec.rb0000644000175000017500000000212211771004303024337 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Tx.Commit" do # # Environment # include EventedSpec::SpecHelper default_timeout 4 let(:message) { "Hello, world!" } # # Examples # it "should confirm transaction completeness" do received_messages = [] em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) do queue.bind(exchange) end channel.tx_select do queue.consume(true) do |header, payload, delivery_tag, redelivered, exchange, routing_key, message_count| received_messages << message done end exchange.publish(message) channel.tx_commit end end # em_amqp_connect end received_messages.should == [message] end # it end # describeamq-client-0.9.3/spec/integration/eventmachine/channel_close_spec.rb0000644000175000017500000000124511771004303025136 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Channel.Close" do include EventedSpec::SpecHelper default_timeout 1 it "should close the channel" do @events = [] em_amqp_connect do |connection| @events << :connect channel = AMQ::Client::Channel.new(connection, 1) channel.open do @events << :open channel.close do @events << :close connection.disconnect do @events << :disconnect done end end end end @events.should == [:connect, :open, :close, :disconnect] end end amq-client-0.9.3/spec/integration/eventmachine/queue_declare_spec.rb0000644000175000017500000000126611771004303025147 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "queue.declare" do # # Environment # include EventedSpec::SpecHelper default_timeout 1 # # Examples # context "when queue name is nil" do it "raises ArgumentError" do em_amqp_connect do |connection| ch = AMQ::Client::Channel.new(connection, 1) ch.open do |ch| begin AMQ::Client::Queue.new(connection, ch, nil) rescue ArgumentError => ae ae.message.should =~ /queue name must not be nil/ done end end end end end # context end amq-client-0.9.3/spec/integration/eventmachine/basic_get_spec.rb0000644000175000017500000000431711771004303024264 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Basic.Get" do include EventedSpec::SpecHelper default_timeout 1 context "when set two messages beforehand" do let(:messages) { ["message 1", "message 2"] } it "synchronously fetches all the messages" do @received_messages = [] em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) do queue.bind("amq.fanout") exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) do puts "Published a message: #{message}" end end queue.get(true) do |method, header, payload| puts "Got #{payload}" @received_messages << payload end queue.get(true) do |method, header, payload| puts "Got #{payload}" @received_messages << payload end delayed(0.5) { # need to delete the queue manually because #get doesn't count as consumption, # hence, no auto-delete queue.delete } done(0.75) { @received_messages.should =~ messages } end end end end end context "when sent no messages beforehand" do it "should receive nils" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) queue.bind("amq.fanout") exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) queue.get(true) do |method, header, payload| header.should be_nil payload.should be_nil queue.delete done(0.5) end # get end end # em_amqp_connect end # it end # context end # describe amq-client-0.9.3/spec/integration/eventmachine/exchange_declare_spec.rb0000644000175000017500000001163611771004303025607 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Exchange.Declare" do # # Environment # include EventedSpec::SpecHelper default_timeout 2 let(:exchange_name) { "amq-client.testexchange.#{Time.now.to_i}" } # # Examples # context "when exchange type is non-standard" do context "and DOES NOT begin with x-" do it "raises an exception" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do begin AMQ::Client::Exchange.new(client, channel, exchange_name, "my_shiny_metal_exchange_type") rescue AMQ::Client::UnknownExchangeTypeError => e done end end # channel.open end # em_amqp_connect end # it end # context end # context it "should create an exchange and trigger a callback" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, "fanout") exchange.declare do exchange.delete done(0.2) end end end end # it "should create an exchange and trigger a callback" context "options" do context "passive" do context "when set" do it "should trigger channel level error if given exchange doesn't exist" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.on_error do @error_fired = true end exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare(true, false, false, false) do @callback_fired = true end delayed(0.1) { exchange.delete } done(0.3) end end @callback_fired.should be_false @error_fired.should be_true end # it "should trigger channel level error if given exchange doesn't exist" it "should raise no error and fire the callback if given exchange exists" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.on_error do @error_fired = true end exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare(false, false, false, false) do # initial declaration AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout).declare(true) do @callback_fired = true end end delayed(0.1) { exchange.delete } done(0.3) end end @callback_fired.should be_true @error_fired.should be_false end # it "should raise no error and fire the callback if given exchange exists" end # context "when set" context "when unset" do it "should raise no error and fire the callback if given exchange doesn't exist" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.on_error do @error_fired = true end exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare(false, false, false, false) do @callback_fired = true end delayed(0.1) { exchange.delete } done(0.3) end end @callback_fired.should be_true @error_fired.should be_false end # it "should raise no error and fire the callback if given exchange doesn't exist" it "should raise no error and fire the callback if given exchange exists" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.on_error do @error_fired = true end exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout) exchange.declare(false, false, false, false) do # initial declaration AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout).declare(false) do @callback_fired = true end end delayed(0.1) { exchange.delete } done(0.3) end end @callback_fired.should be_true @error_fired.should be_false end # it "should raise no error and fire the callback if given exchange exists" end # context "when unset" end # context "passive" # Other options make little sense to test end # context "options" end # describe amq-client-0.9.3/spec/integration/eventmachine/channel_flow_spec.rb0000644000175000017500000000161011771004303024774 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Channel#flow" do include EventedSpec::SpecHelper default_timeout 2 it "controls channel flow state" do em_amqp_connect do |client| flow_states = [] channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.flow_is_active?.should be_true channel.flow(false) do |flow_status1| channel.flow_is_active?.should be_false flow_states << channel.flow_is_active? channel.flow(true) do |flow_status2| channel.flow_is_active?.should be_true flow_states << channel.flow_is_active? end # channel.flow end # channel.flow end # channel.open done(1.0) { flow_states.should == [false, true] } end # em_amqp_connect end # it end # describeamq-client-0.9.3/spec/integration/eventmachine/concurrent_basic_publish_spec.rb0000644000175000017500000000763711771004303027425 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' include PlatformDetection if mri? require "multi_json" describe AMQ::Client::EventMachineClient, "Basic.Publish" do include EventedSpec::SpecHelper default_timeout 21.0 context "when messages are published across threads" do let(:inputs) do [ { :index=>{:_routing=>530,:_index=>"optimizer",:_type=>"earnings",:_id=>530}}, { :total_conversions=>0,:banked_clicks=>0,:total_earnings=>0,:pending_conversions=>0,:paid_net_earnings=>0,:banked_conversions=>0,:pending_earnings=>0,:optimizer_id=>530,:total_impressions=>0,:banked_earnings=>0,:bounce_count=>0,:time_on_page=>0,:total_clicks=>0,:entrances=>0,:pending_clicks=>0,:paid_earnings=>0}, { :index=>{:_routing=>430,:_index=>"optimizer",:_type=>"earnings",:_id=>430}}, { :total_conversions=>1443,:banked_clicks=>882,:total_earnings=>5796.3315841537,:pending_conversions=>22,:paid_net_earnings=>4116.90224486802,:banked_conversions=>1086,:pending_earnings=>257.502767857143,:optimizer_id=>430,:total_impressions=>6370497,:banked_earnings=>122.139339285714,:bounce_count=>6825,:time_on_page=>0,:total_clicks=>38143,:entrances=>12336,:pending_clicks=>1528,:paid_earnings=>5670.78224486798}, { :index=>{:_routing=>506,:_index=>"optimizer",:_type=>"earnings",:_id=>506}}, { :total_conversions=>237,:banked_clicks=>232,:total_earnings=>550.6212071428588277,:pending_conversions=>9,:paid_net_earnings=>388.021207142857,:banked_conversions=>225,:pending_earnings=>150.91,:optimizer_id=>506,:total_impressions=>348319,:banked_earnings=>12.92,:bounce_count=>905,:time_on_page=>0,:total_clicks=>4854,:entrances=>1614,:pending_clicks=>1034,:paid_earnings=>537.501207142858}, {:index=>{:_routing=>345,:_index=>"optimizer",:_type=>"earnings",:_id=>345}}, {:total_conversions=>0,:banked_clicks=>0,:total_earnings=>0,:pending_conversions=>0,:paid_net_earnings=>0,:banked_conversions=>0,:pending_earnings=>0,:optimizer_id=>345,:total_impressions=>0,:banked_earnings=>0,:bounce_count=>0,:time_on_page=>0,:total_clicks=>0,:entrances=>0,:pending_clicks=>0,:paid_earnings=>0} ] end let(:messages) { inputs.map {|i| MultiJson.encode(i) } * 3 } # the purpose of this is to make sure UNEXPECTED_FRAME issues are gone it "synchronizes on channel" do @received_messages = [] @received_messages = [] em_amqp_connect do |client| client.on_error do |conn, connection_close| fail "Handling a connection-level exception: #{connection_close.reply_text}" end channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") queue.consume(true) do |amq_method| queue.on_delivery do |method, header, payload| @received_messages << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) EventMachine.add_timer(2.0) do # ZOMG THREADS! 30.times do Thread.new do messages.each do |message| exchange.publish(message, queue.name, {}, false, true) end end end end end # let it run for several seconds because you know, concurrency issues do not always manifest themselves # immediately. MK. done(14.0) { # we don't care about the exact number, just the fact that there are # no UNEXPECTED_FRAME connection-level exceptions. MK. @received_messages.size.should > 120 } end end # em_amqp_connect end # it end # context end # describe endamq-client-0.9.3/spec/integration/eventmachine/connection_start_spec.rb0000644000175000017500000000222211771004303025711 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' # # We assume that default connection settings (amqp://guest:guest@localhost:5672/) should work # describe AMQ::Client::EventMachineClient, "Connection.Start" do include EventedSpec::SpecHelper default_timeout 0.5 context "with valid credentials" do it "should trigger the callback" do em do AMQ::Client::EventMachineClient.connect do |client| done end end end end context "with invalid credentials" do context "when given an errback" do it "should trigger the errback" do em do AMQ::Client::EventMachineClient.connect(:port => 12938, :on_tcp_connection_failure => proc { done }) do |client| raise "This callback should never happen" end end end end context "when given no errback" do it "should raise an error" do expect { em do AMQ::Client::EventMachineClient.connect(:port => 12938) { } done(0.5) end }.to raise_error(AMQ::Client::TCPConnectionFailed) end end end end amq-client-0.9.3/spec/integration/eventmachine/basic_consume_spec.rb0000644000175000017500000001277011771004303025160 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' # # Note that this spec doesn't test acknowledgements. # See basic_ack_spec for example with acks # describe AMQ::Client::EventMachineClient, "AMQP consumer" do include EventedSpec::SpecHelper default_timeout 5 context "sending 100 messages" do let(:messages) { (0..99).map {|i| "Message #{i}" } } it "should receive all the messages" do @received_messages = [] em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") queue.consume(true) do |amq_method| queue.on_delivery do |method, header, payload| @received_messages << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) end end done(3.5) { @received_messages.should =~ messages } end end end # it "should receive all the messages" it "should not leave messages in the queues with noack=true" do @received_messages = [] @rereceived_messages = [] em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.qos(0, 1) # Maximum prefetch size = 1 queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") # Change noack to false and watch spec fail queue.consume(true) do |amq_method| queue.on_delivery do |method, header, payload| @received_messages << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) end end # We're opening another channel and starting consuming the same queue, # assuming 2.0 secs was enough to receive all the messages delayed(2.0) do other_channel = AMQ::Client::Channel.new(client, 2) other_channel.open do other_channel.qos(0, 1) # Maximum prefetch size = 1 other_queue = AMQ::Client::Queue.new(client, other_channel, queue.name) other_queue.consume(true) do |amq_method| other_queue.on_delivery do |method, header, payload| @rereceived_messages << payload end end end end end done(4.5) { @rereceived_messages.should == [] @received_messages.should =~ messages } end end # it "should not leave messages in the queues with noack=true" end # context "sending 100 messages" end # describe AMQ::Client::EventMachineClient, "Basic.Consume" describe "Multiple", AMQ::Client::Async::Consumer do include EventedSpec::SpecHelper default_timeout 4 context "sharing the same queue with equal prefetch levels" do let(:messages) { (0..99).map {|i| "Message #{i}" } } it "have messages distributed to them in the round-robin manner" do @consumer1_mailbox = [] @consumer2_mailbox = [] @consumer3_mailbox = [] em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") consumer1 = AMQ::Client::Async::Consumer.new(channel, queue, "#{queue.name}-consumer-#{Time.now}") consumer2 = AMQ::Client::Async::Consumer.new(channel, queue) consumer3 = AMQ::Client::Async::Consumer.new(channel, queue, "#{queue.name}-consumer-#{rand}-#{Time.now}", false, true) consumer1.consume.on_delivery do |method, header, payload| @consumer1_mailbox << payload end consumer2.consume(true).on_delivery do |method, header, payload| @consumer2_mailbox << payload end consumer3.consume(false) do puts "Consumer 3 is ready" end consumer3.on_delivery do |method, header, payload| @consumer3_mailbox << payload end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) messages.each do |message| exchange.publish(message) end end done(1.5) { @consumer1_mailbox.size.should == 34 @consumer2_mailbox.size.should == 33 @consumer3_mailbox.size.should == 33 } end end # it end # context end # describe describe AMQ::Client::Async::Consumer do include EventedSpec::SpecHelper default_timeout 4 context "registered with a callback" do it "runs that callback when basic.consume-ok arrives" do em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) queue.bind("amq.fanout") consumer1 = AMQ::Client::Async::Consumer.new(channel, queue, "#{queue.name}-consumer-#{Time.now}") consumer1.consume do done end # consume do end # open do end # em_amqp_connect end # it end # context end # describe amq-client-0.9.3/spec/integration/eventmachine/spec_helper.rb0000644000175000017500000000106111771004303023614 0ustar tfheentfheen# encoding: utf-8 require "amq/client/adapters/event_machine" require "amq/client/queue" require "amq/client/exchange" require "evented-spec" case RUBY_VERSION when "1.8.7" then class Array alias sample choice end when /^1.9/ then Encoding.default_internal = Encoding::UTF_8 Encoding.default_external = Encoding::UTF_8 end def em_amqp_connect(&block) em do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "amq_client_testbed", :frame_max => 65536, :heartbeat_interval => 1) do |client| yield client end end end amq-client-0.9.3/spec/integration/eventmachine/basic_return_spec.rb0000644000175000017500000000243211771004303025020 0ustar tfheentfheen# encoding: utf-8 require 'spec_helper' require 'integration/eventmachine/spec_helper' describe AMQ::Client::EventMachineClient, "Basic.Return" do include EventedSpec::SpecHelper default_timeout 1.0 context "when messages are sent to a direct exchange not bound to a queue" do let(:messages) { (0..9).map {|i| "Message #{i}" } } it "should return all the messages" do @returned_messages = [] em_amqp_connect do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) # need to delete the queue manually because we don't start consumption, # hence, no auto-delete delayed(0.4) { queue.delete } exchange = AMQ::Client::Exchange.new(client, channel, "direct-exchange", :direct).declare.on_return do |method, header, body| @returned_messages << method.reply_text end messages.each do |message| exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {}, false, true) end end done(0.6) { @returned_messages.size == messages.size } end @returned_messages.should == ["NO_CONSUMERS"] * messages.size end end endamq-client-0.9.3/spec/spec_helper.rb0000644000175000017500000000110111771004303016616 0ustar tfheentfheen# encoding: utf-8 require "bundler" Bundler.setup Bundler.require(:default, :test) require 'amq/client' # # Ruby version-specific # require "effin_utf8" case RUBY_VERSION when "1.8.7" then class Array alias sample choice end when /^1.9/ then Encoding.default_internal = Encoding::UTF_8 Encoding.default_external = Encoding::UTF_8 end RSpec.configure do |c| c.filter_run_excluding :nojruby => true if RUBY_PLATFORM =~ /java/ end module PlatformDetection def mri? !defined?(RUBY_ENGINE) || (defined?(RUBY_ENGINE) && ("ruby" == RUBY_ENGINE)) end endamq-client-0.9.3/spec/client/0000755000175000017500000000000011771004303015265 5ustar tfheentfheenamq-client-0.9.3/spec/client/framing/0000755000175000017500000000000011771004303016710 5ustar tfheentfheenamq-client-0.9.3/spec/client/framing/string_frame_spec.rb0000644000175000017500000000327211771004303022733 0ustar tfheentfheen# encoding: utf-8 require "spec_helper" # We need to require AMQ-Protocol manually. # In the library this is required in the file # amq/client.rb, but this is a unit test and # we don't want to mess around with unecessary # dependencies. require "amq/protocol/client" require "amq/protocol/frame" # We have to use Kernel#load so extensions to the # Logging module from client.rb will be overridden. load "amq/client/framing/string/frame.rb" describe AMQ::Client::Framing::String do subject do AMQ::Client::Framing::String::Frame end # Created by: # frame = AMQ::Protocol::Queue::Declare.encode(1, "tasks", false, false, false, false, {}) # frame.encode # frame.payload before do data = ["\x01\x00\x00\x00\x00\x00\b"] data << "\x00\n\x00(\x01/\x00\x00" data << "\xCE" @string = data.join subject.stub(:decode_header).with(data.first).and_return([1, 0, data[1].bytesize]) end it "should be able to decode frame type" do subject.decode(@string).should be_kind_of(AMQ::Protocol::MethodFrame) end it "should be able to decode channel" do subject.decode(@string).channel.should eql(0) end it "should be able to decode payload" do subject.decode(@string).payload.should eql("\x00\n\x00(\x01/\x00\x00") end it "should raise an error if the frame length is miscalculated" do data = @string[0..-2] + "too long" + "\xCE" string = String.new(data) lambda { subject.decode(string) }.should raise_error(AMQ::Client::BadLengthError) end it "should raise an error if the frame doesn't end with FINAL_OCTET" do string = @string[0..-2] + "x" lambda { subject.decode(string) }.should raise_error(AMQ::Client::NoFinalOctetError) end end amq-client-0.9.3/spec/client/framing/io_frame_spec.rb0000644000175000017500000000315511771004303022034 0ustar tfheentfheen# encoding: binary require "spec_helper" require "stringio" # We need to require AMQ-Protocol manually. # In the library this is required in the file # amq/client.rb, but this is a unit test and # we don't want to mess around with unecessary # dependencies. require "amq/protocol/client" require "amq/protocol/frame" # We have to use Kernel#load so extensions to the # Logging module from client.rb will be overridden. load "amq/client/framing/io/frame.rb" describe AMQ::Client::Framing::IO do subject do AMQ::Client::Framing::IO::Frame end # Created by: # frame = AMQ::Protocol::Queue::Declare.encode(1, "tasks", false, false, false, false, {}) # frame.encode # frame.payload before do data = ["\x01\x00\x00\x00\x00\x00\b"] data << "\x00\n\x00(\x01/\x00\x00" data << "\xCE" @io = StringIO.new(data.join) subject.stub(:decode_header).with(data.first).and_return([1, 0, data[1].bytesize]) end it "should be able to decode frame type" do subject.decode(@io).should be_kind_of(AMQ::Protocol::MethodFrame) end it "should be able to decode channel" do subject.decode(@io).channel.should eql(0) end it "should be able to decode payload" do subject.decode(@io).payload.should eql("\x00\n\x00(\x01/\x00\x00") end context "if the frame length is miscalculated" do it "should raise an error" end context "if frame doesn't end with FINAL_OCTET" do it "should raise an error" do data = @io.read[0..-2] + "too long" + "\xCE" io = StringIO.new(data) lambda { subject.decode(io) }.should raise_error(AMQ::Client::NoFinalOctetError) end end end amq-client-0.9.3/spec/client/protocol/0000755000175000017500000000000011771004303017126 5ustar tfheentfheenamq-client-0.9.3/spec/client/protocol/get_response_spec.rb0000644000175000017500000000355011771004303023165 0ustar tfheentfheen# encoding: utf-8 require "spec_helper" require "amq/protocol/client" require "amq/protocol/get_response" # require "amq/protocol/frame" # # # We have to use Kernel#load so extensions to the # # Logging module from client.rb will be overridden. # load "amq/client/framing/string/frame.rb" describe AMQ::Protocol::GetResponse do describe "when method is GetOk" do before { @method = AMQ::Protocol::Basic::GetOk.new("dtag", true, "tasks", "foo", 1) } subject { AMQ::Protocol::GetResponse.new(@method) } it "should NOT be #empty?" do should_not be_empty end it "should have #delivery_tag" do subject.delivery_tag.should eql("dtag") end it "should have #redelivered" do subject.redelivered.should be_true end it "should have #exchange" do subject.exchange.should eql("tasks") end it "should have #routing_key" do subject.routing_key.should eql("foo") end it "should have #message_count" do subject.message_count.should eql(1) end it "should NOT have #cluster_id" do subject.cluster_id.should be_nil end end describe "when method is GetEmpty" do before { @method = AMQ::Protocol::Basic::GetEmpty.new("ID") } subject { AMQ::Protocol::GetResponse.new(@method) } it "should be #empty?" do should be_empty end it "should NOT have #delivery_tag" do subject.delivery_tag.should be_nil end it "should NOT have #redelivered" do subject.redelivered.should be_nil end it "should NOT have #exchange" do subject.exchange.should be_nil end it "should NOT have #routing_key" do subject.routing_key.should be_nil end it "should NOT have #message_count" do subject.message_count.should be_nil end it "should have #cluster_id" do subject.cluster_id.should eql("ID") end end end amq-client-0.9.3/.gitmodules0000644000175000017500000000050411771004303015231 0ustar tfheentfheen[submodule "vendor/amq-protocol"] path = vendor/amq-protocol url = https://github.com/ruby-amqp/amq-protocol.git [submodule "vendor/cool.io"] path = vendor/cool.io url = https://github.com/tarcieri/cool.io.git [submodule "vendor/evented-spec"] path = vendor/evented-spec url = git://github.com/markiz/evented-spec.git amq-client-0.9.3/metadata.yml0000644000175000017500000002270611771004303015367 0ustar tfheentfheen--- !ruby/object:Gem::Specification name: amq-client version: !ruby/object:Gem::Version hash: 61 prerelease: segments: - 0 - 9 - 3 version: 0.9.3 platform: ruby authors: - Jakub Stastny - Michael S. Klishin - Theo Hultberg - Mark Abramov autorequire: bindir: bin cert_chain: [] date: 2012-06-22 00:00:00 Z dependencies: - !ruby/object:Gem::Dependency name: eventmachine prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :runtime version_requirements: *id001 - !ruby/object:Gem::Dependency name: amq-protocol prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 57 segments: - 0 - 9 - 1 version: 0.9.1 type: :runtime version_requirements: *id002 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 email: - stastny@101ideas.cz - michael@novemberain.com executables: [] extensions: [] extra_rdoc_files: - README.textile files: - .gitignore - .gitmodules - .rspec - .travis.yml - .yardopts - Gemfile - LICENSE - README.textile - amq-client.gemspec - bin/ci/before_build.sh - bin/set_test_suite_realms_up.sh - examples/coolio_adapter/basic_consume.rb - examples/coolio_adapter/basic_consume_with_acknowledgements.rb - examples/coolio_adapter/basic_consume_with_rejections.rb - examples/coolio_adapter/basic_publish.rb - examples/coolio_adapter/channel_close.rb - examples/coolio_adapter/example_helper.rb - examples/coolio_adapter/exchange_declare.rb - examples/coolio_adapter/kitchen_sink1.rb - examples/coolio_adapter/queue_bind.rb - examples/coolio_adapter/queue_purge.rb - examples/coolio_adapter/queue_unbind.rb - examples/eventmachine_adapter/authentication/connection_open_failure_due_to_invalid_vhost.rb - examples/eventmachine_adapter/authentication/plain_password_with_custom_role_credentials.rb - examples/eventmachine_adapter/authentication/plain_password_with_default_role_credentials.rb - examples/eventmachine_adapter/authentication/plain_password_with_incorrect_credentials_handled_with_a_callback.rb - examples/eventmachine_adapter/authentication/plain_password_with_incorrect_credentials_handled_with_a_rescue_block.rb - examples/eventmachine_adapter/basic_cancel.rb - examples/eventmachine_adapter/basic_consume.rb - examples/eventmachine_adapter/basic_consume_with_acknowledgements.rb - examples/eventmachine_adapter/basic_consume_with_rejections.rb - examples/eventmachine_adapter/basic_get.rb - examples/eventmachine_adapter/basic_get_with_empty_queue.rb - examples/eventmachine_adapter/basic_publish.rb - examples/eventmachine_adapter/basic_qos.rb - examples/eventmachine_adapter/basic_recover.rb - examples/eventmachine_adapter/basic_return.rb - examples/eventmachine_adapter/channel_close.rb - examples/eventmachine_adapter/channel_flow.rb - examples/eventmachine_adapter/channel_level_exception_handling.rb - examples/eventmachine_adapter/error_handling/connection_failure_callback.rb - examples/eventmachine_adapter/error_handling/connection_failure_exception.rb - examples/eventmachine_adapter/error_handling/connection_loss_handler_that_fails_over.rb - examples/eventmachine_adapter/error_handling/connection_loss_handler_with_automatic_recovery.rb - examples/eventmachine_adapter/error_handling/connection_loss_handler_with_manual_recovery.rb - examples/eventmachine_adapter/error_handling/handling_a_channel_level_exception.rb - examples/eventmachine_adapter/example_helper.rb - examples/eventmachine_adapter/exchange_declare.rb - examples/eventmachine_adapter/extensions/rabbitmq/handling_confirm_select_ok.rb - examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rb - examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_unroutable_message.rb - examples/eventmachine_adapter/kitchen_sink1.rb - examples/eventmachine_adapter/queue_bind.rb - examples/eventmachine_adapter/queue_declare.rb - examples/eventmachine_adapter/queue_purge.rb - examples/eventmachine_adapter/queue_unbind.rb - examples/eventmachine_adapter/server_capabilities.rb - examples/eventmachine_adapter/tls/tls_without_peer_verification.rb - examples/eventmachine_adapter/tx_commit.rb - examples/eventmachine_adapter/tx_rollback.rb - examples/eventmachine_adapter/tx_select.rb - examples/tls_certificates/client/cert.pem - examples/tls_certificates/client/key.pem - examples/tls_certificates/client/keycert.p12 - examples/tls_certificates/client/req.pem - examples/tls_certificates/server/cert.pem - examples/tls_certificates/server/key.pem - examples/tls_certificates/server/keycert.p12 - examples/tls_certificates/server/req.pem - examples/tls_certificates/testca/cacert.cer - examples/tls_certificates/testca/cacert.pem - examples/tls_certificates/testca/certs/01.pem - examples/tls_certificates/testca/certs/02.pem - examples/tls_certificates/testca/index.txt - examples/tls_certificates/testca/index.txt.attr - examples/tls_certificates/testca/index.txt.attr.old - examples/tls_certificates/testca/index.txt.old - examples/tls_certificates/testca/openssl.cnf - examples/tls_certificates/testca/private/cakey.pem - examples/tls_certificates/testca/serial - examples/tls_certificates/testca/serial.old - irb.rb - lib/amq/client.rb - lib/amq/client/adapter.rb - lib/amq/client/adapters/coolio.rb - lib/amq/client/adapters/event_machine.rb - lib/amq/client/async/adapter.rb - lib/amq/client/async/adapters/coolio.rb - lib/amq/client/async/adapters/event_machine.rb - lib/amq/client/async/adapters/eventmachine.rb - lib/amq/client/async/callbacks.rb - lib/amq/client/async/channel.rb - lib/amq/client/async/consumer.rb - lib/amq/client/async/entity.rb - lib/amq/client/async/exchange.rb - lib/amq/client/async/extensions/rabbitmq/basic.rb - lib/amq/client/async/extensions/rabbitmq/confirm.rb - lib/amq/client/async/queue.rb - lib/amq/client/callbacks.rb - lib/amq/client/channel.rb - lib/amq/client/consumer_tag_generator.rb - lib/amq/client/entity.rb - lib/amq/client/exceptions.rb - lib/amq/client/exchange.rb - lib/amq/client/extensions/rabbitmq.rb - lib/amq/client/extensions/rabbitmq/basic.rb - lib/amq/client/extensions/rabbitmq/confirm.rb - lib/amq/client/framing/io/frame.rb - lib/amq/client/framing/string/frame.rb - lib/amq/client/handlers_registry.rb - lib/amq/client/logging.rb - lib/amq/client/openable.rb - lib/amq/client/queue.rb - lib/amq/client/server_named_entity.rb - lib/amq/client/settings.rb - lib/amq/client/version.rb - lib/amq/protocol/get_response.rb - spec/benchmarks/adapters.rb - spec/client/framing/io_frame_spec.rb - spec/client/framing/string_frame_spec.rb - spec/client/protocol/get_response_spec.rb - spec/integration/coolio/basic_ack_spec.rb - spec/integration/coolio/basic_cancel_spec.rb - spec/integration/coolio/basic_consume_spec.rb - spec/integration/coolio/basic_get_spec.rb - spec/integration/coolio/basic_return_spec.rb - spec/integration/coolio/channel_close_spec.rb - spec/integration/coolio/channel_flow_spec.rb - spec/integration/coolio/connection_close_spec.rb - spec/integration/coolio/connection_start_spec.rb - spec/integration/coolio/exchange_declare_spec.rb - spec/integration/coolio/spec_helper.rb - spec/integration/coolio/tx_commit_spec.rb - spec/integration/coolio/tx_rollback_spec.rb - spec/integration/eventmachine/basic_ack_spec.rb - spec/integration/eventmachine/basic_cancel_spec.rb - spec/integration/eventmachine/basic_consume_spec.rb - spec/integration/eventmachine/basic_get_spec.rb - spec/integration/eventmachine/basic_return_spec.rb - spec/integration/eventmachine/channel_close_spec.rb - spec/integration/eventmachine/channel_flow_spec.rb - spec/integration/eventmachine/concurrent_basic_publish_spec.rb - spec/integration/eventmachine/connection_close_spec.rb - spec/integration/eventmachine/connection_start_spec.rb - spec/integration/eventmachine/exchange_declare_spec.rb - spec/integration/eventmachine/queue_declare_spec.rb - spec/integration/eventmachine/regressions/amqp_gem_issue66_spec.rb - spec/integration/eventmachine/spec_helper.rb - spec/integration/eventmachine/tx_commit_spec.rb - spec/integration/eventmachine/tx_rollback_spec.rb - spec/regression/bad_frame_slicing_in_adapters_spec.rb - spec/spec_helper.rb - spec/unit/client/adapter_spec.rb - spec/unit/client/entity_spec.rb - spec/unit/client/logging_spec.rb - spec/unit/client/mixins/status_spec.rb - spec/unit/client/settings_spec.rb - spec/unit/client_spec.rb - tasks.rb homepage: http://github.com/ruby-amqp/amq-client licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: amq-client rubygems_version: 1.8.15 signing_key: specification_version: 3 summary: amq-client is a fully-featured, low-level AMQP 0.9.1 client test_files: [] has_rdoc: amq-client-0.9.3/LICENSE0000644000175000017500000000206211771004303014062 0ustar tfheentfheenCopyright (c) 2011 Jakub Šťastný aka Botanicus 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: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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. amq-client-0.9.3/.rspec0000644000175000017500000000001111771004303014162 0ustar tfheentfheen--colour amq-client-0.9.3/.yardopts0000644000175000017500000000005011771004303014716 0ustar tfheentfheen--no-private --protected lib/amq/**/*.rbamq-client-0.9.3/tasks.rb0000755000175000017500000000032511771004303014532 0ustar tfheentfheen#!/usr/bin/env nake # encoding: utf-8 if RUBY_VERSION =~ /^1.9/ Encoding.default_internal = Encoding::UTF_8 Encoding.default_external = Encoding::UTF_8 end require "contributors" load "contributors.nake" amq-client-0.9.3/examples/0000755000175000017500000000000011771004303014673 5ustar tfheentfheenamq-client-0.9.3/examples/tls_certificates/0000755000175000017500000000000011771004303020222 5ustar tfheentfheenamq-client-0.9.3/examples/tls_certificates/server/0000755000175000017500000000000011771004303021530 5ustar tfheentfheenamq-client-0.9.3/examples/tls_certificates/server/req.pem0000644000175000017500000000162311771004303023024 0ustar tfheentfheen-----BEGIN CERTIFICATE REQUEST----- MIICbDCCAVQCAQAwJzEUMBIGA1UEAxMLZ2lvdmUubG9jYWwxDzANBgNVBAoTBnNl cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN0ESmeX4FFwjNng zqkHrj1xP9hTF5tN6RSrQeEVcBNtrjheRLHzU2fl0xWcqAmAlVGEHFTRmkG3j/Ci Apppgjj84ASBtRwfTc6cRcc0sHnzp4kZ1oUeRJA5+dRsEjOlAqVCMYt+OafqZeQt bmUs/k6s36em4Qjhar+OBshBCn23srCD49v1V0kbDR2YyVV88/wVUJGkYH2UlzUD LDyAoeDiaL+7IooV0tX0hZ/4NeW9FDa+WOZASFKrhu/GcK2binkHsAUd59OeV1KA ZFRm7Ijn/i8UzKkHd15X6WS73nnXi40XSCDrp4MB+g2MSZxrT0/4YHLwt8my6IF4 VXiKu2MCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4IBAQC2aRbyq5pJ34M8jsaEjcks iov5KP17jfnHnz517/rKxKYRaoxftXVvUbtDLKMQNMAA9K65jetg6/6zqi3QTJwd 52Pn6OYTpzyFov42KRh1OSiRRa5CNXzDlHhosuVnVEOo2rdQggWZTY1clAbjEJmU N6bn6NSL4B/Vn8GAVxXhRGGoHj26LupdoI6GS2S3xuExw0xiS3usq6xYthpxHQ/L pQI2Ijk+IJZPnJR2RZji/7P3nWHWQX+HrCagCu4oyY4o7inWPVJpxD+1LmagRhv5 RyMdQKoY+6x3/r+tWATTNOVqbGzfuKj6TQSkCYvOZOejlRBsMhyYlpldVMCRmaoh -----END CERTIFICATE REQUEST----- amq-client-0.9.3/examples/tls_certificates/server/key.pem0000644000175000017500000000321711771004303023026 0ustar tfheentfheen-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA3QRKZ5fgUXCM2eDOqQeuPXE/2FMXm03pFKtB4RVwE22uOF5E sfNTZ+XTFZyoCYCVUYQcVNGaQbeP8KICmmmCOPzgBIG1HB9NzpxFxzSwefOniRnW hR5EkDn51GwSM6UCpUIxi345p+pl5C1uZSz+Tqzfp6bhCOFqv44GyEEKfbeysIPj 2/VXSRsNHZjJVXzz/BVQkaRgfZSXNQMsPICh4OJov7siihXS1fSFn/g15b0UNr5Y 5kBIUquG78ZwrZuKeQewBR3n055XUoBkVGbsiOf+LxTMqQd3XlfpZLveedeLjRdI IOungwH6DYxJnGtPT/hgcvC3ybLogXhVeIq7YwIDAQABAoIBAEu0+YussZET/Ztw bznlQKEZVuZR6Ccxs+J5m1JvlnmBO4lheSR/lhVj2z9u7vx6SCupFk9TkQRrzWl/ BWdBNvMwY8gHajNc4bkhPKG1AbJ0bPIAoMPuj0vcICDMeBuqrVJQb0o6DaPgHdDg Yw1TMTVf8CiseC8jj/5XtykHZoGTNTKzusvTjL8hTXFaWQfHQaN3WC1qwrFU2+x6 AJeoSz5F1Q/lykqVAdl2B1L39kiSCAkbVE1GI2qjftCff3ycufYV/fxXeyZwZx9B NGWUJFyZte8EcrAUoo9B/gvALGDbJsSUsbri+HsRsdOQT3K/giafUipX2FB8Bnxm nasEfskCgYEA74PrKYo13mTUWRJ2FQTBRHLsMR53PK83RpRRs8361/uCJrjpqfdD 2fUt8kH0rmm2vaWYsllucJoYdYSC9CQdECLzpOZS907PJHXCOsFsBjw74fvjZ+gY 9EXIENZSOSR1PQCWZm+5lL4xi/T+beWBfz0YksErj2GM7dyJeQjkIz8CgYEA7Dpx ANgrgO9WTu51NIlKt3P7+t6q6MHQcWuzkWMBmVU4zxeyggux+ucMj+l3KLyw7fLT jRz03eGpqjQT8Yl676uYONhTDC9VOBbLgjShuVOX7lleMLxVFJWqL1FphNghxysF HVCq1WH0Qu4keirPEotBxkNZRaRYHwRYlVPKMt0CgYEApIHSAj0IlNBiPS995R/X 8sCQU4heU1LxP0vd9gZy1OfNU/VLoE7RzqEkxrDgcu7u8cEMaOsd/L8KL6UtIKyx PYUUHV2I/I2nnp43Io35OSsj4ipU3eg/Q3+uU0oxPUg6MgT2SDNSnsQnWb6TBj5N PGxlNV7yIU/aMQF5dqVRtJcCgYEArC4Mn6jwTJImPnHgS+Kl6wFG8JvLxss9uu3d fGLFj5VmSsvi+Ja9qzstFNf+WlruOwF64KfycqdAmyZKQwsJ6BcSZJyIK6F0Y+V5 f/YMyp/7ZWcOGEetW8uat9KHLqS6OglJOQzK96zl9MLPI5yAQevujSwZrYEUGcd5 KZ5hCqECgYBExYSDJOuSMvKFw66jrLiBedLPuzh1iznwd6e4idpqIUkdhbEuXhHG +35HeN5cGwjbjXtIjxJsAddTbjvSqaPukmBKLm1ABqF3r0irbNaPcK1xfG9a5L28 /enwipaSWjGovfDXWqmmCvWC8M7iGiqFChI87WlzbvaAapOW0D576Q== -----END RSA PRIVATE KEY----- amq-client-0.9.3/examples/tls_certificates/server/cert.pem0000644000175000017500000000204611771004303023172 0ustar tfheentfheen-----BEGIN CERTIFICATE----- MIIC5DCCAcygAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl c3RDQTAeFw0xMTA0MTcyMDE3MjdaFw0xMjA0MTYyMDE3MjdaMCcxFDASBgNVBAMT C2dpb3ZlLmxvY2FsMQ8wDQYDVQQKEwZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDdBEpnl+BRcIzZ4M6pB649cT/YUxebTekUq0HhFXATba44 XkSx81Nn5dMVnKgJgJVRhBxU0ZpBt4/wogKaaYI4/OAEgbUcH03OnEXHNLB586eJ GdaFHkSQOfnUbBIzpQKlQjGLfjmn6mXkLW5lLP5OrN+npuEI4Wq/jgbIQQp9t7Kw g+Pb9VdJGw0dmMlVfPP8FVCRpGB9lJc1Ayw8gKHg4mi/uyKKFdLV9IWf+DXlvRQ2 vljmQEhSq4bvxnCtm4p5B7AFHefTnldSgGRUZuyI5/4vFMypB3deV+lku95514uN F0gg66eDAfoNjEmca09P+GBy8LfJsuiBeFV4irtjAgMBAAGjLzAtMAkGA1UdEwQC MAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEB BQUAA4IBAQCCmvsAQ1GaPfoKMqCWxyrQ2BNVPWm9J65thZKxZQF01gLox9cpv6+X QERcD71HStxbzh2B8Hebbk9OplGuyrdgfvzUxcn88kObj6udipDx4YxTJvtff/9w xeD5OWDVgef0GkB1Rjj3C3W/sfmTZBYfdKuWuwxMG/NxISkQP4aFHwJnPrzNx9ON bHoKVNrQ2iKAiMysjnFeA/4QuhBQRf41h9SBWwJEW3Ts91TzbgcjCL46Dq29QB9A 4v8t6K/nibP6n53zHbVzdxIEJ2hFKm+vuqaHRW3048Xgww1xkdxrVbyGp9si92i1 KJ5SDIOR8bQ7OXvdvpiyy6p9fIG0Z6w0 -----END CERTIFICATE----- amq-client-0.9.3/examples/tls_certificates/server/keycert.p120000644000175000017500000000445511771004303023532 0ustar tfheentfheen0 )0 *H 00 *H 0|0u *H 0 *H  0HvޱFº t>ɒnSl]6=˰p}wRZcf+\_ 7@cV4FdOE6\Dn!{%4Tha 9qX<`!YFGe.i*1\$dڄh t&O VtL?Z:oK$1Y,5 <hMF[?H|#/KU2C&z)ofPB#~YF,T!#\({s2`̙!忌zAql";+_8aˢw[Q[ g_ecu9b IrӚ ﶠxpLk٢=n>G7{ZL,|QOlfAO^gn^zrF7Aq SBpQ ] f#hJ2rB4&A CZ>ϒc\~^0,@*cc?BRB6`֔v[VK'Nk&N4zLZ ԧ5rBr̽S \#Zelf]ИXkQ߁M89dg4b|j0q kME g&E=.6QB`e#9*Θ LIgD`4񽕫*Md|K]2Ƒ4w`䶝~K;BjljELVGN .٨&p#v>[{ I.dء6|))] kd)YS,qX"1 ߜL %BO/)dh]WBqX0A *H 2.0*0& *H  00 *H  0K qN&tt0ՓO)b8C. n}ZϿ`SWJ5>SGakw# zʮM9FSi%UlL"r–nRv*߿( P:pO ~:$ :M2JCˏNlWf:0Cfes9.O*m|1DDRd*1V?Z{W/LQQ8Z釴 ɀvTJ^۸A'%J|niGS +aڱJ|) h~j+&(|XG [iWʹc-FNDZɇه8GP[pCd +K5n]*COĢΥ~ПK@|y_ ۔":Ciu ~QiCPm>D8QxjTwyCpE,G8?~.o$o ,es"Ů܈y|mL! QtCRRiΞ%s!a^-csxZ>e=ێz!>G18mQ-+>ue5*fQ_uy0(fx+hzʞ_ERfpʴNT{ ^`8 TZ!qOa\⼰?hc~"B􆆘8O('āvVW5ŭ6ƉhVXö{q!z8[3("_Sa`42Eub5EBiѫy>*۾~eHp[-bM! |/x"DՁn/R1%0# *H  1M2~Z\1c010!0 +oOY7".vݟ; 8amq-client-0.9.3/examples/tls_certificates/testca/0000755000175000017500000000000011771004303021505 5ustar tfheentfheenamq-client-0.9.3/examples/tls_certificates/testca/index.txt0000644000175000017500000000015211771004303023353 0ustar tfheentfheenV 120416201727Z 01 unknown /CN=giove.local/O=server V 120416201833Z 02 unknown /CN=giove.local/O=client amq-client-0.9.3/examples/tls_certificates/testca/index.txt.old0000644000175000017500000000006511771004303024133 0ustar tfheentfheenV 120416201727Z 01 unknown /CN=giove.local/O=server amq-client-0.9.3/examples/tls_certificates/testca/index.txt.attr.old0000644000175000017500000000002511771004303025100 0ustar tfheentfheenunique_subject = yes amq-client-0.9.3/examples/tls_certificates/testca/serial0000644000175000017500000000000311771004303022700 0ustar tfheentfheen03 amq-client-0.9.3/examples/tls_certificates/testca/serial.old0000644000175000017500000000000311771004303023455 0ustar tfheentfheen02 amq-client-0.9.3/examples/tls_certificates/testca/openssl.cnf0000644000175000017500000000500611771004303023661 0ustar tfheentfheen[ ca ] default_ca = testca [ testca ] dir = . certificate = $dir/cacert.pem database = $dir/index.txt new_certs_dir = $dir/certs private_key = $dir/private/cakey.pem serial = $dir/serial default_crl_days = 7 default_days = 365 default_md = sha1 policy = testca_policy x509_extensions = certificate_extensions [ testca_policy ] commonName = supplied stateOrProvinceName = optional countryName = optional emailAddress = optional organizationName = optional organizationalUnitName = optional [ certificate_extensions ] basicConstraints = CA:false [ req ] default_bits = 2048 default_keyfile = ./private/cakey.pem default_md = sha1 prompt = yes distinguished_name = root_ca_distinguished_name x509_extensions = root_ca_extensions [ root_ca_distinguished_name ] commonName = hostname [ root_ca_extensions ] basicConstraints = CA:true keyUsage = keyCertSign, cRLSign [ client_ca_extensions ] basicConstraints = CA:false keyUsage = digitalSignature extendedKeyUsage = 1.3.6.1.5.5.7.3.2 [ server_ca_extensions ] basicConstraints = CA:false keyUsage = keyEncipherment extendedKeyUsage = 1.3.6.1.5.5.7.3.1amq-client-0.9.3/examples/tls_certificates/testca/cacert.pem0000644000175000017500000000177511771004303023463 0ustar tfheentfheen-----BEGIN CERTIFICATE----- MIICxjCCAa6gAwIBAgIJAOF/re9e0JhgMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV BAMTCE15VGVzdENBMB4XDTExMDQxNzIwMDcxN1oXDTEyMDQxNjIwMDcxN1owEzER MA8GA1UEAxMITXlUZXN0Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDK8ZdVo1llXXrS7ed5Luel1VRq0DmJG1TZ8bAgovK9fx6WsgzeJ17zYwAEheUz B8PogkNqU3ZIa4T51VCtamoiG6bbKYpco4lutKM7aNGNJNcUfDhwyt/NYOxXM3xf ahMWjrbH0e4qKJgEjnJLpoeEa+YquDG2NXzocZY5+upy0pX6Reh1EQbju69j9f5Q Z6u4cvraScyN5IYuq3lKTmc2TxVyINVkpK9DlGJZUBAOBLSbFxGZDRoY0D3b1aeS /XMfVvcrJi48Ns2ZvT+CAy0KVeKBeQ9+6kD/YAizcxDGLRvqOZXOHYaE2L51DabL QTxk9NFPgIxrYtGS7RtQ7dUhAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0P BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAzFtKwsrCBaIAf1/VCJZh4+gzs/UW+ UXeC17GRzazb0O0drm9aMOtwE48NGVTwBjqmnPzFg56FYyll3oVZHz/fgkQZ+6iu qAbwlmY2H+L9RyC9Mv3B+Ew/o3MNCQQ3rgxbA7hb0k8mwDplxS5GBRROwZl/zHks gb4yPR6G83+zrgn6JIybdEGUySc1XDx+p6fVXvQG/1fsmExN9/ZuC6ulgBF7e+R5 d7l1AluGL4kS7GMDRZnU9QcXkhnlUyPXIDr/Jd1HFKtwgrXtVl5YIWTaRdWOXGwX Q8BpM3Vk/NQFoTHO4Na3y8JY6iJzYTIXWHjI6RJdUffsEPtBoysHFHYv -----END CERTIFICATE----- amq-client-0.9.3/examples/tls_certificates/testca/certs/0000755000175000017500000000000011771004303022625 5ustar tfheentfheenamq-client-0.9.3/examples/tls_certificates/testca/certs/01.pem0000644000175000017500000000204611771004303023552 0ustar tfheentfheen-----BEGIN CERTIFICATE----- MIIC5DCCAcygAwIBAgIBATANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl c3RDQTAeFw0xMTA0MTcyMDE3MjdaFw0xMjA0MTYyMDE3MjdaMCcxFDASBgNVBAMT C2dpb3ZlLmxvY2FsMQ8wDQYDVQQKEwZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDdBEpnl+BRcIzZ4M6pB649cT/YUxebTekUq0HhFXATba44 XkSx81Nn5dMVnKgJgJVRhBxU0ZpBt4/wogKaaYI4/OAEgbUcH03OnEXHNLB586eJ GdaFHkSQOfnUbBIzpQKlQjGLfjmn6mXkLW5lLP5OrN+npuEI4Wq/jgbIQQp9t7Kw g+Pb9VdJGw0dmMlVfPP8FVCRpGB9lJc1Ayw8gKHg4mi/uyKKFdLV9IWf+DXlvRQ2 vljmQEhSq4bvxnCtm4p5B7AFHefTnldSgGRUZuyI5/4vFMypB3deV+lku95514uN F0gg66eDAfoNjEmca09P+GBy8LfJsuiBeFV4irtjAgMBAAGjLzAtMAkGA1UdEwQC MAAwCwYDVR0PBAQDAgUgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEB BQUAA4IBAQCCmvsAQ1GaPfoKMqCWxyrQ2BNVPWm9J65thZKxZQF01gLox9cpv6+X QERcD71HStxbzh2B8Hebbk9OplGuyrdgfvzUxcn88kObj6udipDx4YxTJvtff/9w xeD5OWDVgef0GkB1Rjj3C3W/sfmTZBYfdKuWuwxMG/NxISkQP4aFHwJnPrzNx9ON bHoKVNrQ2iKAiMysjnFeA/4QuhBQRf41h9SBWwJEW3Ts91TzbgcjCL46Dq29QB9A 4v8t6K/nibP6n53zHbVzdxIEJ2hFKm+vuqaHRW3048Xgww1xkdxrVbyGp9si92i1 KJ5SDIOR8bQ7OXvdvpiyy6p9fIG0Z6w0 -----END CERTIFICATE----- amq-client-0.9.3/examples/tls_certificates/testca/certs/02.pem0000644000175000017500000000204611771004303023553 0ustar tfheentfheen-----BEGIN CERTIFICATE----- MIIC5DCCAcygAwIBAgIBAjANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhNeVRl c3RDQTAeFw0xMTA0MTcyMDE4MzNaFw0xMjA0MTYyMDE4MzNaMCcxFDASBgNVBAMT C2dpb3ZlLmxvY2FsMQ8wDQYDVQQKEwZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQC/4CSqBjpmNXoDt5xU0D4ONG3bQXBV4bJid/nmzIvV67pb v/VpqKxM+UqoV9d09u/H+f/jAKu0of1e1d+1o09JtjJshX4sYREh2/n0umENH1xC yvWnP0eFTithj9qmVcK5UOvoZKSKYT4gtCIpYhRUQZkEhPYKhvxePztjRIeUghkK Qc9Qi0/eARm8d3Zdo0ORnnNNIP+G7BjecmJvTLCP/PBDIGG6r1eybNeulNWddgLg cUq0ACFepxCJW6RdGVrMXhWomScvKssIUMAdDfwM9ffq64MYE2ZLG1OBBPefNI47 wz8h9ak15T2ZpKFU9biXLr/SnGhdhNR31d16pAtLAgMBAAGjLzAtMAkGA1UdEwQC MAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEB BQUAA4IBAQCVBpz3gZRr1s48SVF4+C9YLzrSaWsvzKZNDKH7RJ4f1VR//ZY5zsYi RqSlzSfLM76Y6Y/Eq0iFshtKmuXHKyA4r/Gp+iiCw4U9Htk91rg98wAPc8wOBgn1 OmomH65JpLwxYvUwyt91opGppcqZHWhruhI0fFTFtPIlGKK3KOmJLPpaSvY0YTJ+ vaI3D6yQEMQoZ/mcXk928ofJJvOpUEmvjTW4Orz+T8NmiffLb64P50h86bdV+8tw FJx6ix6vLF41LU2iPEYHuuXkA7+M5e+POGscJJCb1p6JKxzI6D/UVDnrbhOlqBa5 U45f0oXQ/ndOYUrBRu3BPFdNAjvpa0ld -----END CERTIFICATE----- amq-client-0.9.3/examples/tls_certificates/testca/private/0000755000175000017500000000000011771004303023157 5ustar tfheentfheenamq-client-0.9.3/examples/tls_certificates/testca/private/cakey.pem0000644000175000017500000000321311771004303024755 0ustar tfheentfheen-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAyvGXVaNZZV160u3neS7npdVUatA5iRtU2fGwIKLyvX8elrIM 3ide82MABIXlMwfD6IJDalN2SGuE+dVQrWpqIhum2ymKXKOJbrSjO2jRjSTXFHw4 cMrfzWDsVzN8X2oTFo62x9HuKiiYBI5yS6aHhGvmKrgxtjV86HGWOfrqctKV+kXo dREG47uvY/X+UGeruHL62knMjeSGLqt5Sk5nNk8VciDVZKSvQ5RiWVAQDgS0mxcR mQ0aGNA929Wnkv1zH1b3KyYuPDbNmb0/ggMtClXigXkPfupA/2AIs3MQxi0b6jmV zh2GhNi+dQ2my0E8ZPTRT4CMa2LRku0bUO3VIQIDAQABAoIBAQDJoXiDHFVgUZ0L XlUBYKnEaIyDxzey0hXep7Me6eaUgW0JugLw4VsEI9NLqyBKMCfjpTCHvj6huzmV 4utSMI0cMC76Rm5ylgSgmhYnm3+/ZN/QOY71+YqcCfUmuj+SqNgoLEjLhPbEqipH NKO4J88ysOUwgmrZppDgfKIOHw66Xlx0WtyFksozLve5pqxzs2gNZDmT5YdlGt+w X2zaUr7GholPGUVzhZSlpBpPkloSNYyGPX7O25bc63Ev92m3vnroJZYFiaUaKcFE M2RVVd3m8J47uoSwxl2ppnIgwodTWe20swc3d4cXK30U4USLsvWesthnfUc65QWa KfeanOrBAoGBAOvxGM9ufV1EFyV3D4kDB2UGp2ccv2t+rJ+urpl7JLCw1Aetpc3v Qg/QsbBfOhfI650zOZgzE5bG6B6wNYVLAC/UusrYgeLkyqKVbQgDTP+djD61jYjy IG5RP7EumN07Gvja59B4Kw5zN6TB3MKGz9Qv3a2MOvyg/3TRnssHOkQ5AoGBANwy V822s149G46tIbESw5ICcY8HorP1kD2syMeBQWKJcEgiSXL8Q3TIKdqaim8Q1Bqu fSYwISUVsFDaTyvRl25hLfkQ0t+qsul7EcjNFHf9L7dJx7z/dj8lVTQWGYse5iVQ aplx7fYQHgXdC7NjtpIrxUZkJ7bAl+0cpavdcCgpAoGAetCbO46mDyBcdBIPsiAz fzEBfrkGIyxjKxPAqv/gz2CcXgrT3eiHGLhnZgmLscnSa5e4iTM9JSUQuri6g1HR HRS8zs34fmTd3deuU5d0QzJ9SD81F24B16rPXqmExNP5bER2mpuSvgjXlBmdklye XjM0TxxJsCsWDnb3E3QFrnECgYBSpXqbNZXBK0JqnMTmh1psNQqWWpFQ5jxLScza RMNbzqYcDPJwfAp9jJtY92Q6J6DUmuVSLgJivu88iZPpqHMj9MmikBP160XXqF+W dJLYLml4a/LSFzg0nziJojnYI7LSEorQKRjdoFMEdGDt5eEin9cdgn39c/ASCQyN o0FzcQKBgHifRoEEyyHzepXiv2osPsOV9cEoWROLRaooE7boPISimJ1PCFGON0XT 20PmWJL3j3/f2Eqk47x4WpzLOp/OwUqqpaDpImtQX7GD7C+/PbAdbT1Q1Kc9kxc9 a5FJg85oJqDPB1yEmYG5nWIlqB3LOX/IdOfYSOUFvRiomwJJoxys -----END RSA PRIVATE KEY----- amq-client-0.9.3/examples/tls_certificates/testca/index.txt.attr0000644000175000017500000000002511771004303024323 0ustar tfheentfheenunique_subject = yes amq-client-0.9.3/examples/tls_certificates/testca/cacert.cer0000644000175000017500000000131211771004303023436 0ustar tfheentfheen00 ^И`0  *H 010UMyTestCA0 110417200717Z 120416200717Z010UMyTestCA0"0  *H 0 UYe]zy.Tj9T  '^c3CjSvHkPjj")\n;hэ$|8p`W3|_j*(rKk*15|q9rҕEu㻯cPgrI̍.yJNg6Or dCbYP =էsV+&.<6͙?- Uy~@`s-9ؾu ApȰDj5uɧbkRH]8Xڲ_/}73'#Ǭr}ŋ8Vtj'k/e&2sK.&+# 1VdwpV鹀UU ``ﲭW=Ћu%8?n"*L3Hݒ';ThqvWcm|g/NpSEƔn{nXσw+ ϑ@K^j]~K ,"Nא[fҀqժ5 &HզRxNO>=l VT0<` -k, rŮ _MT<\l6ۀ$8y`krua,3Yj)D?sNayȔ!Oqt,>XAEI9A'0޽|?1ʛ +/; wE]ˍ5KFzQO.v7&Zk?_G%0A *H 2.0*0& *H  00 *H  05ȫB#CӬ$J\)٥C[ʻ-I ~j "'{ #'`IԻ/; ; `e]-, 3N{ۄUF.1ć^ĎJAעqߺ0UO/a☏ZE@e - /s:Xze\Q7Tu+/aEޭW7:=b/>ւPׅo94IXO cȽJ79SSȿGewN0m ThY03b,sNW*YI1Arҝ!mƃB퍟;!`8I$áO@5iFdyANS}-"c}& ufyigaE˺:2oMO-c~&bjS}dkNN[3%:;KLD% 4._b,ɇfs䞾!jHꓵ]-{jiu%Ja@LTi*?(ʞ7P LC" [ךsRX(U8w@tRJ)UG+ HQژ )9LvAH/ ټ"c'[scन]&E l%rRٱVVnGƆroRImsFY# ZY"8.oq 5"`%\3 m^zY"\[/Boلq %>4( 5672, :vhost => "amq_client_testbed") do |client| begin puts puts puts "=============> #{description}" block.call(client) rescue Interrupt warn "Manually interrupted, terminating ..." rescue Exception => exception STDERR.puts "\n\e[1;31m[#{exception.class}] #{exception.message}\e[0m" exception.backtrace.each do |line| line = "\e[0;36m#{line}\e[0m" if line.match(Regexp::quote(File.basename(__FILE__))) STDERR.puts " - " + line end end end cool.io.run end amq-client-0.9.3/examples/coolio_adapter/queue_unbind.rb0000755000175000017500000000171311771004303022674 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Bind and then unbind a queue to amq.fanout" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel, "amqclient.queue2") queue.declare do puts "Queue #{queue.name.inspect} is now declared!" end queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" queue.unbind("amq.fanout") do puts "Queue #{queue.name} is now unbound from amq.fanout" puts puts "Deleting queue #{queue.name}" queue.delete do |message_count| puts "Deleted." puts client.disconnect do puts puts "AMQP connection is now properly closed" Coolio::Loop.default.stop end end end end end amq-client-0.9.3/examples/coolio_adapter/kitchen_sink1.rb0000755000175000017500000000250611771004303022744 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "An example that combines several AMQ operations" do |client| puts "AMQP connection is open: #{client.connection.server_properties.inspect}" channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel, "amqclient.queue2") queue.declare(false, false, false, true) do puts "Queue #{queue.name.inspect} is now declared!" end exchange = AMQ::Client::Exchange.new(client, channel, "amqclient.adapters.em.exchange1", :fanout) exchange.declare { puts "Exchange #{exchange.name.inspect} is now declared!" } queue.consume do |msg| puts msg end show_stopper = Proc.new { puts puts "Deleting queue #{queue.name}" queue.delete do |message_count| puts puts "Deleted #{queue.name}. It had #{message_count} messages in it." puts puts "Deleting exchange #{exchange.name}" exchange.delete do client.disconnect do puts puts "AMQP connection is now properly closed" Coolio::Loop.default.stop end end end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper end amq-client-0.9.3/examples/coolio_adapter/exchange_declare.rb0000755000175000017500000000135711771004303023456 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Declare a new fanout exchange" do |client| puts "AMQP connection is open: #{client.connection.server_properties.inspect}" channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end exchange = AMQ::Client::Exchange.new(client, channel, "amqclient.adapters.em.exchange1", :fanout) exchange.declare show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" Coolio::Loop.default.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper end amq-client-0.9.3/examples/coolio_adapter/basic_consume_with_rejections.rb0000755000175000017500000000217611771004303026307 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Set a queue up for message delivery" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel) queue.declare queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end queue.consume do |consumer_tag| queue.on_delivery do |header, payload, consumer_tag, delivery_tag, redelivered, exchange, routing_key| puts "Got a delivery: #{payload} (delivery tag: #{delivery_tag}), rejecting..." queue.reject(delivery_tag, false) end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) 10.times do |i| exchange.publish("Message ##{i}") end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" Coolio::Loop.default.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper end amq-client-0.9.3/examples/coolio_adapter/basic_consume_with_acknowledgements.rb0000755000175000017500000000212011771004303027461 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Set a queue up for message delivery" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel) queue.declare queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end queue.consume do |consumer_tag| queue.on_delivery do |method, header, payload| puts "Got a delivery: #{payload} (delivery tag: #{method.delivery_tag}), ack-ing..." queue.acknowledge(method.delivery_tag) end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) 10.times do |i| exchange.publish("Message ##{i}") end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" Coolio::Loop.default.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper end amq-client-0.9.3/examples/coolio_adapter/basic_publish.rb0000755000175000017500000000160011771004303023013 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Publish 100 messages using basic.publish" do |client| puts "AMQP connection is open: #{client.connection.server_properties.inspect}" channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end exchange = AMQ::Client::Exchange.new(client, channel, "amqclient.adapters.em.exchange1", :fanout) exchange.declare do 100.times do # exchange.publish("à bientôt!") exchange.publish("See you soon!") end $stdout.flush end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" Coolio::Loop.default.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper end amq-client-0.9.3/examples/coolio_adapter/queue_purge.rb0000755000175000017500000000160611771004303022540 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Purge a queue and announce how many messages it had" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel, "amqclient.queue2") queue.declare(false, false, false, true) do puts "Queue #{queue.name.inspect} is now declared!" end queue.purge do |message_count| puts "Queue #{queue.name} is now purged. It had #{message_count} messages." puts puts "Deleting queue #{queue.name}" queue.delete do |message_count| puts "Deleted." puts client.disconnect do puts puts "AMQP connection is now properly closed" Coolio::Loop.default.stop end end end end amq-client-0.9.3/examples/coolio_adapter/basic_consume.rb0000755000175000017500000000271711771004303023030 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Set a queue up for message delivery" do |connection| channel = AMQ::Client::Channel.new(connection, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(connection, channel) queue.declare(false, false, false, true) do puts "Server-named, auto-deletable Queue #{queue.name.inspect} is ready" end queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end show_stopper = Proc.new { connection.disconnect do puts puts "AMQP connection is now properly closed" Coolio::Loop.default.stop end } queue.consume(true) do |consume_ok| puts "Subscribed for messages routed to #{queue.name}, consumer tag is #{consume_ok.consumer_tag}, using no-ack mode" puts queue.on_delivery do |basic_deliver, header, payload| puts "Got a delivery:" puts " Delivery tag: #{basic_deliver.delivery_tag}" puts " Header: #{header.inspect}" puts " Payload: #{payload.inspect}" show_stopper.call if basic_deliver.delivery_tag == 100 end exchange = AMQ::Client::Exchange.new(connection, channel, "amq.fanout", :fanout) 100.times do |i| exchange.publish("Message ##{i}") end end Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper end amq-client-0.9.3/examples/eventmachine_adapter/0000755000175000017500000000000011771004303021041 5ustar tfheentfheenamq-client-0.9.3/examples/eventmachine_adapter/basic_cancel.rb0000755000175000017500000000225411771004303023762 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Set a queue up for message delivery" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end queue.consume(true) do |consumer_tag| queue.on_delivery do |method, header, payload| puts "Received #{payload}" end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) 100.times do |i| exchange.publish("Message ##{i}") end queue.cancel do 100.times do |i| exchange.publish("Message ##{i} that MUST NOT have been routed to #{queue.name}") end end end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end amq-client-0.9.3/examples/eventmachine_adapter/channel_close.rb0000755000175000017500000000117311771004303024170 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Open and then close AMQ channel" do |connection| puts "AMQP connection is open: #{connection.server_properties.inspect}" channel = AMQ::Client::Channel.new(connection, 1) channel.open do puts "Channel #{channel.id} is now open!" puts "Lets close it." channel.close do puts "Closed channel ##{channel.id}" puts connection.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end end end end amq-client-0.9.3/examples/eventmachine_adapter/channel_flow.rb0000755000175000017500000000171011771004303024027 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Activate or deactivate channel delivery using channel.flow" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) do |q, _, _, _| puts "flow is now #{channel.flow_is_active? ? 'on' : 'off'}" channel.flow(false) do |method| puts "flow is now #{method.active ? 'on' : 'off'}" end sleep 0.1 channel.flow(true) do |method| puts "flow is now #{method.active ? 'on' : 'off'}" end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/queue_bind.rb0000755000175000017500000000154611771004303023517 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Bind a new queue to amq.fanout" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end AMQ::Client::Queue.new(client, channel, "amqclient.queue2").declare do |queue, declare_ok| puts queue.class.name puts "Queue #{queue.name.inspect} is now declared!" queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout." puts puts "Deleting queue #{queue.name}" queue.delete do |message_count| puts "Deleted." puts client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end end end end end amq-client-0.9.3/examples/eventmachine_adapter/example_helper.rb0000644000175000017500000000211511771004303024357 0ustar tfheentfheen# encoding: utf-8 require "bundler" Bundler.setup Bundler.require(:default) $LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__)) require "amq/client/adapters/event_machine" require "amq/client/queue" require "amq/client/exchange" if RUBY_VERSION.to_s =~ /^1.9/ Encoding.default_internal = Encoding::UTF_8 Encoding.default_external = Encoding::UTF_8 end def amq_client_example(description = "", &block) EM.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "amq_client_testbed", :frame_max => 65536, :heartbeat_interval => 1) do |client| begin puts puts puts "=============> #{description}" block.call(client) rescue Interrupt warn "Manually interrupted, terminating ..." rescue Exception => exception STDERR.puts "\n\e[1;31m[#{exception.class}] #{exception.message}\e[0m" exception.backtrace.each do |line| line = "\e[0;36m#{line}\e[0m" if line.match(Regexp::quote(File.basename(__FILE__))) STDERR.puts " - " + line end end end end end amq-client-0.9.3/examples/eventmachine_adapter/queue_unbind.rb0000755000175000017500000000167111771004303024061 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Bind and then unbind a queue to amq.fanout" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel, "amqclient.queue2") queue.declare do puts "Queue #{queue.name.inspect} is now declared!" end queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" queue.unbind("amq.fanout") do puts "Queue #{queue.name} is now unbound from amq.fanout" puts puts "Deleting queue #{queue.name}" queue.delete do |message_count| puts "Deleted." puts client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end end end end end amq-client-0.9.3/examples/eventmachine_adapter/server_capabilities.rb0000644000175000017500000000052311771004303025405 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Inspecting server information & capabilities" do |client| puts client.server_capabilities.inspect puts client.server_properties.inspect client.disconnect { EventMachine.stop } end amq-client-0.9.3/examples/eventmachine_adapter/basic_qos.rb0000755000175000017500000000133511771004303023336 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Alter prefetching settings using basic.qos" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) do |q, _, _, _| channel.qos do |_| puts "basic.qos callback has fired" end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/basic_get.rb0000755000175000017500000000303111771004303023306 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Set a queue up for message delivery" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) do puts "Server-named, auto-deletable Queue #{queue.name.inspect} is ready" end queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) 30.times do |i| puts "Publishing message ##{i}" exchange.publish("Message ##{i}") end sleep 0.1 30.times do |i| queue.get(true) do |method, header, payload| puts "basic.get callback has fired" puts puts " => Payload is #{payload}" puts " => header is #{header.decode_payload.inspect}" puts " => delivery_tag is #{method.delivery_tag}" puts " => redelivered is #{method.redelivered}" puts " => exchange is #{method.exchange}" puts " => routing_key is #{method.routing_key}" puts " => message_count is #{method.message_count}" puts puts end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end amq-client-0.9.3/examples/eventmachine_adapter/tx_commit.rb0000755000175000017500000000130211771004303023370 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Commit acknowledgement transaction using tx.commit" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.tx_select do |_| channel.tx_commit do |_| puts "Transaction on channel #{channel.id} is now committed" end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/basic_recover.rb0000755000175000017500000000136411771004303024203 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Notify broker about consumer recovery using basic.recover" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) do |q, _, _, _| channel.recover do |_| puts "basic.recover callback has fired" end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/tx_rollback.rb0000755000175000017500000000131211771004303023672 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Rollback acknowledgement transaction using tx.rollback" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.tx_select do |_| channel.tx_rollback do |_| puts "Transaction on channel #{channel.id} is now rolled back" end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/kitchen_sink1.rb0000755000175000017500000000271611771004303024131 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "An example that combines several AMQ operations" do |connection| puts "AMQP connection is open: #{connection.server_properties.inspect}" channel = AMQ::Client::Channel.new(connection, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(connection, channel, "amqclient.queue2") queue.declare(false, false, false, true) do puts "Queue #{queue.name.inspect} is now declared!" end exchange = AMQ::Client::Exchange.new(connection, channel, "amqclient.adapters.em.exchange1", :fanout) exchange.declare { puts "Exchange #{exchange.name.inspect} is now declared!" } queue.consume do |consume_ok| puts "basic.consume_ok callback has fired for #{queue.name}, consumer_tag = #{consume_ok.consumer_tag}" end show_stopper = Proc.new { puts puts "Deleting queue #{queue.name}" queue.delete do |delete_ok| puts puts "Deleted #{queue.name}. It had #{delete_ok.message_count} messages in it." puts puts "Deleting exchange #{exchange.name}" exchange.delete do connection.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end end end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end amq-client-0.9.3/examples/eventmachine_adapter/exchange_declare.rb0000755000175000017500000000303111771004303024627 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Declare a new fanout exchange" do |connection| puts "AMQP connection is open: #{connection.server_properties.inspect}" channel = AMQ::Client::Channel.new(connection, 1) channel.open do puts "Channel #{channel.id} is now open!" exchange_name = "amqclient.adapters.em.exchange" 10.times do exchange = AMQ::Client::Exchange.new(connection, channel, exchange_name, :fanout) exchange.declare end exchange2 = AMQ::Client::Exchange.new(connection, channel, exchange_name + "-2", :fanout) exchange2.declare AMQ::Client::Exchange.new(connection, channel, exchange_name, :fanout).declare do |exchange, declare_ok| puts "Channel is aware of the following exchanges: #{channel.exchanges.map { |e| e.name }.join(', ')}" exchange.delete do puts "Exchange #{exchange.name} was successfully deleted" exchange2.delete do puts "Exchange #{exchange2.name} was successfully deleted" connection.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end end end end show_stopper = Proc.new { connection.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(2, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/basic_consume_with_rejections.rb0000755000175000017500000000214311771004303027463 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Reject a message using basic.reject" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel) queue.declare queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end queue.consume do |consumer_tag| queue.on_delivery do |method, header, payload| puts "Got a delivery: #{payload} (delivery tag: #{method.delivery_tag}), rejecting..." queue.reject(method.delivery_tag, false) end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) 10.times do |i| exchange.publish("Message ##{i}") end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end amq-client-0.9.3/examples/eventmachine_adapter/channel_level_exception_handling.rb0000644000175000017500000000212011771004303030102 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Channel-level exception handling" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open" show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } channel.on_error do |ch, close| puts "Oops, there is a channel-level exception: #{close.inspect}" EM.add_timer(1.2) { show_stopper.call } end # amq.* names are reserevd so this causes a channel-level exception. MK. x = AMQ::Client::Exchange.new(client, channel, "amq.client.examples.extensions.x1", :direct) x.declare(false, false, false, true, false) EM.add_timer(1) do if channel.closed? puts "1 second later channel #{channel.id} is closed" end end Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(2, show_stopper) end endamq-client-0.9.3/examples/eventmachine_adapter/authentication/0000755000175000017500000000000011771004303024060 5ustar tfheentfheen././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/authentication/plain_password_with_default_role_credentials.rbamq-client-0.9.3/examples/eventmachine_adapter/authentication/plain_password_with_default_role_crede0000755000175000017500000000124711771004303033761 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__)), "..") require File.join(__dir, "example_helper") EM.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "/amq_client_testbed", :user => "guest", :password => "guest") do |client| puts "Connected, authenticated" puts "client.authenticating? => #{client.authenticating?}" show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/authentication/plain_password_with_custom_role_credentials.rbamq-client-0.9.3/examples/eventmachine_adapter/authentication/plain_password_with_custom_role_creden0000755000175000017500000000141311771004303034020 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__)), "..") require File.join(__dir, "example_helper") EM.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "/amq_client_testbed", :user => "amq_client_gem", :password => "amq_client_gem_password") do |client| puts "Connected, authenticated" show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end ././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/authentication/plain_password_with_incorrect_credentials_handled_with_a_callback.rbamq-client-0.9.3/examples/eventmachine_adapter/authentication/plain_password_with_incorrect_credenti0000755000175000017500000000147511771004303034022 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__)), "..") require File.join(__dir, "example_helper") EM.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "/amq_client_testbed", :user => "amq_client_gem", :password => "a password that is incorrect #{Time.now.to_i}", :on_possible_authentication_failure => Proc.new { |settings| puts "Authentication failed, as expected, settings are: #{settings.inspect}" EventMachine.stop }) do |client| raise "Should not really be executed" end end ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/authentication/connection_open_failure_due_to_invalid_vhost.rbamq-client-0.9.3/examples/eventmachine_adapter/authentication/connection_open_failure_due_to_invalid0000644000175000017500000000176711771004303033752 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__)), "..") require File.join(__dir, "example_helper") begin EventMachine.run do show_stopper = Proc.new { EM.stop } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EventMachine.add_timer(4, show_stopper) AMQ::Client::EventMachineClient.connect(:port => 9689, :vhost => "/a/b/c/#{rand}/d/#{Time.now.to_i}", :user => "amq_client_gem", :password => "amq_client_gem_password", :timeout => 0.3) do |client| raise "Connected, authenticated. This is not what this example is supposed to do!" end end rescue AMQ::Client::TCPConnectionFailed => e puts "TCP connection has failed, as expected. Shutting down…" EventMachine.stop if EventMachine.reactor_running? end././@LongLink0000000000000000000000000000020700000000000011564 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/authentication/plain_password_with_incorrect_credentials_handled_with_a_rescue_block.rbamq-client-0.9.3/examples/eventmachine_adapter/authentication/plain_password_with_incorrect_credenti0000644000175000017500000000136511771004303034015 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__)), "..") require File.join(__dir, "example_helper") begin EventMachine.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "/amq_client_testbed", :user => "amq_client_gem", :password => "a password that is incorrect #{Time.now.to_i}") do |client| raise "Should not really be executed" end end rescue AMQ::Client::PossibleAuthenticationFailureError => afe puts "Authentication failed, as expected. Caught #{afe.inspect}" EventMachine.stop if EventMachine.reactor_running? end amq-client-0.9.3/examples/eventmachine_adapter/basic_return.rb0000755000175000017500000000204711771004303024054 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "basic.return example" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true) exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) exchange.on_return do |method, header, body| puts "Handling a returned message: exchange = #{method.exchange}, reply_code = #{method.reply_code}, reply_text = #{method.reply_text}" puts "Body of the returned message: #{body}" end 10.times do |i| exchange.publish("Message ##{i}", AMQ::Protocol::EMPTY_STRING, {}, false, true) end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/basic_get_with_empty_queue.rb0000755000175000017500000000264111771004303026771 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Set a queue up for message delivery" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel) queue.declare(false, false, false, true) do puts "Server-named, auto-deletable Queue #{queue.name.inspect} is ready" end queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end sleep 0.1 10.times do |i| queue.get(true) do |method, header, payload| puts "basic.get callback has fired" puts puts "Payload is #{payload}" if header puts "header is #{header.decode_payload.inspect}" else puts "header is nil" end puts "delivery_tag is #{method.delivery_tag.inspect}" puts "redelivered is #{method.redelivered.inspect}" puts "exchange is #{method.exchange.inspect}" puts "routing_key is #{method.routing_key.inspect}" puts "message_count is #{method.message_count.inspect}" end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end amq-client-0.9.3/examples/eventmachine_adapter/error_handling/0000755000175000017500000000000011771004303024036 5ustar tfheentfheen././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/error_handling/connection_loss_handler_with_automatic_recovery.rbamq-client-0.9.3/examples/eventmachine_adapter/error_handling/connection_loss_handler_with_automatic0000644000175000017500000000544311771004303033764 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__))) require File.join(__dir, "..", "example_helper") EM.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "amq_client_testbed", :user => "amq_client_gem", :password => "amq_client_gem_password", :timeout => 0.3, :on_tcp_connection_failure => Proc.new { |settings| puts "Failed to connect, this was NOT expected"; EM.stop }) do |connection| if connection.auto_recovering? puts "Connection is auto-recovering..." end ch1 = AMQ::Client::Channel.new(connection, 1, :auto_recovery => true) ch1.on_error do |ch, channel_close| raise channel_close.reply_text end ch1.open do puts "Channel 1 open now" end if ch1.auto_recovering? puts "Channel 1 is auto-recovering" end ch1.on_recovery do |c| puts "Channel #{c.id} has recovered" end ch2 = AMQ::Client::Channel.new(connection, 2, :auto_recovery => true) ch2.on_error do |ch, channel_close| raise channel_close.reply_text end ch2.open do puts "Channel 2 open now" end if ch2.auto_recovering? puts "Channel 2 is auto-recovering" end queues = Array.new(4) do q = AMQ::Client::Queue.new(connection, ch1, AMQ::Protocol::EMPTY_STRING) q.declare(false, false, false, true) do q.consume { puts "Added a consumer on #{q.name}"; q.on_delivery { |*args| puts(args.inspect) } } end q.on_recovery { |_| puts "Queue #{q.name} has recovered" } q end x = AMQ::Client::Exchange.new(connection, ch1, "amqclient.examples.exchanges.fanout", :fanout) x2 = AMQ::Client::Exchange.new(connection, ch1, "amq.fanout", :fanout) x.declare(false, false, true) x.after_connection_interruption { |x| puts "Exchange #{x.name} has reacted to connection interruption" } x.after_recovery { |x| puts "Exchange #{x.name} has recovered" } queues.each { |q| q.bind(x) } connection.on_tcp_connection_loss do |conn, settings| puts "Trying to reconnect..." conn.reconnect(false, 2) end connection.on_recovery do |conn, settings| puts "Connection recovered" end show_stopper = Proc.new { connection.disconnect { puts "Disconnected. Exiting…"; EventMachine.stop } } Signal.trap "TERM", show_stopper Signal.trap "INT", show_stopper EM.add_timer(30, show_stopper) puts "Connected, authenticated. To really exercise this example, shut AMQP broker down for a few seconds. If you don't it will exit gracefully in 30 seconds." end end amq-client-0.9.3/examples/eventmachine_adapter/error_handling/connection_failure_exception.rb0000644000175000017500000000170311771004303032310 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__))) require File.join(__dir, "..", "example_helper") begin EventMachine.run do show_stopper = Proc.new { EventMachine.stop } Signal.trap "TERM", show_stopper EventMachine.add_timer(4, show_stopper) AMQ::Client::EventMachineClient.connect(:port => 9689, :vhost => "amq_client_testbed", :user => "amq_client_gem", :password => "amq_client_gem_password", :timeout => 0.3) do |client| raise "Connected, authenticated. This is not what this example is supposed to do!" end end rescue AMQ::Client::TCPConnectionFailed => e puts "TCP connection has failed, as expected. Shutting down…" EventMachine.stop if EventMachine.reactor_running? end ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/error_handling/connection_loss_handler_that_fails_over.rbamq-client-0.9.3/examples/eventmachine_adapter/error_handling/connection_loss_handler_that_fails_ove0000644000175000017500000000247411771004303033733 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__))) require File.join(__dir, "..", "example_helper") EM.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "amq_client_testbed", :user => "amq_client_gem", :password => "amq_client_gem_password", :timeout => 0.3, :on_tcp_connection_failure => Proc.new { |settings| puts "Failed to connect, this was NOT expected"; EM.stop }) do |connection| connection.on_tcp_connection_loss do |conn, settings| puts "Trying to reconnect..." conn.reconnect_to(:host => "dev.rabbitmq.com") end connection.on_recovery do |conn, settings| puts "Connection recovered" end show_stopper = Proc.new { connection.disconnect { puts "Disconnected. Exiting…"; EventMachine.stop } } Signal.trap "TERM", show_stopper Signal.trap "INT", show_stopper EM.add_timer(30, show_stopper) puts "Connected, authenticated. To really exercise this example, shut AMQP broker down for a few seconds. If you don't it will exit gracefully in 30 seconds." end end amq-client-0.9.3/examples/eventmachine_adapter/error_handling/handling_a_channel_level_exception.rb0000644000175000017500000000242211771004303033404 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "..", "example_helper") amq_client_example "Handling a channel-level exception" do |connection| channel = AMQ::Client::Channel.new(connection, 1) channel.open do puts "Channel #{channel.id} is now open!" channel.on_error do |ch, close| puts "Handling a channel-level exception: #{close.reply_text}" end EventMachine.add_timer(0.4) do # these two definitions result in a race condition. For sake of this example, # however, it does not matter. Whatever definition succeeds first, 2nd one will # cause a channel-level exception (because attributes are not identical) AMQ::Client::Queue.new(connection, channel, "amqpgem.examples.channel_exception").declare(false, false, false, true) do |queue| puts "#{queue.name} is ready to go" end AMQ::Client::Queue.new(connection, channel, "amqpgem.examples.channel_exception").declare(false, true, false, false) do |queue| puts "#{queue.name} is ready to go" end end end show_stopper = Proc.new do $stdout.puts "Stopping..." connection.close { EventMachine.stop } end Signal.trap "INT", show_stopper EM.add_timer(2, show_stopper) end ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/error_handling/connection_loss_handler_with_manual_recovery.rbamq-client-0.9.3/examples/eventmachine_adapter/error_handling/connection_loss_handler_with_manual_re0000644000175000017500000000536311771004303033742 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__))) require File.join(__dir, "..", "example_helper") EM.run do AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "amq_client_testbed", :user => "amq_client_gem", :password => "amq_client_gem_password", :timeout => 0.3, :on_tcp_connection_failure => Proc.new { |settings| puts "Failed to connect, this was NOT expected"; EM.stop }) do |connection| if connection.auto_recovering? puts "Connection is auto-recovering..." end ch1 = AMQ::Client::Channel.new(connection, 1) ch1.on_error do |ch, channel_close| raise channel_close.reply_text end ch1.open do puts "Channel 1 open now" end if ch1.auto_recovering? puts "Channel 1 is auto-recovering" end ch1.on_recovery do |c| puts "Channel #{c.id} has recovered" end ch2 = AMQ::Client::Channel.new(connection, 2) ch2.on_error do |ch, channel_close| raise channel_close.reply_text end ch2.open do puts "Channel 2 open now" end if ch2.auto_recovering? puts "Channel 2 is auto-recovering" end queues = Array.new(4) do q = AMQ::Client::Queue.new(connection, ch1, AMQ::Protocol::EMPTY_STRING) q.declare(false, false, false, true) do q.consume { puts "Added a consumer on #{q.name}"; q.on_delivery { |*args| puts(args.inspect) } } end q.on_recovery { |_| puts "Queue #{q.name} has recovered" } q end x = AMQ::Client::Exchange.new(connection, ch1, "amqclient.examples.exchanges.fanout", :fanout) x2 = AMQ::Client::Exchange.new(connection, ch1, "amq.fanout", :fanout) x.declare(false, false, true) x.after_connection_interruption { |x| puts "Exchange #{x.name} has reacted to connection interruption" } x.after_recovery { |x| puts "Exchange #{x.name} has recovered" } queues.each { |q| q.bind(x) } connection.on_tcp_connection_loss do |conn, settings| puts "Trying to reconnect..." conn.reconnect(false, 2) end connection.on_recovery do |conn, settings| puts "Connection recovered" end show_stopper = Proc.new { connection.disconnect { puts "Disconnected. Exiting…"; EventMachine.stop } } Signal.trap "TERM", show_stopper Signal.trap "INT", show_stopper EM.add_timer(30, show_stopper) puts "Connected, authenticated. To really exercise this example, shut AMQP broker down for a few seconds. If you don't it will exit gracefully in 30 seconds." end end amq-client-0.9.3/examples/eventmachine_adapter/error_handling/connection_failure_callback.rb0000644000175000017500000000157111771004303032051 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.join(File.dirname(File.expand_path(__FILE__))) require File.join(__dir, "..", "example_helper") EM.run do show_stopper = Proc.new { EventMachine.stop } Signal.trap "TERM", show_stopper EM.add_timer(4, show_stopper) AMQ::Client::EventMachineClient.connect(:port => 9689, :vhost => "amq_client_testbed", :user => "amq_client_gem", :password => "amq_client_gem_password", :timeout => 0.3, :on_tcp_connection_failure => Proc.new { |settings| puts "Failed to connect, as expected"; EM.stop }) do |client| raise "Connected, authenticated. This is not what this example is supposed to do!" end end amq-client-0.9.3/examples/eventmachine_adapter/basic_consume_with_acknowledgements.rb0000755000175000017500000000220011771004303030642 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Acknowledge a message using basic.ack" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel) queue.declare queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end queue.consume do |consumer_tag| queue.on_delivery do |basic_deliver, header, payload| puts "Got a delivery: #{payload} (delivery tag: #{basic_deliver.delivery_tag}), ack-ing..." queue.acknowledge(basic_deliver.delivery_tag) end exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) 10.times do |i| exchange.publish("Message ##{i}") end end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EventMachine.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end amq-client-0.9.3/examples/eventmachine_adapter/extensions/0000755000175000017500000000000011771004303023240 5ustar tfheentfheenamq-client-0.9.3/examples/eventmachine_adapter/extensions/rabbitmq/0000755000175000017500000000000011771004303025041 5ustar tfheentfheenamq-client-0.9.3/examples/eventmachine_adapter/extensions/rabbitmq/handling_confirm_select_ok.rb0000644000175000017500000000136311771004303032722 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "..", "..", "example_helper") require "amq/client/extensions/rabbitmq/confirm" amq_client_example "confirm.select (a RabbitMQ extension)" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open" channel.confirm_select do |select_ok| puts "Broker replied with confirm.select_ok" end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end ././@LongLink0000000000000000000000000000016600000000000011570 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_unroutable_message.rbamq-client-0.9.3/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_unro0000644000175000017500000000243411771004303034015 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "..", "..", "example_helper") require "amq/client/extensions/rabbitmq/confirm" amq_client_example "Publisher confirmations using RabbitMQ extension: unroutable message scenario" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open" channel.confirm_select channel.on_error do puts "Oops, there is a channel-levle exceptions!" end channel.on_ack do |basic_ack| puts "Received basic_ack: multiple = #{basic_ack.multiple}, delivery_tag = #{basic_ack.delivery_tag}" end x = AMQ::Client::Exchange.new(client, channel, AMQ::Protocol::EMPTY_STRING, :direct) x.on_return { |basic_return, metadata, payload| puts "Received basic.return: reply_text = #{basic_return.reply_text}, reply_code = #{basic_return.reply_code}" } 10.times { x.publish("A message", AMQ::Protocol::EMPTY_STRING, {}, true) } show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(3, show_stopper) end end ././@LongLink0000000000000000000000000000016600000000000011570 Lustar rootrootamq-client-0.9.3/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rbamq-client-0.9.3/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_tran0000644000175000017500000000306311771004303033775 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "..", "..", "example_helper") require "amq/client/extensions/rabbitmq/confirm" amq_client_example "Publisher confirmations using RabbitMQ extension: routable message scenario" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open" channel.confirm_select channel.on_error do puts "Oops, there is a channel-levle exceptions!" end channel.on_ack do |basic_ack| puts "Received basic_ack: multiple = #{basic_ack.multiple}, delivery_tag = #{basic_ack.delivery_tag}" end x = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout) q = AMQ::Client::Queue.new(client, channel, AMQ::Protocol::EMPTY_STRING) q.declare(false, false, true, true) do |_, declare_ok| puts "Defined a new server-named queue: #{q.name}" q.bind("amq.fanout").consume(false, true, true) { |consume_ok| puts "Received basic.consume-ok" }.on_delivery do |method, header, payload| puts "Received #{payload}" end end EM.add_timer(0.5) do 10.times { |i| x.publish("Message ##{i}", AMQ::Protocol::EMPTY_STRING, { :delivery_mode => 2 }, true) } end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(3, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/basic_publish.rb0000755000175000017500000000166111771004303024204 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Publish 100 messages using basic.publish" do |connection| puts "AMQP connection is open: #{connection.server_properties.inspect}" channel = AMQ::Client::Channel.new(connection, 1) channel.open do puts "Channel #{channel.id} is now open!" end exchange = AMQ::Client::Exchange.new(connection, channel, "amqclient.adapters.em.exchange1", :fanout) exchange.declare do 100.times do # exchange.publish("à bientôt!") exchange.publish("See you soon!") print "." end $stdout.flush end show_stopper = Proc.new { connection.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } EM.add_periodic_timer(1, show_stopper) Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper end amq-client-0.9.3/examples/eventmachine_adapter/tls/0000755000175000017500000000000011771004303021643 5ustar tfheentfheenamq-client-0.9.3/examples/eventmachine_adapter/tls/tls_without_peer_verification.rb0000644000175000017500000000260611771004303030336 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 examples_dir = File.join(File.dirname(File.expand_path(__FILE__)), "..", "..") __dir = File.join(File.dirname(File.expand_path(__FILE__)), "..") require File.join(__dir, "example_helper") certificate_chain_file_path = File.join(examples_dir, "tls_certificates", "client", "cert.pem") client_private_key_file_path = File.join(examples_dir, "tls_certificates", "client", "key.pem") EM.run do AMQ::Client::EventMachineClient.connect(:port => 5671, :vhost => "amq_client_testbed", :user => "amq_client_gem", :password => "amq_client_gem_password", :ssl => { :cert_chain_file => certificate_chain_file_path, :private_key_file => client_private_key_file_path }) do |client| puts "Connected, authenticated. TLS seems to work." client.disconnect { puts "Now closing the connection…"; EM.stop } end show_stopper = Proc.new { EM.stop } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper # TLS connections take forever and a day # (compared to non-TLS connections) to estabilish. EM.add_timer(8, show_stopper) end amq-client-0.9.3/examples/eventmachine_adapter/queue_purge.rb0000755000175000017500000000156411771004303023725 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Purge a queue and announce how many messages it had" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(client, channel, "amqclient.queue2") queue.declare(false, false, false, true) do puts "Queue #{queue.name.inspect} is now declared!" end queue.purge do |message_count| puts "Queue #{queue.name} is now purged. It had #{message_count} messages." puts puts "Deleting queue #{queue.name}" queue.delete do |message_count| puts "Deleted." puts client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end end end end amq-client-0.9.3/examples/eventmachine_adapter/basic_consume.rb0000755000175000017500000000273411771004303024211 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Set a queue up for message delivery" do |connection| channel = AMQ::Client::Channel.new(connection, 1) channel.open do puts "Channel #{channel.id} is now open!" end queue = AMQ::Client::Queue.new(connection, channel) queue.declare(false, false, false, true) do puts "Server-named, auto-deletable Queue #{queue.name.inspect} is ready" end queue.bind("amq.fanout") do puts "Queue #{queue.name} is now bound to amq.fanout" end show_stopper = Proc.new { connection.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } queue.consume(true) do |consume_ok| puts "Subscribed for messages routed to #{queue.name}, consumer tag is #{consume_ok.consumer_tag}, using no-ack mode" puts queue.on_delivery do |basic_deliver, header, payload| puts "Got a delivery:" puts " Delivery tag: #{basic_deliver.delivery_tag}" puts " Header: #{header.inspect}" puts " Payload: #{payload.inspect}" show_stopper.call if basic_deliver.delivery_tag == 100 end exchange = AMQ::Client::Exchange.new(connection, channel, "amq.fanout", :fanout) 100.times do |i| exchange.publish("Message ##{i}") end end Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end amq-client-0.9.3/examples/eventmachine_adapter/tx_select.rb0000755000175000017500000000124611771004303023366 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Choose to use acknowledgement transactions on a channel using tx.select" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do channel.tx_select do puts "Channel #{channel.id} is now using ack transactions" end show_stopper = Proc.new { client.disconnect do puts puts "AMQP connection is now properly closed" EM.stop end } Signal.trap "INT", show_stopper Signal.trap "TERM", show_stopper EM.add_timer(1, show_stopper) end end amq-client-0.9.3/examples/eventmachine_adapter/queue_declare.rb0000755000175000017500000000212211771004303024171 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 __dir = File.dirname(File.expand_path(__FILE__)) require File.join(__dir, "example_helper") amq_client_example "Purge a queue and announce how many messages it had" do |client| channel = AMQ::Client::Channel.new(client, 1) channel.open do puts "Channel #{channel.id} is now open!" 4.times do q = AMQ::Client::Queue.new(client, channel, AMQ::Protocol::EMPTY_STRING) q.declare(false, false, false, true) end begin q = AMQ::Client::Queue.new(client, channel, AMQ::Protocol::EMPTY_STRING) q.declare(false, false, false, true, true) rescue ArgumentError => e puts "Non-sensical declaration of a server-named queue with nowait did not slip through, great" end queue = AMQ::Client::Queue.new(client, channel, AMQ::Protocol::EMPTY_STRING) queue.declare(false, false, false, true) do puts "Queue #{queue.name.inspect} is now declared!" puts "Channel is aware of the following queues: #{channel.queues.map { |q| q.name }.join(', ')}" client.disconnect { EM.stop } end end end amq-client-0.9.3/.travis.yml0000644000175000017500000000057611771004303015176 0ustar tfheentfheenlanguage: ruby bundler_args: --without development before_script: ./bin/ci/before_build.sh script: "bundle exec rspec spec" rvm: - jruby-19mode - jruby-head - 1.8.7 - rbx-19mode - 1.9.2 - 1.9.3 gemfile: - Gemfile - gemfiles/eventmachine-pre notifications: recipients: - michaelklishin@me.com branches: only: - master - 0.9.x-stable - 0.8.x-stableamq-client-0.9.3/.gitignore0000644000175000017500000000017011771004303015043 0ustar tfheentfheen/*.gem .bundle vendor/bundle .yardoc/* doc/* .rvmrc # see http://bit.ly/h2WJPm for reasoning Gemfile.lock vendor .rbx/* amq-client-0.9.3/irb.rb0000755000175000017500000000330311771004303014160 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 # This file is supposed to make inspecting AMQ client easier. # How does it work: # 1) This file is executed. # 2) We load irb, redefine where IRB looks for .irbrc and start IRB. # 3) IRB loads .irbrc, which we redefined, so it loads this file again. # However now the second branch of "if __FILE__ == $0" gets executed, # so it runs our custom code which loads the original .irbrc and then # it redefines some IRB settings. In this case it add IRB hook which # is executed after IRB is started. # Although it looks unnecessarily complicated, I can't see any easier # solution to this problem in case that you need to patch original settings. # Obviously in case you don't have the need, you'll be happy with simple: # require "irb" # # require_relative "lib/amq/protocol/client.rb" # include AMQ::Protocol # # IRB.start(__FILE__) require "irb" require "bundler" Bundler.setup Bundler.require(:default) $LOAD_PATH.unshift(File.expand_path("../lib", __FILE__)) if __FILE__ == $0 puts "~ Using #{__FILE__} as an executable ..." def IRB.rc_file_generators yield Proc.new { |_| __FILE__ } end IRB.start(__FILE__) else begin irbrc = File.join(ENV["HOME"], ".irbrc") puts "~ Using #{__FILE__} as a custom .irbrc .." require "amq/client.rb" include AMQ::Client require "amq/protocol/client" include AMQ require "stringio" def fd(data) Frame.decode(StringIO.new(data)) end puts "~ Loading original #{irbrc} ..." load irbrc puts "Loading finished." rescue Exception => exception # it just discards all the exceptions! abort exception.message + "\n - " + exception.backtrace.join("\n - ") end end amq-client-0.9.3/Gemfile0000644000175000017500000000237511771004303014357 0ustar tfheentfheen# encoding: utf-8 source :rubygems # Use local clones if possible. # If you want to use your local copy, just symlink it to vendor. # See http://blog.101ideas.cz/posts/custom-gems-in-gemfile.html extend Module.new { def gem(name, *args) options = args.last.is_a?(Hash) ? args.last : Hash.new local_path = File.expand_path("../vendor/#{name}", __FILE__) if File.exist?(local_path) super name, options.merge(:path => local_path). delete_if { |key, _| [:git, :branch].include?(key) } else super name, *args end end } gem "eventmachine" # cool.io uses iobuffer that won't compile on JRuby # (and, probably, Windows) gem "cool.io", :platform => :ruby gem "amq-protocol", :git => "git://github.com/ruby-amqp/amq-protocol.git", :branch => "master" group :development do gem "yard" # yard tags this buddy along gem "RedCloth", :platform => :mri gem "nake", :platform => :ruby_19 # excludes Windows and JRuby gem "perftools.rb", :platform => :mri end group :test do gem "rspec", ">= 2.6.0" gem "evented-spec", :git => "git://github.com/ruby-amqp/evented-spec.git", :branch => "master" gem "effin_utf8" gem "multi_json" gem "json", :platform => :jruby gem "yajl-ruby", :platform => :ruby_18 end amq-client-0.9.3/bin/0000755000175000017500000000000011771004303013625 5ustar tfheentfheenamq-client-0.9.3/bin/ci/0000755000175000017500000000000011771004303014220 5ustar tfheentfheenamq-client-0.9.3/bin/ci/before_build.sh0000755000175000017500000000161011771004303017176 0ustar tfheentfheen#!/bin/sh # guest:guest has full access to / sudo rabbitmqctl add_vhost / sudo rabbitmqctl add_user guest guest sudo rabbitmqctl set_permissions -p / guest ".*" ".*" ".*" # guest:guest has full access to amq_client_testbed # amq_client_gem:amq_client_gem has full access to /amq_client_testbed sudo rabbitmqctl delete_vhost "amq_client_testbed" sudo rabbitmqctl add_vhost "amq_client_testbed" sudo rabbitmqctl delete_user amq_client_gem sudo rabbitmqctl add_user amq_client_gem amq_client_gem_password sudo rabbitmqctl set_permissions -p amq_client_testbed guest ".*" ".*" ".*" sudo rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem ".*" ".*" ".*" # amqp_gem_reader:reader_password has read access to amq_client_testbed sudo rabbitmqctl add_user amq_client_gem_reader reader_password sudo rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem_reader "^---$" "^---$" ".*"amq-client-0.9.3/bin/set_test_suite_realms_up.sh0000755000175000017500000000152111771004303021275 0ustar tfheentfheen#!/bin/sh # guest:guest has full access to / rabbitmqctl add_vhost / rabbitmqctl add_user guest guest rabbitmqctl set_permissions -p / guest ".*" ".*" ".*" # guest:guest has full access to amq_client_testbed # amq_client_gem:amq_client_gem has full access to /amq_client_testbed rabbitmqctl delete_vhost "amq_client_testbed" rabbitmqctl add_vhost "amq_client_testbed" rabbitmqctl delete_user amq_client_gem rabbitmqctl add_user amq_client_gem amq_client_gem_password rabbitmqctl set_permissions -p amq_client_testbed guest ".*" ".*" ".*" rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem ".*" ".*" ".*" # amqp_gem_reader:reader_password has read access to amq_client_testbed rabbitmqctl add_user amq_client_gem_reader reader_password rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem_reader "^---$" "^---$" ".*"amq-client-0.9.3/lib/0000755000175000017500000000000011771004303013623 5ustar tfheentfheenamq-client-0.9.3/lib/amq/0000755000175000017500000000000011771004303014401 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client.rb0000644000175000017500000000447511771004303016216 0ustar tfheentfheen# encoding: utf-8 require "amq/client/version" require "amq/client/exceptions" require "amq/client/handlers_registry" require "amq/client/adapter" require "amq/client/channel" require "amq/client/exchange" require "amq/client/queue" begin require "amq/protocol/client" rescue LoadError => exception if exception.message.match("amq/protocol") raise LoadError.new("amq-client could not load amq-protocol.") else raise exception end end module AMQ module Client # List available adapters as a hash of { :adapter_name => metadata }, # where metadata are hash with :path and :const_name keys. # # @return [Hash] # @api plugin def self.adapters @adapters ||= (self.async_adapters) end # List available asynchronous adapters. # # @return [Hash] # @api plugin # @see AMQ::Client.adapters def self.async_adapters @async_adapters ||= { :eventmachine => { :path => "amq/client/async/adapters/eventmachine", :const_name => "Async::EventMachineClient" }, :event_machine => { :path => "amq/client/async/adapters/eventmachine", :const_name => "Async::EventMachineClient" }, :coolio => { :path => "amq/client/async/adapters/coolio", :const_name => "Async::CoolioClient" } } end # Establishes connection to AMQ broker using given adapter # (defaults to the socket adapter) and returns it. The new # connection object is yielded to the block if it is given. # # @example # AMQ::Client.connect(adapter: "socket") do |client| # # Use the client. # end # @param [Hash] Connection parameters, including :adapter to use. # @api public def self.connect(settings = nil, &block) adapter = (settings && settings.delete(:adapter)) adapter = load_adapter(adapter) adapter.connect(settings, &block) end # Loads adapter given its name as a Symbol. # # @raise [InvalidAdapterNameError] When loading attempt failed (LoadError was raised). def self.load_adapter(adapter) meta = self.adapters[adapter.to_sym] require meta[:path] eval(meta[:const_name]) rescue LoadError raise InvalidAdapterNameError.new(adapter) end end # Client end # AMQ amq-client-0.9.3/lib/amq/protocol/0000755000175000017500000000000011771004303016242 5ustar tfheentfheenamq-client-0.9.3/lib/amq/protocol/get_response.rb0000644000175000017500000000211511771004303021263 0ustar tfheentfheen# encoding: utf-8 # Purpose of this class is to simplify work with GetOk and GetEmpty. module AMQ module Protocol class GetResponse attr_reader :method def initialize(method) @method = method end def empty? @method.is_a?(::AMQ::Protocol::Basic::GetEmpty) end # GetOk attributes def delivery_tag if @method.respond_to?(:delivery_tag) @method.delivery_tag end end def redelivered if @method.respond_to?(:redelivered) @method.redelivered end end def exchange if @method.respond_to?(:exchange) @method.exchange end end def routing_key if @method.respond_to?(:routing_key) @method.routing_key end end def message_count if @method.respond_to?(:message_count) @method.message_count end end # GetEmpty attributes def cluster_id if @method.respond_to?(:cluster_id) @method.cluster_id end end end end end amq-client-0.9.3/lib/amq/client/0000755000175000017500000000000011771004303015657 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/logging.rb0000644000175000017500000000316011771004303017632 0ustar tfheentfheen# encoding: utf-8 # You can use arbitrary logger which responds to #debug, #info, #error and #fatal methods, so for example the logger from standard library will work fine: # # AMQ::Client.logging = true # AMQ::Client.logger = MyLogger.new(STDERR) # # AMQ::Client.logger defaults to a new instance of Ruby stdlib logger. # # If you want to be able to log messages just from specified classes or even instances, just make the instance respond to #logging and set it to desired value. So for example Queue.class_eval { def logging; true; end } will turn on logging for the whole Queue class whereas queue = Queue.new; def queue.logging; false; end will disable logging for given Queue instance. module AMQ module Client module Logging def self.included(klass) unless klass.method_defined?(:client) raise NotImplementedError.new("Class #{klass} has to provide #client method!") end end def self.logging @logging ||= false end def self.logging=(boolean) @logging = boolean end REQUIRED_METHODS = [:debug, :info, :error, :fatal].freeze def debug(message) log(:debug, message) end def info(message) log(:info, message) end def error(message) log(:error, message) end def fatal(message) log(:fatal, message) end protected def log(method, message) if self.respond_to?(:logging) ? self.logging : AMQ::Client::Logging.logging self.client.logger.__send__(method, message) message end end end end end amq-client-0.9.3/lib/amq/client/version.rb0000644000175000017500000000011611771004303017667 0ustar tfheentfheen# encoding: utf-8 module AMQ module Client VERSION = "0.9.3" end end amq-client-0.9.3/lib/amq/client/handlers_registry.rb0000644000175000017500000000070111771004303021732 0ustar tfheentfheen# encoding: utf-8 module AMQ module Client class HandlersRegistry @@handlers ||= Hash.new # # API # def self.register(klass, &block) @@handlers[klass] = block end class << self alias handle register end def self.find(klass) @@handlers[klass] end def self.handlers @@handlers end end # HandlersRegistry end # Client end # AMQamq-client-0.9.3/lib/amq/client/async/0000755000175000017500000000000011771004303016774 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/async/adapters/0000755000175000017500000000000011771004303020577 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/async/adapters/coolio.rb0000644000175000017500000002065111771004303022414 0ustar tfheentfheen# encoding: utf-8 # http://coolio.github.com require "cool.io" require "amq/client" require "amq/client/framing/string/frame" module AMQ module Client module Async # # CoolioClient is a drop-in replacement for EventMachineClient, if you prefer # cool.io style. # class CoolioClient # # Behaviours # include AMQ::Client::Async::Adapter # # API # # # Cool.io socket delegates most of its operations to the parent adapter. # Thus, 99.9% of the time you don't need to deal with this class. # # @api private # @private class Socket < ::Coolio::TCPSocket attr_accessor :adapter # Connects to given host/port and sets parent adapter. # # @param [CoolioClient] # @param [String] # @param [Fixnum] def self.connect(adapter, host, port) socket = super(host, port) socket.adapter = adapter socket end # Triggers socket_connect callback def on_connect #puts "On connect" adapter.socket_connected end # Triggers on_read callback def on_read(data) # puts "Received data" # puts_data(data) adapter.receive_data(data) end # Triggers socket_disconnect callback def on_close adapter.socket_disconnected end # Triggers tcp_connection_failed callback def on_connect_failed adapter.tcp_connection_failed end # Sends raw data through the socket # # param [String] Binary data def send_raw(data) # puts "Sending data" # puts_data(data) write(data) end protected # Debugging routine def puts_data(data) puts " As string: #{data.inspect}" puts " As byte array: #{data.bytes.to_a.inspect}" end end # Cool.io socket for multiplexing et al. # # @private attr_accessor :socket # Hash with available callbacks attr_accessor :callbacks # Creates a socket and attaches it to cool.io default loop. # # Called from CoolioClient.connect # # @see AMQ::Client::Adapter::ClassMethods#connect # @param [Hash] connection settings # @api private def establish_connection(settings) @settings = Settings.configure(settings) socket = Socket.connect(self, @settings[:host], @settings[:port]) socket.attach(Cool.io::Loop.default) self.socket = socket @on_tcp_connection_failure = @settings[:on_tcp_connection_failure] || Proc.new { |settings| raise self.class.tcp_connection_failure_exception_class.new(settings) } @on_possible_authentication_failure = @settings[:on_possible_authentication_failure] || Proc.new { |settings| raise self.class.authentication_failure_exception_class.new(settings) } @locale = @settings.fetch(:locale, "en_GB") @client_properties = Settings.client_properties.merge(@settings.fetch(:client_properties, Hash.new)) @auto_recovery = (!!@settings[:auto_recovery]) socket end # Registers on_open callback # @see #on_open # @api private def register_connection_callback(&block) self.on_open(&block) end # Performs basic initialization. Do not use this method directly, use # CoolioClient.connect instead # # @see AMQ::Client::Adapter::ClassMethods#connect # @api private def initialize # Be careful with default values for #ruby hashes: h = Hash.new(Array.new); h[:key] ||= 1 # won't assign anything to :key. MK. @callbacks = Hash.new self.logger = self.class.logger # channel => collected frames. MK. @frames = Hash.new { Array.new } @channels = Hash.new @mechanism = "PLAIN" end # Sets a callback for successful connection (after we receive open-ok) # # @api public def on_open(&block) define_callback :connect, &block end alias on_connection on_open # Sets a callback for disconnection (as in client-side disconnection) # # @api public def on_closed(&block) define_callback :disconnect, &block end alias on_disconnection on_closed # Sets a callback for tcp connection failure (as in can't make initial connection) def on_tcp_connection_failure(&block) define_callback :tcp_connection_failure, &block end # Called by AMQ::Client::Connection after we receive connection.open-ok. # # @api private def connection_successful @authenticating = false opened! exec_callback_yielding_self(:connect) end # Called by AMQ::Client::Connection after we receive connection.close-ok. # # @api private def disconnection_successful exec_callback_yielding_self(:disconnect) close_connection closed! end # Called when socket is connected but before handshake is done # # @api private def socket_connected post_init end # Called after socket is closed # # @api private def socket_disconnected end alias close disconnect self.handle(Protocol::Connection::Start) do |connection, frame| connection.handle_start(frame.decode_payload) end self.handle(Protocol::Connection::Tune) do |connection, frame| connection.handle_tune(frame.decode_payload) connection.open(connection.vhost) end self.handle(Protocol::Connection::OpenOk) do |connection, frame| connection.handle_open_ok(frame.decode_payload) end self.handle(Protocol::Connection::Close) do |connection, frame| connection.handle_close(frame.decode_payload) end self.handle(Protocol::Connection::CloseOk) do |connection, frame| connection.handle_close_ok(frame.decode_payload) end # Sends raw data through the socket # # @param [String] binary data # @api private def send_raw(data) socket.send_raw data end # The story about the buffering is kinda similar to EventMachine, # you keep receiving more than one frame in a single packet. # # @param [String] chunk with binary data received. It could be one frame, # more than one frame or less than one frame. # @api private def receive_data(chunk) @chunk_buffer << chunk while frame = get_next_frame receive_frame(AMQ::Client::Framing::String::Frame.decode(frame)) end end # Closes the socket. # # @api private def close_connection @socket.close end # Returns class used for tcp connection failures. # # @api private def self.tcp_connection_failure_exception_class AMQ::Client::TCPConnectionFailed end # self.tcp_connection_failure_exception_class def handle_skipped_hearbeats # TODO end protected # @api private def post_init if @had_successfully_connected_before @recovered = true self.exec_callback_yielding_self(:before_recovery, @settings) self.register_connection_callback do self.auto_recover self.exec_callback_yielding_self(:after_recovery, @settings) end end # now we can set it. MK. @had_successfully_connected_before = true @reconnecting = false @handling_skipped_hearbeats = false self.reset self.handshake end # @api private def reset @chunk_buffer = "" @frames = Array.new end end # CoolioClient end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/adapters/event_machine.rb0000644000175000017500000003434611771004303023743 0ustar tfheentfheen# encoding: utf-8 require "eventmachine" require "amq/client" require "amq/client/async/adapter" require "amq/client/framing/string/frame" module AMQ module Client module Async class EventMachineClient < EM::Connection # # Behaviours # include AMQ::Client::Async::Adapter # # API # # @group Connection operations # Initiates connection to AMQP broker. If callback is given, runs it when (and if) AMQP connection # succeeds. # # @option settings [String] :host ("127.0.0.1") Hostname AMQ broker runs on. # @option settings [String] :port (5672) Port AMQ broker listens on. # @option settings [String] :vhost ("/") Virtual host to use. # @option settings [String] :user ("guest") Username to use for authentication. # @option settings [String] :pass ("guest") Password to use for authentication. # @option settings [String] :ssl (false) Should be use TLS (SSL) for connection? # @option settings [String] :timeout (nil) Connection timeout. # @option settings [String] :logging (false) Turns logging on or off. # @option settings [String] :broker (nil) Broker name (use if you intend to use broker-specific features). # @option settings [Fixnum] :frame_max (131072) Maximum frame size to use. If broker cannot support frames this large, broker's maximum value will be used instead. # # @param [Hash] settings def self.connect(settings = {}, &block) @settings = Settings.configure(settings) instance = EventMachine.connect(@settings[:host], @settings[:port], self, @settings) instance.register_connection_callback(&block) instance end # Reconnect after a period of wait. # # @param [Fixnum] period Period of time, in seconds, to wait before reconnection attempt. # @param [Boolean] force If true, enforces immediate reconnection. # @api public def reconnect(force = false, period = 5) if @reconnecting and not force EventMachine::Timer.new(period) { reconnect(true, period) } return end if !@reconnecting @reconnecting = true self.reset end EventMachine.reconnect(@settings[:host], @settings[:port], self) end # Similar to #reconnect, but uses different connection settings # @see #reconnect # @api public def reconnect_to(settings, period = 5) if !@reconnecting @reconnecting = true self.reset end @settings = Settings.configure(settings) EventMachine.reconnect(@settings[:host], @settings[:port], self) end # Periodically try to reconnect. # # @param [Fixnum] period Period of time, in seconds, to wait before reconnection attempt. # @param [Boolean] force If true, enforces immediate reconnection. # @api public def periodically_reconnect(period = 5) @reconnecting = true self.reset @periodic_reconnection_timer = EventMachine::PeriodicTimer.new(period) { EventMachine.reconnect(@settings[:host], @settings[:port], self) } end # @endgroup # Defines a callback that will be executed when AMQP connection is considered open: # client and broker has agreed on max channel identifier and maximum allowed frame # size and authentication succeeds. You can define more than one callback. # # @see on_possible_authentication_failure # @api public def on_open(&block) @connection_deferrable.callback(&block) end # on_open(&block) alias on_connection on_open # Defines a callback that will be run when broker confirms connection termination # (client receives connection.close-ok). You can define more than one callback. # # @api public def on_closed(&block) @disconnection_deferrable.callback(&block) end # on_closed(&block) alias on_disconnection on_closed # @see #on_open # @private def register_connection_callback(&block) unless block.nil? # delay calling block we were given till after we receive # connection.open-ok. Connection will notify us when # that happens. self.on_open do block.call(self) end end end def initialize(*args) super(*args) self.logger = self.class.logger # channel => collected frames. MK. @frames = Hash.new { Array.new } @channels = Hash.new @callbacks = Hash.new opening! # track TCP connection state, used to detect initial TCP connection failures. @tcp_connection_established = false @tcp_connection_failed = false @intentionally_closing_connection = false # EventMachine::Connection's and Adapter's constructors arity # make it easier to use *args. MK. @settings = Settings.configure(args.first) @on_tcp_connection_failure = @settings[:on_tcp_connection_failure] || Proc.new { |settings| raise self.class.tcp_connection_failure_exception_class.new(settings) } @on_possible_authentication_failure = @settings[:on_possible_authentication_failure] || Proc.new { |settings| raise self.class.authentication_failure_exception_class.new(settings) } @mechanism = "PLAIN" @locale = @settings.fetch(:locale, "en_GB") @client_properties = Settings.client_properties.merge(@settings.fetch(:client_properties, Hash.new)) @auto_recovery = (!!@settings[:auto_recovery]) self.reset self.set_pending_connect_timeout((@settings[:timeout] || 3).to_f) unless defined?(JRUBY_VERSION) if self.heartbeat_interval > 0 self.initialize_heartbeat_sender end end # initialize(*args) # For EventMachine adapter, this is a no-op. # @api public def establish_connection(settings) # Unfortunately there doesn't seem to be any sane way # how to get EventMachine connect to the instance level. end alias close disconnect # Whether we are in authentication state (after TCP connection was estabilished # but before broker authenticated us). # # @return [Boolean] # @api public def authenticating? @authenticating end # authenticating? # IS TCP connection estabilished and currently active? # @return [Boolean] # @api public def tcp_connection_established? @tcp_connection_established end # tcp_connection_established? # # Implementation # # Backwards compatibility with 0.7.0.a25. MK. Deferrable = EventMachine::DefaultDeferrable alias send_raw send_data # EventMachine reactor callback. Is run when TCP connection is estabilished # but before resumption of the network loop. Note that this includes cases # when TCP connection has failed. # @private def post_init reset # note that upgrading to TLS in #connection_completed causes # Erlang SSL app that RabbitMQ relies on to report # error on TCP connection <0.1465.0>:{ssl_upgrade_error,"record overflow"} # and close TCP connection down. Investigation of this issue is likely # to take some time and to not be worth in as long as #post_init # works fine. MK. upgrade_to_tls_if_necessary rescue Exception => error raise error end # post_init # Called by EventMachine reactor once TCP connection is successfully estabilished. # @private def connection_completed # we only can safely set this value here because EventMachine is a lovely piece of # software that calls #post_init before #unbind even when TCP connection # fails. MK. @tcp_connection_established = true @periodic_reconnection_timer.cancel if @periodic_reconnection_timer # again, this is because #unbind is called in different situations # and there is no easy way to tell initial connection failure # from connection loss. Not in EventMachine 0.12.x, anyway. MK. if @had_successfully_connected_before @recovered = true self.start_automatic_recovery self.upgrade_to_tls_if_necessary end # now we can set it. MK. @had_successfully_connected_before = true @reconnecting = false @handling_skipped_hearbeats = false @last_server_heartbeat = Time.now self.initialize_heartbeat_sender if self.heartbeat_interval > 0 self.handshake end # @private def close_connection(*args) @intentionally_closing_connection = true super(*args) end # Called by EventMachine reactor when # # * We close TCP connection down # * Our peer closes TCP connection down # * There is a network connection issue # * Initial TCP connection fails # @private def unbind(exception = nil) if !@tcp_connection_established && !@had_successfully_connected_before && !@intentionally_closing_connection @tcp_connection_failed = true logger.error "[amqp] Detected TCP connection failure" self.tcp_connection_failed end closing! @tcp_connection_established = false self.handle_connection_interruption if @reconnecting @disconnection_deferrable.succeed closed! self.tcp_connection_lost if !@intentionally_closing_connection && @had_successfully_connected_before # since AMQP spec dictates that authentication failure is a protocol exception # and protocol exceptions result in connection closure, check whether we are # in the authentication stage. If so, it is likely to signal an authentication # issue. Java client behaves the same way. MK. if authenticating? && !@intentionally_closing_connection @on_possible_authentication_failure.call(@settings) if @on_possible_authentication_failure end end # unbind # # EventMachine receives data in chunks, sometimes those chunks are smaller # than the size of AMQP frame. That's why you need to add some kind of buffer. # # @private def receive_data(chunk) @chunk_buffer << chunk while frame = get_next_frame self.receive_frame(AMQ::Client::Framing::String::Frame.decode(frame)) end end # Called by AMQ::Client::Connection after we receive connection.open-ok. # @api public def connection_successful @authenticating = false opened! @connection_deferrable.succeed end # connection_successful # Called by AMQ::Client::Connection after we receive connection.close-ok. # # @api public def disconnection_successful @disconnection_deferrable.succeed # true for "after writing buffered data" self.close_connection(true) self.reset closed! end # disconnection_successful # Called when time since last server heartbeat received is greater or equal to the # heartbeat interval set via :heartbeat_interval option on connection. # # @api plugin def handle_skipped_hearbeats if !@handling_skipped_hearbeats && @tcp_connection_established && !@intentionally_closing_connection @handling_skipped_hearbeats = true @heartbeats_timer.cancel self.run_skipped_heartbeats_callbacks end end # @private def initialize_heartbeat_sender @last_server_heartbeat = Time.now @heartbeats_timer = EventMachine::PeriodicTimer.new(self.heartbeat_interval, &method(:send_heartbeat)) end self.handle(Protocol::Connection::Start) do |connection, frame| connection.handle_start(frame.decode_payload) end self.handle(Protocol::Connection::Tune) do |connection, frame| connection.handle_tune(frame.decode_payload) connection.open(connection.vhost) end self.handle(Protocol::Connection::OpenOk) do |connection, frame| connection.handle_open_ok(frame.decode_payload) end self.handle(Protocol::Connection::Close) do |connection, frame| connection.handle_close(frame.decode_payload) end self.handle(Protocol::Connection::CloseOk) do |connection, frame| connection.handle_close_ok(frame.decode_payload) end protected def reset @size = 0 @payload = "" @frames = Array.new @chunk_buffer = "" @connection_deferrable = EventMachine::DefaultDeferrable.new @disconnection_deferrable = EventMachine::DefaultDeferrable.new # used to track down whether authentication succeeded. AMQP 0.9.1 dictates # that on authentication failure broker must close TCP connection without sending # any more data. This is why we need to explicitly track whether we are past # authentication stage to signal possible authentication failures. @authenticating = false end def upgrade_to_tls_if_necessary tls_options = @settings[:ssl] if tls_options.is_a?(Hash) start_tls(tls_options) elsif tls_options start_tls end end # upgrade_to_tls_if_necessary end # EventMachineClient end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/adapters/eventmachine.rb0000644000175000017500000000010511771004303023566 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/adapters/event_machine" amq-client-0.9.3/lib/amq/client/async/adapter.rb0000644000175000017500000005565011771004303020754 0ustar tfheentfheen# encoding: utf-8 require "amq/client/logging" require "amq/client/settings" require "amq/client/async/entity" require "amq/client/async/channel" module AMQ # For overview of AMQP client adapters API, see {AMQ::Client::Adapter} module Client module Async # Base adapter class. Specific implementations (for example, EventMachine-based, Cool.io-based or # sockets-based) subclass it and must implement Adapter API methods: # # * #send_raw(data) # * #estabilish_connection(settings) # * #close_connection # # @abstract module Adapter def self.included(host) host.extend ClassMethods host.extend ProtocolMethodHandlers host.class_eval do # # API # attr_accessor :logger attr_accessor :settings # @return [Array<#call>] attr_reader :callbacks # The locale defines the language in which the server will send reply texts. # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.2) attr_accessor :locale # Client capabilities # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.2.1) attr_accessor :client_properties # Server properties # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.1.3) attr_reader :server_properties # Server capabilities # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.1.3) attr_reader :server_capabilities # Locales server supports # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.1.3) attr_reader :server_locales # Authentication mechanism used. # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.2) attr_reader :mechanism # Authentication mechanisms broker supports. # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.2) attr_reader :server_authentication_mechanisms # Channels within this connection. # # @see http://bit.ly/amqp091spec AMQP 0.9.1 specification (Section 2.2.5) attr_reader :channels # Maximum channel number that the server permits this connection to use. # Usable channel numbers are in the range 1..channel_max. # Zero indicates no specified limit. # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Sections 1.4.2.5.1 and 1.4.2.6.1) attr_accessor :channel_max # Maximum frame size that the server permits this connection to use. # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Sections 1.4.2.5.2 and 1.4.2.6.2) attr_accessor :frame_max attr_reader :known_hosts # @api plugin # @see #disconnect # @note Adapters must implement this method but it is NOT supposed to be used directly. # AMQ protocol defines two-step process of closing connection (send Connection.Close # to the peer and wait for Connection.Close-Ok), implemented by {Adapter#disconnect} def close_connection raise NotImplementedError end unless defined?(:close_connection) # since it is a module, this method may already be defined end end # self.included(host) module ClassMethods # Settings def settings @settings ||= AMQ::Client::Settings.default end def logger @logger ||= begin require "logger" Logger.new(STDERR) end end def logger=(logger) methods = AMQ::Client::Logging::REQUIRED_METHODS unless methods.all? { |method| logger.respond_to?(method) } raise AMQ::Client::Logging::IncompatibleLoggerError.new(methods) end @logger = logger end # @return [Boolean] Current value of logging flag. def logging settings[:logging] end # Turns loggin on or off. def logging=(boolean) settings[:logging] = boolean end # Establishes connection to AMQ broker and returns it. New connection object is yielded to # the block if it is given. # # @example Specifying adapter via the :adapter option # AMQ::Client::Adapter.connect(:adapter => "socket") # @example Specifying using custom adapter class # AMQ::Client::SocketClient.connect # @param [Hash] Connection parameters, including :adapter to use. # @api public def connect(settings = nil, &block) @settings = Settings.configure(settings) instance = self.new instance.establish_connection(settings) instance.register_connection_callback(&block) instance end # Can be overriden by higher-level libraries like amqp gem or bunny. # Defaults to AMQ::Client::TCPConnectionFailed. # # @return [Class] def tcp_connection_failure_exception_class @tcp_connection_failure_exception_class ||= AMQ::Client::TCPConnectionFailed end # tcp_connection_failure_exception_class # Can be overriden by higher-level libraries like amqp gem or bunny. # Defaults to AMQ::Client::PossibleAuthenticationFailure. # # @return [Class] def authentication_failure_exception_class @authentication_failure_exception_class ||= AMQ::Client::PossibleAuthenticationFailureError end # authentication_failure_exception_class end # ClassMethods # # Behaviors # include Openable include Callbacks extend RegisterEntityMixin register_entity :channel, AMQ::Client::Async::Channel # # API # # Establish socket connection to the server. # # @api plugin def establish_connection(settings) raise NotImplementedError end # Properly close connection with AMQ broker, as described in # section 2.2.4 of the {http://bit.ly/amqp091spec AMQP 0.9.1 specification}. # # @api plugin # @see #close_connection def disconnect(reply_code = 200, reply_text = "Goodbye", class_id = 0, method_id = 0, &block) @intentionally_closing_connection = true self.on_disconnection do @frames.clear block.call if block end # ruby-amqp/amqp#66, MK. if self.open? closing! self.send_frame(Protocol::Connection::Close.encode(reply_code, reply_text, class_id, method_id)) elsif self.closing? # no-op else self.disconnection_successful end end # Sends AMQ protocol header (also known as preamble). # # @note This must be implemented by all AMQP clients. # @api plugin # @see http://bit.ly/amqp091spec AMQP 0.9.1 specification (Section 2.2) def send_preamble self.send_raw(AMQ::Protocol::PREAMBLE) end # Sends frame to the peer, checking that connection is open. # # @raise [ConnectionClosedError] def send_frame(frame) if closed? raise ConnectionClosedError.new(frame) else self.send_raw(frame.encode) end end # Sends multiple frames, one by one. For thread safety this method takes a channel # object and synchronizes on it. # # @api public def send_frameset(frames, channel) # some (many) developers end up sharing channels between threads and when multiple # threads publish on the same channel aggressively, at some point frames will be # delivered out of order and broker will raise 505 UNEXPECTED_FRAME exception. # If we synchronize on the channel, however, this is both thread safe and pretty fine-grained # locking. Note that "single frame" methods do not need this kind of synchronization. MK. channel.synchronize do frames.each { |frame| self.send_frame(frame) } end end # send_frameset(frames) # Returns heartbeat interval this client uses, in seconds. # This value may or may not be used depending on broker capabilities. # Zero means the server does not want a heartbeat. # # @return [Fixnum] Heartbeat interval this client uses, in seconds. # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.6) def heartbeat_interval @settings[:heartbeat] || @settings[:heartbeat_interval] || 0 end # heartbeat_interval # vhost this connection uses. Default is "/", a historically estabilished convention # of RabbitMQ and amqp gem. # # @return [String] vhost this connection uses # @api public def vhost @settings.fetch(:vhost, "/") end # vhost # @group Error Handling and Recovery # Called when initial TCP connection fails. # @api public def tcp_connection_failed @recovered = false @on_tcp_connection_failure.call(@settings) if @on_tcp_connection_failure end # Called when previously established TCP connection fails. # @api public def tcp_connection_lost @recovered = false @on_tcp_connection_loss.call(self, @settings) if @on_tcp_connection_loss self.handle_connection_interruption end # @return [Boolean] def reconnecting? @reconnecting end # reconnecting? # Defines a callback that will be run when initial TCP connection fails. # You can define only one callback. # # @api public def on_tcp_connection_failure(&block) @on_tcp_connection_failure = block end # Defines a callback that will be run when TCP connection to AMQP broker is lost (interrupted). # You can define only one callback. # # @api public def on_tcp_connection_loss(&block) @on_tcp_connection_loss = block end # Defines a callback that will be run when TCP connection is closed before authentication # finishes. Usually this means authentication failure. You can define only one callback. # # @api public def on_possible_authentication_failure(&block) @on_possible_authentication_failure = block end # Defines a callback that will be executed when connection is closed after # connection-level exception. Only one callback can be defined (the one defined last # replaces previously added ones). # # @api public def on_error(&block) self.redefine_callback(:error, &block) end # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure). # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_connection_interruption(&block) self.redefine_callback(:after_connection_interruption, &block) end # on_connection_interruption(&block) alias after_connection_interruption on_connection_interruption # @private # @api plugin def handle_connection_interruption @channels.each { |n, c| c.handle_connection_interruption } self.exec_callback_yielding_self(:after_connection_interruption) end # handle_connection_interruption # Defines a callback that will be executed after TCP connection has recovered after a network failure # but before AMQP connection is re-opened. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def before_recovery(&block) self.redefine_callback(:before_recovery, &block) end # before_recovery(&block) # @private def run_before_recovery_callbacks self.exec_callback_yielding_self(:before_recovery, @settings) @channels.each { |n, ch| ch.run_before_recovery_callbacks } end # Defines a callback that will be executed after AMQP connection has recovered after a network failure.. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_recovery(&block) self.redefine_callback(:after_recovery, &block) end # on_recovery(&block) alias after_recovery on_recovery # @private def run_after_recovery_callbacks self.exec_callback_yielding_self(:after_recovery, @settings) @channels.each { |n, ch| ch.run_after_recovery_callbacks } end # @return [Boolean] whether connection is in the automatic recovery mode # @api public def auto_recovering? !!@auto_recovery end # auto_recovering? alias auto_recovery? auto_recovering? # Performs recovery of channels that are in the automatic recovery mode. Does not run recovery # callbacks. # # @see Channel#auto_recover # @see Queue#auto_recover # @see Exchange#auto_recover # @api plugin def auto_recover @channels.select { |channel_id, ch| ch.auto_recovering? }.each { |n, ch| ch.auto_recover } end # auto_recover # Performs recovery of channels that are in the automatic recovery mode. "before recovery" callbacks # are run immediately, "after recovery" callbacks are run after AMQP connection is re-established and # auto recovery is performed (using #auto_recover). # # Use this method if you want to run automatic recovery process after handling a connection-level exception, # for example, 320 CONNECTION_FORCED (used by RabbitMQ when it is shut down gracefully). # # @see Channel#auto_recover # @see Queue#auto_recover # @see Exchange#auto_recover # @api plugin def start_automatic_recovery self.run_before_recovery_callbacks self.register_connection_callback do # always run automatic recovery, because it is per-channel # and connection has to start it. Channels that did not opt-in for # autorecovery won't be selected. MK. self.auto_recover self.run_after_recovery_callbacks end end # start_automatic_recovery # Defines a callback that will be executed after time since last broker heartbeat is greater # than or equal to the heartbeat interval (skipped heartbeat is detected). # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_skipped_heartbeats(&block) self.redefine_callback(:skipped_heartbeats, &block) end # on_skipped_heartbeats(&block) # @private def run_skipped_heartbeats_callbacks self.exec_callback_yielding_self(:skipped_heartbeats, @settings) end # @endgroup # # Implementation # # Sends opaque data to AMQ broker over active connection. # # @note This must be implemented by all AMQP clients. # @api plugin def send_raw(data) raise NotImplementedError end # Sends connection preamble to the broker. # @api plugin def handshake @authenticating = true self.send_preamble end # Sends connection.open to the server. # # @api plugin # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.7) def open(vhost = "/") self.send_frame(Protocol::Connection::Open.encode(vhost)) end # Resets connection state. # # @api plugin def reset_state! # no-op by default end # reset_state! # @api plugin # @see http://tools.ietf.org/rfc/rfc2595.txt RFC 2595 def encode_credentials(username, password) "\0#{username}\0#{password}" end # encode_credentials(username, password) # Processes a single frame. # # @param [AMQ::Protocol::Frame] frame # @api plugin def receive_frame(frame) @frames[frame.channel] ||= Array.new @frames[frame.channel] << frame if frameset_complete?(@frames[frame.channel]) receive_frameset(@frames[frame.channel]) # for channel.close, frame.channel will be nil. MK. clear_frames_on(frame.channel) if @frames[frame.channel] end end # Processes a frameset by finding and invoking a suitable handler. # Heartbeat frames are treated in a special way: they simply update @last_server_heartbeat # value. # # @param [Array] frames # @api plugin def receive_frameset(frames) frame = frames.first if Protocol::HeartbeatFrame === frame @last_server_heartbeat = Time.now else if callable = AMQ::Client::HandlersRegistry.find(frame.method_class) f = frames.shift callable.call(self, f, frames) else raise MissingHandlerError.new(frames.first) end end end # Clears frames that were received but not processed on given channel. Needs to be called # when the channel is closed. # @private def clear_frames_on(channel_id) raise ArgumentError, "channel id cannot be nil!" if channel_id.nil? @frames[channel_id].clear end # Sends a heartbeat frame if connection is open. # @api plugin def send_heartbeat if tcp_connection_established? && !@handling_skipped_hearbeats if @last_server_heartbeat < (Time.now - (self.heartbeat_interval * 2)) && !reconnecting? logger.error "[amqp] Detected missing server heartbeats" self.handle_skipped_hearbeats end send_frame(Protocol::HeartbeatFrame) end end # send_heartbeat # Handles connection.start. # # @api plugin # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.1.) def handle_start(connection_start) @server_properties = connection_start.server_properties @server_capabilities = @server_properties["capabilities"] @server_authentication_mechanisms = (connection_start.mechanisms || "").split(" ") @server_locales = Array(connection_start.locales) username = @settings[:user] || @settings[:username] password = @settings[:pass] || @settings[:password] # It's not clear whether we should transition to :opening state here # or in #open but in case authentication fails, it would be strange to have # @status undefined. So lets do this. MK. opening! self.send_frame(Protocol::Connection::StartOk.encode(@client_properties, @mechanism, self.encode_credentials(username, password), @locale)) end # Handles Connection.Tune-Ok. # # @api plugin # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.6) def handle_tune(tune_ok) @channel_max = tune_ok.channel_max.freeze @frame_max = tune_ok.frame_max.freeze @heartbeat_interval = self.heartbeat_interval || tune_ok.heartbeat self.send_frame(Protocol::Connection::TuneOk.encode(@channel_max, [settings[:frame_max], @frame_max].min, @heartbeat_interval)) end # handle_tune(method) # Handles Connection.Open-Ok. # # @api plugin # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.8.) def handle_open_ok(open_ok) @known_hosts = open_ok.known_hosts.dup.freeze opened! self.connection_successful if self.respond_to?(:connection_successful) end # Handles connection.close. When broker detects a connection level exception, this method is called. # # @api plugin # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.5.2.9) def handle_close(conn_close) closed! self.exec_callback_yielding_self(:error, conn_close) end # Handles Connection.Close-Ok. # # @api plugin # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.10) def handle_close_ok(close_ok) closed! self.disconnection_successful end # handle_close_ok(close_ok) protected # Returns next frame from buffer whenever possible # # @api private def get_next_frame return nil unless @chunk_buffer.size > 7 # otherwise, cannot read the length # octet + short offset = 3 # 1 + 2 # length payload_length = @chunk_buffer[offset, 4].unpack(AMQ::Protocol::PACK_UINT32).first # 4 bytes for long payload length, 1 byte final octet frame_length = offset + payload_length + 5 if frame_length <= @chunk_buffer.size @chunk_buffer.slice!(0, frame_length) else nil end end # def get_next_frame # Utility methods # Determines, whether the received frameset is ready to be further processed def frameset_complete?(frames) return false if frames.empty? first_frame = frames[0] first_frame.final? || (first_frame.method_class.has_content? && content_complete?(frames[1..-1])) end # Determines, whether given frame array contains full content body def content_complete?(frames) return false if frames.empty? header = frames[0] raise "Not a content header frame first: #{header.inspect}" unless header.kind_of?(AMQ::Protocol::HeaderFrame) header.body_size == frames[1..-1].inject(0) {|sum, frame| sum + frame.payload.size } end end # Adapter end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/callbacks.rb0000644000175000017500000000353111771004303021242 0ustar tfheentfheen# encoding: utf-8 module AMQ module Client module Async module Callbacks def redefine_callback(event, callable = nil, &block) f = (callable || block) # yes, re-assign! @callbacks[event] = [f] self end def define_callback(event, callable = nil, &block) f = (callable || block) @callbacks[event] ||= [] @callbacks[event] << f if f self end # define_callback(event, &block) alias append_callback define_callback def prepend_callback(event, &block) @callbacks[event] ||= [] @callbacks[event].unshift(block) self end # prepend_callback(event, &block) def clear_callbacks(event) @callbacks[event].clear if @callbacks[event] end # clear_callbacks(event) def exec_callback(name, *args, &block) list = Array(@callbacks[name]) if list.any? list.each { |c| c.call(*args, &block) } end end def exec_callback_once(name, *args, &block) list = (@callbacks.delete(name) || Array.new) if list.any? list.each { |c| c.call(*args, &block) } end end def exec_callback_yielding_self(name, *args, &block) list = Array(@callbacks[name]) if list.any? list.each { |c| c.call(self, *args, &block) } end end def exec_callback_once_yielding_self(name, *args, &block) list = (@callbacks.delete(name) || Array.new) if list.any? list.each { |c| c.call(self, *args, &block) } end end def has_callback?(name) @callbacks[name] && !@callbacks[name].empty? end # has_callback? end # Callbacks end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/consumer.rb0000644000175000017500000002027511771004303021162 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/callbacks" require "amq/client/consumer_tag_generator" module AMQ module Client module Async class Consumer # # Behaviours # include Async::Callbacks extend Async::ProtocolMethodHandlers # # API # attr_reader :channel attr_reader :queue attr_reader :consumer_tag attr_reader :arguments def self.tag_generator @tag_generator ||= AMQ::Client::ConsumerTagGenerator.new end # self.tag_generator def self.tag_generator=(generator) @tag_generator = generator end def initialize(channel, queue, consumer_tag = self.class.tag_generator.generate_for(queue), exclusive = false, no_ack = false, arguments = {}, no_local = false, &block) @callbacks = Hash.new @channel = channel || raise(ArgumentError, "channel is nil") @connection = channel.connection || raise(ArgumentError, "connection is nil") @queue = queue || raise(ArgumentError, "queue is nil") @consumer_tag = consumer_tag @exclusive = exclusive @no_ack = no_ack @arguments = arguments @no_local = no_local self.register_with_channel self.register_with_queue end # initialize def exclusive? !!@exclusive end # exclusive? def consume(nowait = false, &block) @connection.send_frame(Protocol::Basic::Consume.encode(@channel.id, @queue.name, @consumer_tag, @no_local, @no_ack, @exclusive, nowait, @arguments)) self.redefine_callback(:consume, &block) @channel.consumers_awaiting_consume_ok.push(self) self end # consume(nowait = false, &block) # Used by automatic recovery code. # @api plugin def resubscribe(&block) @connection.send_frame(Protocol::Basic::Consume.encode(@channel.id, @queue.name, @consumer_tag, @no_local, @no_ack, @exclusive, block.nil?, @arguments)) self.redefine_callback(:consume, &block) if block self end # resubscribe(&block) def cancel(nowait = false, &block) @connection.send_frame(Protocol::Basic::Cancel.encode(@channel.id, @consumer_tag, nowait)) self.clear_callbacks(:delivery) self.clear_callbacks(:consume) self.unregister_with_channel self.unregister_with_queue if !nowait self.redefine_callback(:cancel, &block) @channel.consumers_awaiting_cancel_ok.push(self) end self end # cancel(nowait = false, &block) def on_delivery(&block) self.append_callback(:delivery, &block) self end # on_delivery(&block) # @group Acknowledging & Rejecting Messages # Acknowledge a delivery tag. # @return [Consumer] self # # @api public # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.13.) def acknowledge(delivery_tag) @channel.acknowledge(delivery_tag) self end # acknowledge(delivery_tag) # # @return [Consumer] self # # @api public # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.8.3.14.) def reject(delivery_tag, requeue = true) @channel.reject(delivery_tag, requeue) self end # reject(delivery_tag, requeue = true) # @endgroup # @group Error Handling & Recovery # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure). # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_connection_interruption(&block) self.redefine_callback(:after_connection_interruption, &block) end # on_connection_interruption(&block) alias after_connection_interruption on_connection_interruption # @private def handle_connection_interruption(method = nil) self.exec_callback_yielding_self(:after_connection_interruption) end # handle_connection_interruption # Defines a callback that will be executed after TCP connection is recovered after a network failure # but before AMQP connection is re-opened. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def before_recovery(&block) self.redefine_callback(:before_recovery, &block) end # before_recovery(&block) # @private def run_before_recovery_callbacks self.exec_callback_yielding_self(:before_recovery) end # Defines a callback that will be executed when AMQP connection is recovered after a network failure.. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_recovery(&block) self.redefine_callback(:after_recovery, &block) end # on_recovery(&block) alias after_recovery on_recovery # @private def run_after_recovery_callbacks self.exec_callback_yielding_self(:after_recovery) end # Called by associated connection object when AMQP connection has been re-established # (for example, after a network failure). # # @api plugin def auto_recover self.exec_callback_yielding_self(:before_recovery) self.resubscribe self.exec_callback_yielding_self(:after_recovery) end # auto_recover # @endgroup # # Implementation # def handle_delivery(basic_deliver, metadata, payload) self.exec_callback(:delivery, basic_deliver, metadata, payload) end # handle_delivery(basic_deliver, metadata, payload) def handle_consume_ok(consume_ok) self.exec_callback_once(:consume, consume_ok) end # handle_consume_ok(consume_ok) def handle_cancel_ok(cancel_ok) @consumer_tag = nil # detach from object graph so that this object will be garbage-collected @queue = nil @channel = nil @connection = nil self.exec_callback_once(:cancel, cancel_ok) end # handle_cancel_ok(method) self.handle(Protocol::Basic::ConsumeOk) do |connection, frame| channel = connection.channels[frame.channel] consumer = channel.consumers_awaiting_consume_ok.shift consumer.handle_consume_ok(frame.decode_payload) end self.handle(Protocol::Basic::CancelOk) do |connection, frame| channel = connection.channels[frame.channel] consumer = channel.consumers_awaiting_cancel_ok.shift consumer.handle_cancel_ok(frame.decode_payload) end self.handle(Protocol::Basic::Deliver) do |connection, method_frame, content_frames| channel = connection.channels[method_frame.channel] basic_deliver = method_frame.decode_payload consumer = channel.consumers[basic_deliver.consumer_tag] metadata = content_frames.shift payload = content_frames.map { |frame| frame.payload }.join # Handle the delivery only if the consumer still exists. # The broker has been known to deliver a few messages after the consumer has been shut down. consumer.handle_delivery(basic_deliver, metadata, payload) if consumer end protected def register_with_channel @channel.consumers[@consumer_tag] = self end # register_with_channel def register_with_queue @queue.consumers[@consumer_tag] = self end # register_with_queue def unregister_with_channel @channel.consumers.delete(@consumer_tag) end # register_with_channel def unregister_with_queue @queue.consumers.delete(@consumer_tag) end # register_with_queue end # Consumer end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/extensions/0000755000175000017500000000000011771004303021173 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/async/extensions/rabbitmq/0000755000175000017500000000000011771004303022774 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/async/extensions/rabbitmq/confirm.rb0000644000175000017500000002303611771004303024762 0ustar tfheentfheen# encoding: utf-8 module AMQ module Client module Async module Extensions module RabbitMQ # h2. Purpose # In case that the broker crashes, some messages can get lost. # Thanks to this extension, broker sends Basic.Ack when the message # is processed by the broker. In case of persistent messages, it must # be written to disk or ack'd on all the queues it was delivered to. # However it doesn't have to be necessarily 1:1, because the broker # can send Basic.Ack with multi flag to acknowledge multiple messages. # # So it provides clients a lightweight way of keeping track of which # messages have been processed by the broker and which would need # re-publishing in case of broker shutdown or network failure. # # Transactions are solving the same problem, but they are very slow: # confirmations are more than 100 times faster. # # h2. Workflow # * Client asks broker to confirm messages on given channel (Confirm.Select). # * Broker sends back Confirm.Select-Ok, unless we sent Confirm.Select with nowait=true. # * After each published message, the client receives Basic.Ack from the broker. # * If something bad happens inside the broker, it sends Basic.Nack. # # h2. Gotchas # Note that we don't keep track of messages awaiting confirmation. # It'd add a huge overhead and it's impossible to come up with one-suits-all solution. # If you want to create such module, you'll probably want to redefine Channel#after_publish, # so it will put messages into a queue and then handlers for Basic.Ack and Basic.Nack. # This is the reason why we pass every argument from Exchange#publish to Channel#after_publish. # You should not forget though, that both of these methods can have multi flag! # # Transactional channel cannot be put into confirm mode and a confirm # mode channel cannot be made transactional. # # If the connection between the publisher and broker drops with outstanding # confirms, it does not necessarily mean that the messages were lost, so # republishing may result in duplicate messages. # h2. Learn more # @see http://www.rabbitmq.com/blog/2011/02/10/introducing-publisher-confirms # @see http://www.rabbitmq.com/amqp-0-9-1-quickref.html#class.confirm # @see http://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.ack module Confirm module ChannelMixin # Change publisher index. Publisher index is incremented # by 1 after each Basic.Publish starting at 1. This is done # on both client and server, hence this acknowledged messages # can be matched via its delivery-tag. # # @api private attr_writer :publisher_index # Publisher index is an index of the last message since # the confirmations were activated, started with 0. It's # incremented by 1 every time a message is published. # This is done on both client and server, hence this # acknowledged messages can be matched via its delivery-tag. # # @return [Integer] Current publisher index. # @api public def publisher_index @publisher_index ||= 0 end # Resets publisher index to 0 # # @api plugin def reset_publisher_index! @publisher_index = 0 end # This method is executed after publishing of each message via {Exchage#publish}. # Currently it just increments publisher index by 1, so messages # can be actually matched. # # @api plugin def increment_publisher_index! @publisher_index += 1 end # Turn on confirmations for this channel and, if given, # register callback for Confirm.Select-Ok. # # @raise [RuntimeError] Occurs when confirmations are already activated. # @raise [RuntimeError] Occurs when nowait is true and block is given. # # @param [Boolean] nowait Whether we expect Confirm.Select-Ok to be returned by the broker or not. # @yield [method] Callback which will be executed once we receive Confirm.Select-Ok. # @yieldparam [AMQ::Protocol::Confirm::SelectOk] method Protocol method class instance. # # @return [self] self. # # @see #confirm def confirm_select(nowait = false, &block) if nowait && block raise ArgumentError, "confirm.select with nowait = true and a callback makes no sense" end @uses_publisher_confirmations = true reset_publisher_index! self.redefine_callback(:confirm_select, &block) unless nowait self.redefine_callback(:after_publish) do increment_publisher_index! end @connection.send_frame(Protocol::Confirm::Select.encode(@id, nowait)) self end # @return [Boolean] def uses_publisher_confirmations? @uses_publisher_confirmations end # uses_publisher_confirmations? # Turn on confirmations for this channel and, if given, # register callback for basic.ack from the broker. # # @raise [RuntimeError] Occurs when confirmations are already activated. # @raise [RuntimeError] Occurs when nowait is true and block is given. # @param [Boolean] nowait Whether we expect Confirm.Select-Ok to be returned by the broker or not. # # @yield [basick_ack] Callback which will be executed every time we receive Basic.Ack from the broker. # @yieldparam [AMQ::Protocol::Basic::Ack] basick_ack Protocol method class instance. # # @return [self] self. def on_ack(nowait = false, &block) self.use_publisher_confirmations! unless self.uses_publisher_confirmations? self.define_callback(:ack, &block) if block self end # Register error callback for Basic.Nack. It's called # when message(s) is rejected. # # @return [self] self def on_nack(&block) self.define_callback(:nack, &block) if block self end # Handler for Confirm.Select-Ok. By default, it just # executes hook specified via the #confirmations method # with a single argument, a protocol method class # instance (an instance of AMQ::Protocol::Confirm::SelectOk) # and then it deletes the callback, since Confirm.Select # is supposed to be sent just once. # # @api plugin def handle_select_ok(method) self.exec_callback_once(:confirm_select, method) end # Handler for Basic.Ack. By default, it just # executes hook specified via the #confirm method # with a single argument, a protocol method class # instance (an instance of AMQ::Protocol::Basic::Ack). # # @api plugin def handle_basic_ack(method) self.exec_callback(:ack, method) end # Handler for Basic.Nack. By default, it just # executes hook specified via the #confirm_failed method # with a single argument, a protocol method class # instance (an instance of AMQ::Protocol::Basic::Nack). # # @api plugin def handle_basic_nack(method) self.exec_callback(:nack, method) end def reset_state! super @uses_publisher_confirmations = false end def self.included(host) host.handle(Protocol::Confirm::SelectOk) do |connection, frame| method = frame.decode_payload channel = connection.channels[frame.channel] channel.handle_select_ok(method) end host.handle(Protocol::Basic::Ack) do |connection, frame| method = frame.decode_payload channel = connection.channels[frame.channel] channel.handle_basic_ack(method) end host.handle(Protocol::Basic::Nack) do |connection, frame| method = frame.decode_payload channel = connection.channels[frame.channel] channel.handle_basic_nack(method) end end # self.included(host) end # ChannelMixin end # Confirm end # RabbitMQ end # Extensions class Channel # use modules, a native Ruby way of extension of existing classes, # instead of reckless monkey-patching. MK. include Extensions::RabbitMQ::Confirm::ChannelMixin end # Channel end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/extensions/rabbitmq/basic.rb0000644000175000017500000000213111771004303024377 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/channel" # Basic.Nack module AMQ module Client module Async module Extensions module RabbitMQ module Basic module ChannelMixin # Overrides {AMQ::Client::Channel#reject} behavior to use basic.nack. # # @api public # @see http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack def reject(delivery_tag, requeue = true, multi = false) if multi @connection.send_frame(Protocol::Basic::Nack.encode(self.id, delivery_tag, multi, requeue)) else super(delivery_tag, requeue) end end # reject end # ChannelMixin end # Basic end # RabbitMQ end # Extensions class Channel # use modules, the native Ruby way of extension of existing classes, # instead of reckless monkey-patching. MK. include Extensions::RabbitMQ::Basic::ChannelMixin end # Channel end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/entity.rb0000644000175000017500000000322211771004303020634 0ustar tfheentfheen# encoding: utf-8 require "amq/client/openable" require "amq/client/async/callbacks" module AMQ module Client module Async module RegisterEntityMixin # @example Registering Channel implementation # Adapter.register_entity(:channel, Channel) # # ... so then I can do: # channel = client.channel(1) # # instead of: # channel = Channel.new(client, 1) def register_entity(name, klass) define_method(name) do |*args, &block| klass.new(self, *args, &block) end # define_method end # register_entity end # RegisterEntityMixin module ProtocolMethodHandlers def handle(klass, &block) AMQ::Client::HandlersRegistry.register(klass, &block) end def handlers AMQ::Client::HandlersRegistry.handlers end end # ProtocolMethodHandlers # AMQ entities, as implemented by AMQ::Client, have callbacks and can run them # when necessary. # # @note Exchanges and queues implementation is based on this class. # # @abstract module Entity # # Behaviors # include Openable include Async::Callbacks # # API # # @return [Array<#call>] attr_reader :callbacks def initialize(connection) @connection = connection # Be careful with default values for #ruby hashes: h = Hash.new(Array.new); h[:key] ||= 1 # won't assign anything to :key. MK. @callbacks = Hash.new end # initialize end # Entity end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/channel.rb0000644000175000017500000003662311771004303020743 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/entity" require "amq/client/queue" require "amq/client/exchange" module AMQ module Client module Async class Channel # # Behaviours # extend RegisterEntityMixin include Entity extend ProtocolMethodHandlers register_entity :queue, AMQ::Client::Queue register_entity :exchange, AMQ::Client::Exchange # # API # DEFAULT_REPLY_TEXT = "Goodbye".freeze attr_reader :id attr_reader :exchanges_awaiting_declare_ok, :exchanges_awaiting_delete_ok attr_reader :queues_awaiting_declare_ok, :queues_awaiting_delete_ok, :queues_awaiting_bind_ok, :queues_awaiting_unbind_ok, :queues_awaiting_purge_ok, :queues_awaiting_get_response attr_reader :consumers_awaiting_consume_ok, :consumers_awaiting_cancel_ok attr_accessor :flow_is_active def initialize(connection, id, options = {}) super(connection) @id = id @exchanges = Hash.new @queues = Hash.new @consumers = Hash.new @options = { :auto_recovery => connection.auto_recovering? }.merge(options) @auto_recovery = (!!@options[:auto_recovery]) # we must synchronize frameset delivery. MK. @mutex = Mutex.new reset_state! # 65536 is here for cases when channel is opened without passing a callback in, # otherwise channel_mix would be nil and it causes a lot of needless headaches. # lets just have this default. MK. channel_max = if @connection.open? @connection.channel_max || 65536 else 65536 end if channel_max != 0 && !(0..channel_max).include?(id) raise ArgumentError.new("Max channel for the connection is #{channel_max}, given: #{id}") end end # @return [Boolean] true if this channel uses automatic recovery mode def auto_recovering? @auto_recovery end # auto_recovering? # @return [Hash] def consumers @consumers end # consumers # @return [Array] Collection of queues that were declared on this channel. def queues @queues.values end # @return [Array] Collection of exchanges that were declared on this channel. def exchanges @exchanges.values end # AMQP connection this channel belongs to. # # @return [AMQ::Client::Connection] Connection this channel belongs to. def connection @connection end # connection # Synchronizes given block using this channel's mutex. # @api public def synchronize(&block) @mutex.synchronize(&block) end # @group Channel lifecycle # Opens AMQP channel. # # @api public def open(&block) @connection.send_frame(Protocol::Channel::Open.encode(@id, AMQ::Protocol::EMPTY_STRING)) @connection.channels[@id] = self self.status = :opening self.redefine_callback :open, &block end alias reopen open # Closes AMQP channel. # # @api public def close(reply_code = 200, reply_text = DEFAULT_REPLY_TEXT, class_id = 0, method_id = 0, &block) @connection.send_frame(Protocol::Channel::Close.encode(@id, reply_code, reply_text, class_id, method_id)) self.redefine_callback :close, &block end # @endgroup # @group Message acknowledgements # Acknowledge one or all messages on the channel. # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.13.) def acknowledge(delivery_tag, multiple = false) @connection.send_frame(Protocol::Basic::Ack.encode(self.id, delivery_tag, multiple)) self end # acknowledge(delivery_tag, multiple = false) # Reject a message with given delivery tag. # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.14.) def reject(delivery_tag, requeue = true) @connection.send_frame(Protocol::Basic::Reject.encode(self.id, delivery_tag, requeue)) self end # reject(delivery_tag, requeue = true) # Notifies AMQ broker that consumer has recovered and unacknowledged messages need # to be redelivered. # # @return [Channel] self # # @note RabbitMQ as of 2.3.1 does not support basic.recover with requeue = false. # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.16.) # @api public def recover(requeue = true, &block) @connection.send_frame(Protocol::Basic::Recover.encode(@id, requeue)) self.redefine_callback :recover, &block self end # recover(requeue = false, &block) # @endgroup # @group QoS and flow handling # Requests a specific quality of service. The QoS can be specified for the current channel # or for all channels on the connection. # # @note RabbitMQ as of 2.3.1 does not support prefetch_size. # @api public def qos(prefetch_size = 0, prefetch_count = 32, global = false, &block) @connection.send_frame(Protocol::Basic::Qos.encode(@id, prefetch_size, prefetch_count, global)) self.redefine_callback :qos, &block self end # qos(prefetch_size = 4096, prefetch_count = 32, global = false, &block) # Asks the peer to pause or restart the flow of content data sent to a consumer. # This is a simple flow­control mechanism that a peer can use to avoid overflowing its # queues or otherwise finding itself receiving more messages than it can process. Note that # this method is not intended for window control. It does not affect contents returned to # Queue#get callers. # # @param [Boolean] active Desired flow state. # # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.5.2.3.) # @api public def flow(active = false, &block) @connection.send_frame(Protocol::Channel::Flow.encode(@id, active)) self.redefine_callback :flow, &block self end # flow(active = false, &block) # @return [Boolean] True if flow in this channel is active (messages will be delivered to consumers that use this channel). # # @api public def flow_is_active? @flow_is_active end # flow_is_active? # @endgroup # @group Transactions # Sets the channel to use standard transactions. One must use this method at least # once on a channel before using #tx_tommit or tx_rollback methods. # # @api public def tx_select(&block) @connection.send_frame(Protocol::Tx::Select.encode(@id)) self.redefine_callback :tx_select, &block self end # tx_select(&block) # Commits AMQP transaction. # # @api public def tx_commit(&block) @connection.send_frame(Protocol::Tx::Commit.encode(@id)) self.redefine_callback :tx_commit, &block self end # tx_commit(&block) # Rolls AMQP transaction back. # # @api public def tx_rollback(&block) @connection.send_frame(Protocol::Tx::Rollback.encode(@id)) self.redefine_callback :tx_rollback, &block self end # tx_rollback(&block) # @endgroup # @group Error handling # Defines a callback that will be executed when channel is closed after # channel-level exception. # # @api public def on_error(&block) self.define_callback(:error, &block) end # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure). # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_connection_interruption(&block) self.redefine_callback(:after_connection_interruption, &block) end # on_connection_interruption(&block) alias after_connection_interruption on_connection_interruption # @private def handle_connection_interruption(method = nil) @queues.each { |name, q| q.handle_connection_interruption(method) } @exchanges.each { |name, e| e.handle_connection_interruption(method) } self.exec_callback_yielding_self(:after_connection_interruption) self.reset_state! end # handle_connection_interruption # Defines a callback that will be executed after TCP connection has recovered after a network failure # but before AMQP connection is re-opened. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def before_recovery(&block) self.redefine_callback(:before_recovery, &block) end # before_recovery(&block) # @private def run_before_recovery_callbacks self.exec_callback_yielding_self(:before_recovery) @queues.each { |name, q| q.run_before_recovery_callbacks } @exchanges.each { |name, e| e.run_before_recovery_callbacks } end # Defines a callback that will be executed after AMQP connection has recovered after a network failure. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_recovery(&block) self.redefine_callback(:after_recovery, &block) end # on_recovery(&block) alias after_recovery on_recovery # @private def run_after_recovery_callbacks self.exec_callback_yielding_self(:after_recovery) @queues.each { |name, q| q.run_after_recovery_callbacks } @exchanges.each { |name, e| e.run_after_recovery_callbacks } end # Called by associated connection object when AMQP connection has been re-established # (for example, after a network failure). # # @api plugin def auto_recover return unless auto_recovering? self.open do # exchanges must be recovered first because queue recovery includes recovery of bindings. MK. @exchanges.each { |name, e| e.auto_recover } @queues.each { |name, q| q.auto_recover } end end # auto_recover # @endgroup # # Implementation # def register_exchange(exchange) raise ArgumentError, "argument is nil!" if exchange.nil? @exchanges[exchange.name] = exchange end # register_exchange(exchange) # Finds exchange in the exchanges cache on this channel by name. Exchange only exists in the cache if # it was previously instantiated on this channel. # # @param [String] name Exchange name # @return [AMQ::Client::Exchange] Exchange (if found) # @api plugin def find_exchange(name) @exchanges[name] end # @api plugin # @private def register_queue(queue) raise ArgumentError, "argument is nil!" if queue.nil? @queues[queue.name] = queue end # register_queue(queue) # @api plugin # @private def find_queue(name) @queues[name] end RECOVERY_EVENTS = [:after_connection_interruption, :before_recovery, :after_recovery].freeze # @api plugin # @private def reset_state! @flow_is_active = true @queues_awaiting_declare_ok = Array.new @exchanges_awaiting_declare_ok = Array.new @queues_awaiting_delete_ok = Array.new @exchanges_awaiting_delete_ok = Array.new @queues_awaiting_purge_ok = Array.new @queues_awaiting_bind_ok = Array.new @queues_awaiting_unbind_ok = Array.new @consumers_awaiting_consume_ok = Array.new @consumers_awaiting_cancel_ok = Array.new @queues_awaiting_get_response = Array.new @callbacks = @callbacks.delete_if { |k, v| !RECOVERY_EVENTS.include?(k) } end # reset_state! # @api plugin # @private def handle_open_ok(open_ok) self.status = :opened self.exec_callback_once_yielding_self(:open, open_ok) end # @api plugin # @private def handle_close_ok(close_ok) self.status = :closed self.connection.clear_frames_on(self.id) self.exec_callback_once_yielding_self(:close, close_ok) end # @api plugin # @private def handle_close(channel_close) self.status = :closed self.connection.clear_frames_on(self.id) self.exec_callback_yielding_self(:error, channel_close) self.handle_connection_interruption(channel_close) end self.handle(Protocol::Channel::OpenOk) do |connection, frame| channel = connection.channels[frame.channel] channel.handle_open_ok(frame.decode_payload) end self.handle(Protocol::Channel::CloseOk) do |connection, frame| method = frame.decode_payload channels = connection.channels channel = channels[frame.channel] channels.delete(channel) channel.handle_close_ok(method) end self.handle(Protocol::Channel::Close) do |connection, frame| method = frame.decode_payload channels = connection.channels channel = channels[frame.channel] connection.send_frame(Protocol::Channel::CloseOk.encode(frame.channel)) channel.handle_close(method) end self.handle(Protocol::Basic::QosOk) do |connection, frame| channel = connection.channels[frame.channel] channel.exec_callback(:qos, frame.decode_payload) end self.handle(Protocol::Basic::RecoverOk) do |connection, frame| channel = connection.channels[frame.channel] channel.exec_callback(:recover, frame.decode_payload) end self.handle(Protocol::Channel::FlowOk) do |connection, frame| channel = connection.channels[frame.channel] method = frame.decode_payload channel.flow_is_active = method.active channel.exec_callback(:flow, method) end self.handle(Protocol::Tx::SelectOk) do |connection, frame| channel = connection.channels[frame.channel] channel.exec_callback(:tx_select, frame.decode_payload) end self.handle(Protocol::Tx::CommitOk) do |connection, frame| channel = connection.channels[frame.channel] channel.exec_callback(:tx_commit, frame.decode_payload) end self.handle(Protocol::Tx::RollbackOk) do |connection, frame| channel = connection.channels[frame.channel] channel.exec_callback(:tx_rollback, frame.decode_payload) end end # Channel end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/exchange.rb0000644000175000017500000002057311771004303021112 0ustar tfheentfheen# encoding: utf-8 require "amq/client/exceptions" require "amq/client/entity" require "amq/client/server_named_entity" module AMQ module Client module Async class Exchange include Entity include ServerNamedEntity extend ProtocolMethodHandlers BUILTIN_TYPES = [:fanout, :direct, :topic, :headers].freeze # # API # # Channel this exchange belongs to. attr_reader :channel # Exchange name. May be server-generated or assigned directly. # @return [String] attr_reader :name # @return [Symbol] One of :direct, :fanout, :topic, :headers attr_reader :type # @return [Hash] Additional arguments given on queue declaration. Typically used by AMQP extensions. attr_reader :arguments def initialize(connection, channel, name, type = :fanout) if !(BUILTIN_TYPES.include?(type.to_sym) || type.to_s =~ /^x-.+/i) raise UnknownExchangeTypeError.new(BUILTIN_TYPES, type) end @connection = connection @channel = channel @name = name @type = type # register pre-declared exchanges if @name == AMQ::Protocol::EMPTY_STRING || @name =~ /^amq\.(direct|fanout|topic|match|headers)/ @channel.register_exchange(self) end super(connection) end # @return [Boolean] true if this exchange is of type `fanout` # @api public def fanout? @type == :fanout end # @return [Boolean] true if this exchange is of type `direct` # @api public def direct? @type == :direct end # @return [Boolean] true if this exchange is of type `topic` # @api public def topic? @type == :topic end # @return [Boolean] true if this exchange is of type `headers` # @api public def headers? @type == :headers end # @return [Boolean] true if this exchange is of a custom type (begins with x-) # @api public def custom_type? @type.to_s =~ /^x-.+/i end # custom_type? # @return [Boolean] true if this exchange is a pre-defined one (amq.direct, amq.fanout, amq.match and so on) def predefined? @name && ((@name == AMQ::Protocol::EMPTY_STRING) || !!(@name =~ /^amq\.(direct|fanout|topic|headers|match)/i)) end # predefined? # @group Declaration # @api public def declare(passive = false, durable = false, auto_delete = false, nowait = false, arguments = nil, &block) # for re-declaration @passive = passive @durable = durable @auto_delete = auto_delete @arguments = arguments @connection.send_frame(Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, passive, durable, auto_delete, false, nowait, arguments)) unless nowait self.define_callback(:declare, &block) @channel.exchanges_awaiting_declare_ok.push(self) end self end # @api public def redeclare(&block) nowait = block.nil? @connection.send_frame(Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, @passive, @durable, @auto_delete, false, nowait, @arguments)) unless nowait self.define_callback(:declare, &block) @channel.exchanges_awaiting_declare_ok.push(self) end self end # redeclare(&block) # @endgroup # @api public def delete(if_unused = false, nowait = false, &block) @connection.send_frame(Protocol::Exchange::Delete.encode(@channel.id, @name, if_unused, nowait)) unless nowait self.define_callback(:delete, &block) # TODO: delete itself from exchanges cache @channel.exchanges_awaiting_delete_ok.push(self) end self end # delete(if_unused = false, nowait = false) # @group Publishing Messages # @api public def publish(payload, routing_key = AMQ::Protocol::EMPTY_STRING, user_headers = {}, mandatory = false, immediate = false, frame_size = nil) headers = { :priority => 0, :delivery_mode => 2, :content_type => "application/octet-stream" }.merge(user_headers) @connection.send_frameset(Protocol::Basic::Publish.encode(@channel.id, payload, headers, @name, routing_key, mandatory, immediate, (frame_size || @connection.frame_max)), @channel) # publisher confirms support. MK. @channel.exec_callback(:after_publish) self end # @api public def on_return(&block) self.redefine_callback(:return, &block) self end # on_return(&block) # @endgroup # @group Error Handling and Recovery # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure). # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_connection_interruption(&block) self.redefine_callback(:after_connection_interruption, &block) end # on_connection_interruption(&block) alias after_connection_interruption on_connection_interruption # @private def handle_connection_interruption(method = nil) self.exec_callback_yielding_self(:after_connection_interruption) end # handle_connection_interruption # Defines a callback that will be executed after TCP connection is recovered after a network failure # but before AMQP connection is re-opened. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def before_recovery(&block) self.redefine_callback(:before_recovery, &block) end # before_recovery(&block) # @private def run_before_recovery_callbacks self.exec_callback_yielding_self(:before_recovery) end # Defines a callback that will be executed when AMQP connection is recovered after a network failure.. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_recovery(&block) self.redefine_callback(:after_recovery, &block) end # on_recovery(&block) alias after_recovery on_recovery # @private def run_after_recovery_callbacks self.exec_callback_yielding_self(:after_recovery) end # Called by associated connection object when AMQP connection has been re-established # (for example, after a network failure). # # @api plugin def auto_recover self.redeclare unless predefined? end # auto_recover # @endgroup # # Implementation # def handle_declare_ok(method) @name = method.exchange if self.anonymous? @channel.register_exchange(self) self.exec_callback_once_yielding_self(:declare, method) end def handle_delete_ok(method) self.exec_callback_once(:delete, method) end # handle_delete_ok(method) self.handle(Protocol::Exchange::DeclareOk) do |connection, frame| method = frame.decode_payload channel = connection.channels[frame.channel] exchange = channel.exchanges_awaiting_declare_ok.shift exchange.handle_declare_ok(method) end # handle self.handle(Protocol::Exchange::DeleteOk) do |connection, frame| channel = connection.channels[frame.channel] exchange = channel.exchanges_awaiting_delete_ok.shift exchange.handle_delete_ok(frame.decode_payload) end # handle self.handle(Protocol::Basic::Return) do |connection, frame, content_frames| channel = connection.channels[frame.channel] method = frame.decode_payload exchange = channel.find_exchange(method.exchange) header = content_frames.shift body = content_frames.map { |frame| frame.payload }.join exchange.exec_callback(:return, method, header, body) end end # Exchange end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/async/queue.rb0000644000175000017500000004405111771004303020451 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/entity" require "amq/client/adapter" require "amq/client/server_named_entity" require "amq/protocol/get_response" require "amq/client/async/consumer" module AMQ module Client module Async class Queue # # Behaviours # include Entity include ServerNamedEntity extend ProtocolMethodHandlers # # API # # Qeueue name. May be server-generated or assigned directly. # @return [String] attr_reader :name # Channel this queue belongs to. # @return [AMQ::Client::Channel] attr_reader :channel # @return [Array] All consumers on this queue. attr_reader :consumers # @return [AMQ::Client::Consumer] Default consumer (registered with {Queue#consume}). attr_reader :default_consumer # @return [Hash] Additional arguments given on queue declaration. Typically used by AMQP extensions. attr_reader :arguments # @return [Array] attr_reader :bindings # @param [AMQ::Client::Adapter] AMQ networking adapter to use. # @param [AMQ::Client::Channel] AMQ channel this queue object uses. # @param [String] Queue name. Please note that AMQP spec does not require brokers to support Unicode for queue names. # @api public def initialize(connection, channel, name = AMQ::Protocol::EMPTY_STRING) raise ArgumentError.new("queue name must not be nil; if you want broker to generate queue name for you, pass an empty string") if name.nil? super(connection) @name = name # this has to stay true even after queue.declare-ok arrives. MK. @server_named = @name.empty? if @server_named self.on_connection_interruption do # server-named queue need to get new names after recovery. MK. @name = AMQ::Protocol::EMPTY_STRING end end @channel = channel # primarily for autorecovery. MK. @bindings = Array.new @consumers = Hash.new end # @return [Boolean] true if this queue was declared as durable (will survive broker restart). # @api public def durable? @durable end # durable? # @return [Boolean] true if this queue was declared as exclusive (limited to just one consumer) # @api public def exclusive? @exclusive end # exclusive? # @return [Boolean] true if this queue was declared as automatically deleted (deleted as soon as last consumer unbinds). # @api public def auto_delete? @auto_delete end # auto_delete? # @group Declaration # Declares this queue. # # # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.1.) def declare(passive = false, durable = false, exclusive = false, auto_delete = false, nowait = false, arguments = nil, &block) raise ArgumentError, "declaration with nowait does not make sense for server-named queues! Either specify name other than empty string or use #declare without nowait" if nowait && self.anonymous? # these two are for autorecovery. MK. @passive = passive @server_named = @name.empty? @durable = durable @exclusive = exclusive @auto_delete = auto_delete @arguments = arguments nowait = true if !block && !@name.empty? @connection.send_frame(Protocol::Queue::Declare.encode(@channel.id, @name, passive, durable, exclusive, auto_delete, nowait, arguments)) if !nowait self.append_callback(:declare, &block) @channel.queues_awaiting_declare_ok.push(self) end self end # Re-declares queue with the same attributes # @api public def redeclare(&block) nowait = true if !block && !@name.empty? # server-named queues get their new generated names. new_name = if @server_named AMQ::Protocol::EMPTY_STRING else @name end @connection.send_frame(Protocol::Queue::Declare.encode(@channel.id, new_name, @passive, @durable, @exclusive, @auto_delete, false, @arguments)) if !nowait self.append_callback(:declare, &block) @channel.queues_awaiting_declare_ok.push(self) end self end # @endgroup # Deletes this queue. # # @param [Boolean] if_unused delete only if queue has no consumers (subscribers). # @param [Boolean] if_empty delete only if queue has no messages in it. # @param [Boolean] nowait Don't wait for reply from broker. # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.9.) def delete(if_unused = false, if_empty = false, nowait = false, &block) nowait = true unless block @connection.send_frame(Protocol::Queue::Delete.encode(@channel.id, @name, if_unused, if_empty, nowait)) if !nowait self.append_callback(:delete, &block) # TODO: delete itself from queues cache @channel.queues_awaiting_delete_ok.push(self) end self end # delete(channel, queue, if_unused, if_empty, nowait, &block) # @group Binding # # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.3.) def bind(exchange, routing_key = AMQ::Protocol::EMPTY_STRING, nowait = false, arguments = nil, &block) nowait = true unless block exchange_name = if exchange.respond_to?(:name) exchange.name else exchange end @connection.send_frame(Protocol::Queue::Bind.encode(@channel.id, @name, exchange_name, routing_key, nowait, arguments)) if !nowait self.append_callback(:bind, &block) @channel.queues_awaiting_bind_ok.push(self) end # store bindings for automatic recovery, but BE VERY CAREFUL to # not cause an infinite rebinding loop here when we recover. MK. binding = { :exchange => exchange_name, :routing_key => routing_key, :arguments => arguments } @bindings.push(binding) unless @bindings.include?(binding) self end # # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.5.) def unbind(exchange, routing_key = AMQ::Protocol::EMPTY_STRING, arguments = nil, &block) exchange_name = if exchange.respond_to?(:name) exchange.name else exchange end @connection.send_frame(Protocol::Queue::Unbind.encode(@channel.id, @name, exchange_name, routing_key, arguments)) self.append_callback(:unbind, &block) @channel.queues_awaiting_unbind_ok.push(self) @bindings.delete_if { |b| b[:exchange] == exchange_name } self end # Used by automatic recovery machinery. # @private # @api plugin def rebind(&block) @bindings.each { |b| self.bind(b[:exchange], b[:routing_key], true, b[:arguments]) } end # @endgroup # @group Consuming messages # @return [Class] AMQ::Client::Consumer or other class implementing consumer API. Used by libraries like {https://github.com/ruby-amqp/amqp Ruby amqp gem}. # @api plugin def self.consumer_class AMQ::Client::Async::Consumer end # self.consumer_class # # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.3.) def consume(no_ack = false, exclusive = false, nowait = false, no_local = false, arguments = nil, &block) raise RuntimeError.new("This queue already has default consumer. Please instantiate AMQ::Client::Consumer directly to register additional consumers.") if @default_consumer nowait = true unless block @default_consumer = self.class.consumer_class.new(@channel, self, generate_consumer_tag(@name), exclusive, no_ack, arguments, no_local, &block) @default_consumer.consume(nowait, &block) self end # Unsubscribes from message delivery. # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.5.) def cancel(nowait = false, &block) raise "There is no default consumer for this queue. This usually means that you are trying to unsubscribe a queue that never was subscribed for messages in the first place." if @default_consumer.nil? @default_consumer.cancel(nowait, &block) self end # cancel(&block) # @endgroup # @group Working With Messages # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Sections 1.8.3.9) def on_delivery(&block) @default_consumer.on_delivery(&block) end # on_delivery(&block) # Fetches messages from the queue. # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.10.) def get(no_ack = false, &block) @connection.send_frame(Protocol::Basic::Get.encode(@channel.id, @name, no_ack)) # most people only want one callback per #get call. Consider the following example: # # 100.times { queue.get { ... } } # # most likely you won't expect 100 callback runs per message here. MK. self.redefine_callback(:get, &block) @channel.queues_awaiting_get_response.push(self) self end # get(no_ack = false, &block) # Purges (removes all messagse from) the queue. # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.7.2.7.) def purge(nowait = false, &block) nowait = true unless block @connection.send_frame(Protocol::Queue::Purge.encode(@channel.id, @name, nowait)) if !nowait self.redefine_callback(:purge, &block) # TODO: handle channel & connection-level exceptions @channel.queues_awaiting_purge_ok.push(self) end self end # purge(nowait = false, &block) # @endgroup # @group Acknowledging & Rejecting Messages # Acknowledge a delivery tag. # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.13.) def acknowledge(delivery_tag) @channel.acknowledge(delivery_tag) self end # acknowledge(delivery_tag) # # @return [Queue] self # # @api public # @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.8.3.14.) def reject(delivery_tag, requeue = true) @channel.reject(delivery_tag, requeue) self end # reject(delivery_tag, requeue = true) # @endgroup # @group Error Handling & Recovery # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure). # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_connection_interruption(&block) self.redefine_callback(:after_connection_interruption, &block) end # on_connection_interruption(&block) alias after_connection_interruption on_connection_interruption # @private def handle_connection_interruption(method = nil) @consumers.each { |tag, consumer| consumer.handle_connection_interruption(method) } self.exec_callback_yielding_self(:after_connection_interruption) end # handle_connection_interruption # Defines a callback that will be executed after TCP connection is recovered after a network failure # but before AMQP connection is re-opened. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def before_recovery(&block) self.redefine_callback(:before_recovery, &block) end # before_recovery(&block) # @private def run_before_recovery_callbacks self.exec_callback_yielding_self(:before_recovery) @consumers.each { |tag, c| c.run_before_recovery_callbacks } end # Defines a callback that will be executed when AMQP connection is recovered after a network failure.. # Only one callback can be defined (the one defined last replaces previously added ones). # # @api public def on_recovery(&block) self.redefine_callback(:after_recovery, &block) end # on_recovery(&block) alias after_recovery on_recovery # @private def run_after_recovery_callbacks self.exec_callback_yielding_self(:after_recovery) @consumers.each { |tag, c| c.run_after_recovery_callbacks } end # Called by associated connection object when AMQP connection has been re-established # (for example, after a network failure). # # @api plugin def auto_recover self.exec_callback_yielding_self(:before_recovery) self.redeclare do self.rebind @consumers.each { |tag, consumer| consumer.auto_recover } self.exec_callback_yielding_self(:after_recovery) end end # auto_recover # @endgroup # # Implementation # # Unique string supposed to be used as a consumer tag. # # @return [String] Unique string. # @api plugin def generate_consumer_tag(name) "#{name}-#{Time.now.to_i * 1000}-#{Kernel.rand(999_999_999_999)}" end def handle_connection_interruption(method = nil) @consumers.each { |tag, c| c.handle_connection_interruption(method) } end # handle_connection_interruption(method = nil) def handle_declare_ok(method) @name = method.queue if @name.empty? @channel.register_queue(self) self.exec_callback_once_yielding_self(:declare, method) end def handle_delete_ok(method) self.exec_callback_once(:delete, method) end # handle_delete_ok(method) def handle_purge_ok(method) self.exec_callback_once(:purge, method) end # handle_purge_ok(method) def handle_bind_ok(method) self.exec_callback_once(:bind, method) end # handle_bind_ok(method) def handle_unbind_ok(method) self.exec_callback_once(:unbind, method) end # handle_unbind_ok(method) def handle_get_ok(method, header, payload) method = Protocol::GetResponse.new(method) self.exec_callback(:get, method, header, payload) end # handle_get_ok(method, header, payload) def handle_get_empty(method) method = Protocol::GetResponse.new(method) self.exec_callback(:get, method) end # handle_get_empty(method) # Get the first queue which didn't receive Queue.Declare-Ok yet and run its declare callback. # The cache includes only queues with {nowait: false}. self.handle(Protocol::Queue::DeclareOk) do |connection, frame| method = frame.decode_payload channel = connection.channels[frame.channel] queue = channel.queues_awaiting_declare_ok.shift queue.handle_declare_ok(method) end self.handle(Protocol::Queue::DeleteOk) do |connection, frame| channel = connection.channels[frame.channel] queue = channel.queues_awaiting_delete_ok.shift queue.handle_delete_ok(frame.decode_payload) end self.handle(Protocol::Queue::BindOk) do |connection, frame| channel = connection.channels[frame.channel] queue = channel.queues_awaiting_bind_ok.shift queue.handle_bind_ok(frame.decode_payload) end self.handle(Protocol::Queue::UnbindOk) do |connection, frame| channel = connection.channels[frame.channel] queue = channel.queues_awaiting_unbind_ok.shift queue.handle_unbind_ok(frame.decode_payload) end self.handle(Protocol::Queue::PurgeOk) do |connection, frame| channel = connection.channels[frame.channel] queue = channel.queues_awaiting_purge_ok.shift queue.handle_purge_ok(frame.decode_payload) end self.handle(Protocol::Basic::GetOk) do |connection, frame, content_frames| channel = connection.channels[frame.channel] queue = channel.queues_awaiting_get_response.shift method = frame.decode_payload header = content_frames.shift body = content_frames.map {|frame| frame.payload }.join queue.handle_get_ok(method, header, body) if queue end self.handle(Protocol::Basic::GetEmpty) do |connection, frame| channel = connection.channels[frame.channel] queue = channel.queues_awaiting_get_response.shift queue.handle_get_empty(frame.decode_payload) end end # Queue end # Async end # Client end # AMQ amq-client-0.9.3/lib/amq/client/adapters/0000755000175000017500000000000011771004303017462 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/adapters/coolio.rb0000644000175000017500000000030711771004303021273 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/adapters/coolio" module AMQ module Client # backwards compatibility # @private CoolioClient = Async::CoolioClient end # Client end # AMQ amq-client-0.9.3/lib/amq/client/adapters/event_machine.rb0000644000175000017500000000033111771004303022611 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/adapters/eventmachine" module AMQ module Client # backwards compatibility # @private EventMachineClient = Async::EventMachineClient end # Client end # AMQ amq-client-0.9.3/lib/amq/client/adapter.rb0000644000175000017500000000064311771004303017627 0ustar tfheentfheen# encoding: utf-8 require "amq/client/logging" require "amq/client/settings" require "amq/client/async/queue" require "amq/client/async/exchange" require "amq/client/async/channel" require "amq/client/async/adapter" module AMQ # For overview of AMQP client adapters API, see {AMQ::Client::Adapter} module Client # backwards compatibility # @private Adapter = Async::Adapter end # Client end # AMQ amq-client-0.9.3/lib/amq/client/callbacks.rb0000644000175000017500000000027411771004303020126 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/callbacks" module AMQ module Client # backwards compatibility # @private Callbacks = Async::Callbacks end # Client end # AMQ amq-client-0.9.3/lib/amq/client/exceptions.rb0000644000175000017500000000654611771004303020400 0ustar tfheentfheen# encoding: utf-8 module AMQ module Client # # Adapters # class TCPConnectionFailed < StandardError # # API # attr_reader :settings def initialize(settings) @settings = settings super("Could not estabilish TCP connection to #{@settings[:host]}:#{@settings[:port]}") end end # Base exception class for data consistency and framing errors. class InconsistentDataError < StandardError end # Raised by adapters when frame does not end with {final octet AMQ::Protocol::Frame::FINAL_OCTET}. # This suggest that there is a bug in adapter or AMQ broker implementation. # # @see http://bit.ly/amqp091spec AMQP 0.9.1 specification (Section 2.3) class NoFinalOctetError < InconsistentDataError def initialize super("Frame doesn't end with #{AMQ::Protocol::Frame::FINAL_OCTET} as it must, which means the size is miscalculated.") end end # Raised by adapters when actual frame payload size in bytes is not equal # to the size specified in that frame's header. # This suggest that there is a bug in adapter or AMQ broker implementation. # # @see http://bit.ly/amqp091spec AMQP 0.9.1 specification (Section 2.3) class BadLengthError < InconsistentDataError def initialize(expected_length, actual_length) super("Frame payload should be #{expected_length} long, but it's #{actual_length} long.") end end # # Client # class MissingHandlerError < StandardError def initialize(frame) super("No callback registered for #{frame.method_class}") end end class ConnectionClosedError < StandardError def initialize(frame) if frame.respond_to?(:method_class) super("Trying to send frame through a closed connection. Frame is #{frame.inspect}") else super("Trying to send frame through a closed connection. Frame is #{frame.inspect}, method class is #{frame.method_class}") end end # initialize end # class ConnectionClosedError module Logging # Raised when logger object passed to {AMQ::Client::Adapter.logger=} does not # provide API it supposed to provide. # # @see AMQ::Client::Adapter.logger= class IncompatibleLoggerError < StandardError def initialize(required_methods) super("Logger has to respond to the following methods: #{required_methods.inspect}") end end end # Logging class PossibleAuthenticationFailureError < StandardError # # API # def initialize(settings) super("AMQP broker closed TCP connection before authentication succeeded: this usually means authentication failure due to misconfiguration or that RabbitMQ version does not support AMQP 0.9.1. Please see http://bit.ly/amqp-gem-080-and-rabbitmq-versions and check your configuration. Settings are #{settings.inspect}.") end # initialize(settings) end # PossibleAuthenticationFailureError class UnknownExchangeTypeError < StandardError BUILTIN_TYPES = [:fanout, :direct, :topic, :headers].freeze def initialize(types, given) super("#{given.inspect} exchange type is unknown. Standard types are #{BUILTIN_TYPES.inspect}, custom exchange types must begin with x-, for example: x-recent-history") end end end # Client end # AMQ amq-client-0.9.3/lib/amq/client/framing/0000755000175000017500000000000011771004303017302 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/framing/string/0000755000175000017500000000000011771004303020610 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/framing/string/frame.rb0000644000175000017500000000374511771004303022240 0ustar tfheentfheen# encoding: utf-8 # This will be probably used by all the async libraries like EventMachine. # It expects the whole frame as one string, so if library of your choice # gives you input chunk-by-chunk, you'll need to have something like this: # # class Client # include EventMachine::Deferrable # # def receive_data(chunk) # if @payload.nil? # self.decode_from_string(chunk[0..6]) # @payload = "" # elsif @payload && chunk[-1] != FINAL_OCTET # @payload += chunk # @size += chunk.bytesize # else # check_size(@size, @payload.bytesize) # Frame.decode(@payload) # we need the whole payload # @size, @payload = nil # end # end # # NOTE: the client should also implement waiting for another frames, in case that some header/body frames are expected. # end require "amq/client/exceptions" module AMQ module Client module Framing module String class Frame < AMQ::Protocol::Frame ENCODINGS_SUPPORTED = defined? Encoding HEADER_SLICE = (0..6).freeze DATA_SLICE = (7..-1).freeze PAYLOAD_SLICE = (0..-2).freeze def self.decode(string) header = string[HEADER_SLICE] type, channel, size = self.decode_header(header) data = string[DATA_SLICE] payload = data[PAYLOAD_SLICE] frame_end = data[-1, 1] frame_end.force_encoding(AMQ::Protocol::Frame::FINAL_OCTET.encoding) if ENCODINGS_SUPPORTED # 1) the size is miscalculated if payload.bytesize != size raise BadLengthError.new(size, payload.bytesize) end # 2) the size is OK, but the string doesn't end with FINAL_OCTET raise NoFinalOctetError.new if frame_end != AMQ::Protocol::Frame::FINAL_OCTET self.new(type, payload, channel) end # self.from end # Frame end # String end # Framing end # Client end # AMQ amq-client-0.9.3/lib/amq/client/framing/io/0000755000175000017500000000000011771004303017711 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/framing/io/frame.rb0000644000175000017500000000141311771004303021327 0ustar tfheentfheen# encoding: utf-8 require "amq/client/exceptions" module AMQ module Client module Framing module IO class Frame < AMQ::Protocol::Frame def self.decode(io) header = io.read(7) type, channel, size = self.decode_header(header) data = io.read(size + 1) payload, frame_end = data[0..-2], data[-1, 1] # TODO: this will hang if the size is bigger than expected or it'll leave there some chars -> make it more error-proof: # BTW: socket#eof? raise NoFinalOctetError.new if frame_end != AMQ::Protocol::Frame::FINAL_OCTET self.new(type, payload, channel) end # self.from end # Frame end # IO end # Framing end # Client end # AMQ amq-client-0.9.3/lib/amq/client/consumer_tag_generator.rb0000644000175000017500000000115211771004303022737 0ustar tfheentfheen# encoding: utf-8 module AMQ module Client class ConsumerTagGenerator # # API # # @return [String] Generated consumer tag def generate "#{Kernel.rand}-#{Time.now.to_i * 1000}-#{Kernel.rand(999_999_999_999)}" end # generate # @return [String] Generated consumer tag def generate_for(queue) raise ArgumentError, "argument must respond to :name" unless queue.respond_to?(:name) "#{queue.name}-#{Time.now.to_i * 1000}-#{Kernel.rand(999_999_999_999)}" end # generate_for(queue) end # ConsumerTagGenerator end # Client end # AMQ amq-client-0.9.3/lib/amq/client/openable.rb0000644000175000017500000000207011771004303017770 0ustar tfheentfheen# encoding: utf-8 module AMQ module Client module Openable VALUES = [:opened, :closed, :opening, :closing].freeze class ImproperStatusError < ArgumentError def initialize(value) super("Value #{value.inspect} isn't permitted. Choose one of: #{AMQ::Client::Openable::VALUES.inspect}") end end attr_reader :status def status=(value) if VALUES.include?(value) @status = value else raise ImproperStatusError.new(value) end end def opened? @status == :opened end alias open? opened? def closed? @status == :closed end def opening? @status == :opening end def closing? @status == :closing end def opened! @status = :opened end # opened! def closed! @status = :closed end # closed! def opening! @status = :opening end # opening! def closing! @status = :closing end # closing! end end end amq-client-0.9.3/lib/amq/client/extensions/0000755000175000017500000000000011771004303020056 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/extensions/rabbitmq.rb0000644000175000017500000000023511771004303022204 0ustar tfheentfheen# encoding: utf-8 # http://www.rabbitmq.com/extensions.html require "amq/client/extensions/rabbitmq/basic" require "amq/client/extensions/rabbitmq/confirm" amq-client-0.9.3/lib/amq/client/extensions/rabbitmq/0000755000175000017500000000000011771004303021657 5ustar tfheentfheenamq-client-0.9.3/lib/amq/client/extensions/rabbitmq/confirm.rb0000644000175000017500000000035311771004303023642 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/extensions/rabbitmq/confirm" module AMQ module Client # backwards compatibility # @private Extensions = Async::Extensions unless defined?(Extensions) end # Client end # AMQ amq-client-0.9.3/lib/amq/client/extensions/rabbitmq/basic.rb0000644000175000017500000000036611771004303023272 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/extensions/rabbitmq/basic" # Basic.Nack module AMQ module Client # backwards compatibility # @private Extensions = Async::Extensions unless defined?(Extensions) end # Client end # AMQ amq-client-0.9.3/lib/amq/client/entity.rb0000644000175000017500000000047111771004303017522 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/entity" module AMQ module Client # backwards compatibility # @private RegisterEntityMixin = Async::RegisterEntityMixin ProtocolMethodHandlers = Async::ProtocolMethodHandlers Entity = Async::Entity end # Client end # AMQ amq-client-0.9.3/lib/amq/client/server_named_entity.rb0000644000175000017500000000073711771004303022261 0ustar tfheentfheen# encoding: utf-8 module AMQ module Client # Common behavior of AMQ entities that can be either client or server-named, for example, exchanges and queues. module ServerNamedEntity # @return [Boolean] true if this entity is anonymous (server-named) def server_named? @server_named || @name.nil? || @name.empty? end # backwards compabitility. MK. alias anonymous? server_named? end # ServerNamedEntity end # Client end # AMQ amq-client-0.9.3/lib/amq/client/channel.rb0000644000175000017500000000026511771004303017617 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/channel" module AMQ module Client # backwards compatibility # @private Channel = Async::Channel end # Client end # AMQ amq-client-0.9.3/lib/amq/client/exchange.rb0000644000175000017500000000027011771004303017765 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/exchange" module AMQ module Client # backwards compatibility # @private Exchange = Async::Exchange end # Client end # AMQ amq-client-0.9.3/lib/amq/client/settings.rb0000644000175000017500000001415411771004303020051 0ustar tfheentfheen# encoding: utf-8 require "amq/protocol/client" # TODO: "amq/protocol/constants" require "uri" module AMQ module Client # @see AMQ::Client::Settings.configure module Settings # @private AMQP_PORTS = {"amqp" => 5672, "amqps" => 5671}.freeze # @private AMQPS = "amqps".freeze # Default connection settings used by AMQ clients # # @see AMQ::Client::Settings.configure def self.default @default ||= { # server :host => "127.0.0.1", :port => AMQ::Protocol::DEFAULT_PORT, # login :user => "guest", :pass => "guest", :vhost => "/", # connection timeout :timeout => nil, # logging :logging => false, # ssl :ssl => false, # broker # if you want to load broker-specific extensions :broker => nil, :frame_max => 131072 } end def self.client_properties @client_properties ||= { :platform => ::RUBY_DESCRIPTION, :product => "AMQ Client", :information => "http://github.com/ruby-amqp/amq-client", :version => AMQ::Client::VERSION } end # Merges given configuration parameters with defaults and returns # the result. # # @param [Hash] Configuration parameters to use. # # @option settings [String] :host ("127.0.0.1") Hostname AMQ broker runs on. # @option settings [String] :port (5672) Port AMQ broker listens on. # @option settings [String] :vhost ("/") Virtual host to use. # @option settings [String] :user ("guest") Username to use for authentication. # @option settings [String] :pass ("guest") Password to use for authentication. # @option settings [String] :ssl (false) Should be use TLS (SSL) for connection? # @option settings [String] :timeout (nil) Connection timeout. # @option settings [String] :logging (false) Turns logging on or off. # @option settings [String] :broker (nil) Broker name (use if you intend to use broker-specific features). # @option settings [Fixnum] :frame_max (131072) Maximum frame size to use. If broker cannot support frames this large, broker's maximum value will be used instead. # # @return [Hash] Merged configuration parameters. def self.configure(settings = nil) case settings when Hash then if username = settings.delete(:username) settings[:user] ||= username end if password = settings.delete(:password) settings[:pass] ||= password end self.default.merge(settings) when String then settings = self.parse_amqp_url(settings) self.default.merge(settings) when NilClass then self.default end end # Parses AMQP connection URI and returns its components as a hash. # # h2. vhost naming schemes # # It is convenient to be able to specify the AMQP connection # parameters as a URI string, and various "amqp" URI schemes # exist. Unfortunately, there is no standard for these URIs, so # while the schemes share the basic idea, they differ in some # details. This implementation aims to encourage URIs that work # as widely as possible. # # The URI scheme should be "amqp", or "amqps" if SSL is required. # # The host, port, username and password are represented in the # authority component of the URI in the same way as in http URIs. # # The vhost is obtained from the first segment of the path, with the # leading slash removed. The path should contain only a single # segment (i.e, the only slash in it should be the leading one). # If the vhost is to include slashes or other reserved URI # characters, these should be percent-escaped. # # @example How vhost is parsed # # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com") # => vhost is nil, so default (/) will be used # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/") # => vhost is an empty string # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/%2Fvault") # => vhost is /vault # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/production") # => vhost is production # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/a.b.c") # => vhost is a.b.c # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/foo/bar") # => ArgumentError # # # @param [String] connection_string AMQP connection URI, à la JDBC connection string. For example: amqp://bus.megacorp.internal:5877. # @return [Hash] Connection parameters (:username, :password, :vhost, :host, :port, :ssl) # # @raise [ArgumentError] When connection URI schema is not amqp or amqps, or the path contains multiple segments # # @see http://bit.ly/ks8MXK Connecting to The Broker documentation guide # @api public def self.parse_amqp_url(connection_string) uri = URI.parse(connection_string) 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) opts = {} opts[:scheme] = uri.scheme opts[:user] = URI.unescape(uri.user) if uri.user opts[:pass] = URI.unescape(uri.password) if uri.password opts[:host] = uri.host if uri.host opts[:port] = uri.port || AMQ::Client::Settings::AMQP_PORTS[uri.scheme] opts[:ssl] = uri.scheme == AMQ::Client::Settings::AMQPS if uri.path =~ %r{^/(.*)} 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('/') opts[:vhost] = URI.unescape($1) end opts end end end end amq-client-0.9.3/lib/amq/client/queue.rb0000644000175000017500000000017111771004303017327 0ustar tfheentfheen# encoding: utf-8 require "amq/client/async/queue" module AMQ module Client Queue = Async::Queue end end