bunny-0.7.8/0000755000076400007640000000000011704323672011722 5ustar pravipravibunny-0.7.8/.travis.yml0000644000076400007640000000047611704323672014042 0ustar pravipravi# https://github.com/travis-ci/travis-ci/wiki/.travis.yml-options bundler_args: --without development script: "bundle exec rspec spec" rvm: - 1.8.7 - ree - 1.9.2 - 1.9.3 - rbx-2.0 notifications: recipients: - celldee@gmail.com - jakub@rabbitmq.com - skaes@railsexpress.de - eric@5stops.com bunny-0.7.8/Rakefile0000644000076400007640000000043611704323672013372 0ustar pravipravi# encoding: utf-8 require "bundler/gem_tasks" desc "Run rspec tests" task :spec do require 'rspec/core/rake_task' RSpec::Core::RakeTask.new("spec") do |t| t.pattern = "spec/spec_*/*_spec.rb" t.rspec_opts = ['--color', '--format doc'] end end task :default => [ :spec ] bunny-0.7.8/lib/0000755000076400007640000000000011704323672012470 5ustar pravipravibunny-0.7.8/lib/qrack/0000755000076400007640000000000011704323672013571 5ustar pravipravibunny-0.7.8/lib/qrack/qrack08.rb0000644000076400007640000000054411704323672015372 0ustar pravipravi# encoding: utf-8 $: << File.expand_path(File.dirname(__FILE__)) require 'protocol/spec08' require 'protocol/protocol08' require 'transport/buffer08' require 'transport/frame08' require 'qrack/client' require 'qrack/channel' require 'qrack/queue' require 'bunny/consumer' require 'qrack/errors' module Qrack include Protocol include Transport end bunny-0.7.8/lib/qrack/amq-client-url.rb0000644000076400007640000001502511704323672016753 0ustar pravipravi# encoding: utf-8 ################################################################ # DO NOT EDIT THIS FILE ! # # The file comes from https://github.com/ruby-amqp/amq-client, # # it's located in lib/amq/client/settings.rb, so if you want # # to make some changes, please do them in the amq-client repo. # ################################################################ # TODO: When we start to work on porting Bunny on AMQ Client, # this file will become obsolete. 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 bunny-0.7.8/lib/qrack/protocol/0000755000076400007640000000000011704323672015432 5ustar pravipravibunny-0.7.8/lib/qrack/protocol/spec09.rb0000644000076400007640000003252711704323672017073 0ustar pravipravi # encoding: utf-8 #:stopdoc: # this file was autogenerated on 2011-07-21 07:07:06 +0100 # using amqp-0.9.1.json (mtime: 2011-07-20 19:10:34 +0100) # # DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb') module Qrack module Protocol09 HEADER = "AMQP".freeze VERSION_MAJOR = 0 VERSION_MINOR = 9 REVISION = 1 PORT = 5672 RESPONSES = { 200 => :REPLY_SUCCESS, 311 => :CONTENT_TOO_LARGE, 312 => :NO_ROUTE, 313 => :NO_CONSUMERS, 320 => :CONNECTION_FORCED, 402 => :INVALID_PATH, 403 => :ACCESS_REFUSED, 404 => :NOT_FOUND, 405 => :RESOURCE_LOCKED, 406 => :PRECONDITION_FAILED, 502 => :SYNTAX_ERROR, 503 => :COMMAND_INVALID, 504 => :CHANNEL_ERROR, 505 => :UNEXPECTED_FRAME, 506 => :RESOURCE_ERROR, 530 => :NOT_ALLOWED, 540 => :NOT_IMPLEMENTED, 541 => :INTERNAL_ERROR, } FIELDS = [ :bit, :long, :longlong, :longstr, :octet, :short, :shortstr, :table, :timestamp, ] class Class class << self FIELDS.each do |f| class_eval %[ def #{f} name properties << [ :#{f}, name ] unless properties.include?([:#{f}, name]) attr_accessor name end ] end def properties() @properties ||= [] end def id() self::ID end def name() self::NAME.to_s end end class Method class << self FIELDS.each do |f| class_eval %[ def #{f} name arguments << [ :#{f}, name ] unless arguments.include?([:#{f}, name]) attr_accessor name end ] end def arguments() @arguments ||= [] end def parent() Protocol09.const_get(self.to_s[/Protocol09::(.+?)::/,1]) end def id() self::ID end def name() self::NAME.to_s end end def == b self.class.arguments.inject(true) do |eql, (type, name)| eql and __send__("#{name}") == b.__send__("#{name}") end end end def self.methods() @methods ||= {} end def self.Method(id, name) @_base_methods ||= {} @_base_methods[id] ||= ::Class.new(Method) do class_eval %[ def self.inherited klass klass.const_set(:ID, #{id}) klass.const_set(:NAME, :#{name.to_s}) klass.parent.methods[#{id}] = klass klass.parent.methods[klass::NAME] = klass end ] end end end def self.classes() @classes ||= {} end def self.Class(id, name) @_base_classes ||= {} @_base_classes[id] ||= ::Class.new(Class) do class_eval %[ def self.inherited klass klass.const_set(:ID, #{id}) klass.const_set(:NAME, :#{name.to_s}) Protocol09.classes[#{id}] = klass Protocol09.classes[klass::NAME] = klass end ] end end end end module Qrack module Protocol09 class Connection < Class( 10, :connection ); end class Channel < Class( 20, :channel ); end class Exchange < Class( 40, :exchange ); end class Queue < Class( 50, :queue ); end class Basic < Class( 60, :basic ); end class Tx < Class( 90, :tx ); end class Connection class Start < Method( 10, :start ); end class StartOk < Method( 11, :start_ok ); end class Secure < Method( 20, :secure ); end class SecureOk < Method( 21, :secure_ok ); end class Tune < Method( 30, :tune ); end class TuneOk < Method( 31, :tune_ok ); end class Open < Method( 40, :open ); end class OpenOk < Method( 41, :open_ok ); end class Close < Method( 50, :close ); end class CloseOk < Method( 51, :close_ok ); end class Start octet :version_major octet :version_minor table :server_properties longstr :mechanisms longstr :locales end class StartOk table :client_properties shortstr :mechanism longstr :response shortstr :locale end class Secure longstr :challenge end class SecureOk longstr :response end class Tune short :channel_max long :frame_max short :heartbeat end class TuneOk short :channel_max long :frame_max short :heartbeat end class Open shortstr :virtual_host shortstr :deprecated_capabilities bit :deprecated_insist end class OpenOk shortstr :deprecated_known_hosts end class Close short :reply_code shortstr :reply_text short :class_id short :method_id end class CloseOk end end class Channel class Open < Method( 10, :open ); end class OpenOk < Method( 11, :open_ok ); end class Flow < Method( 20, :flow ); end class FlowOk < Method( 21, :flow_ok ); end class Close < Method( 40, :close ); end class CloseOk < Method( 41, :close_ok ); end class Open shortstr :deprecated_out_of_band end class OpenOk longstr :deprecated_channel_id end class Flow bit :active end class FlowOk bit :active end class Close short :reply_code shortstr :reply_text short :class_id short :method_id end class CloseOk end end class Exchange class Declare < Method( 10, :declare ); end class DeclareOk < Method( 11, :declare_ok ); end class Delete < Method( 20, :delete ); end class DeleteOk < Method( 21, :delete_ok ); end class Declare short :deprecated_ticket shortstr :exchange shortstr :type bit :passive bit :durable bit :deprecated_auto_delete bit :deprecated_internal bit :nowait table :arguments end class DeclareOk end class Delete short :deprecated_ticket shortstr :exchange bit :if_unused bit :nowait end class DeleteOk end end class Queue class Declare < Method( 10, :declare ); end class DeclareOk < Method( 11, :declare_ok ); end class Bind < Method( 20, :bind ); end class BindOk < Method( 21, :bind_ok ); end class Purge < Method( 30, :purge ); end class PurgeOk < Method( 31, :purge_ok ); end class Delete < Method( 40, :delete ); end class DeleteOk < Method( 41, :delete_ok ); end class Unbind < Method( 50, :unbind ); end class UnbindOk < Method( 51, :unbind_ok ); end class Declare short :deprecated_ticket shortstr :queue bit :passive bit :durable bit :exclusive bit :auto_delete bit :nowait table :arguments end class DeclareOk shortstr :queue long :message_count long :consumer_count end class Bind short :deprecated_ticket shortstr :queue shortstr :exchange shortstr :routing_key bit :nowait table :arguments end class BindOk end class Purge short :deprecated_ticket shortstr :queue bit :nowait end class PurgeOk long :message_count end class Delete short :deprecated_ticket shortstr :queue bit :if_unused bit :if_empty bit :nowait end class DeleteOk long :message_count end class Unbind short :deprecated_ticket shortstr :queue shortstr :exchange shortstr :routing_key table :arguments end class UnbindOk end end class Basic shortstr :content_type shortstr :content_encoding table :headers octet :delivery_mode octet :priority shortstr :correlation_id shortstr :reply_to shortstr :expiration shortstr :message_id timestamp :timestamp shortstr :type shortstr :user_id shortstr :app_id shortstr :deprecated_cluster_id class Qos < Method( 10, :qos ); end class QosOk < Method( 11, :qos_ok ); end class Consume < Method( 20, :consume ); end class ConsumeOk < Method( 21, :consume_ok ); end class Cancel < Method( 30, :cancel ); end class CancelOk < Method( 31, :cancel_ok ); end class Publish < Method( 40, :publish ); end class Return < Method( 50, :return ); end class Deliver < Method( 60, :deliver ); end class Get < Method( 70, :get ); end class GetOk < Method( 71, :get_ok ); end class GetEmpty < Method( 72, :get_empty ); end class Ack < Method( 80, :ack ); end class Reject < Method( 90, :reject ); end class RecoverAsync < Method( 100, :recover_async ); end class Recover < Method( 110, :recover ); end class RecoverOk < Method( 111, :recover_ok ); end class Qos long :prefetch_size short :prefetch_count bit :global end class QosOk end class Consume short :deprecated_ticket shortstr :queue shortstr :consumer_tag bit :no_local bit :no_ack bit :exclusive bit :nowait table :filter end class ConsumeOk shortstr :consumer_tag end class Cancel shortstr :consumer_tag bit :nowait end class CancelOk shortstr :consumer_tag end class Publish short :deprecated_ticket shortstr :exchange shortstr :routing_key bit :mandatory bit :immediate end class Return short :reply_code shortstr :reply_text shortstr :exchange shortstr :routing_key end class Deliver shortstr :consumer_tag longlong :delivery_tag bit :redelivered shortstr :exchange shortstr :routing_key end class Get short :deprecated_ticket shortstr :queue bit :no_ack end class GetOk longlong :delivery_tag bit :redelivered shortstr :exchange shortstr :routing_key long :message_count end class GetEmpty shortstr :deprecated_cluster_id end class Ack longlong :delivery_tag bit :multiple end class Reject longlong :delivery_tag bit :requeue end class RecoverAsync bit :requeue end class Recover bit :requeue end class RecoverOk end end class Tx class Select < Method( 10, :select ); end class SelectOk < Method( 11, :select_ok ); end class Commit < Method( 20, :commit ); end class CommitOk < Method( 21, :commit_ok ); end class Rollback < Method( 30, :rollback ); end class RollbackOk < Method( 31, :rollback_ok ); end class Select end class SelectOk end class Commit end class CommitOk end class Rollback end class RollbackOk end end end end bunny-0.7.8/lib/qrack/protocol/spec08.rb0000644000076400007640000005152311704323672017067 0ustar pravipravi # encoding: utf-8 #:stopdoc: # this file was autogenerated on 2011-07-21 07:15:33 +0100 # using amqp-0.8.json (mtime: 2011-07-20 19:11:32 +0100) # # DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb') module Qrack module Protocol HEADER = "AMQP".freeze VERSION_MAJOR = 8 VERSION_MINOR = 0 REVISION = 0 PORT = 5672 RESPONSES = { 200 => :REPLY_SUCCESS, 310 => :NOT_DELIVERED, 311 => :CONTENT_TOO_LARGE, 312 => :NO_ROUTE, 313 => :NO_CONSUMERS, 320 => :CONNECTION_FORCED, 402 => :INVALID_PATH, 403 => :ACCESS_REFUSED, 404 => :NOT_FOUND, 405 => :RESOURCE_LOCKED, 406 => :PRECONDITION_FAILED, 502 => :SYNTAX_ERROR, 503 => :COMMAND_INVALID, 504 => :CHANNEL_ERROR, 506 => :RESOURCE_ERROR, 530 => :NOT_ALLOWED, 540 => :NOT_IMPLEMENTED, 541 => :INTERNAL_ERROR, } FIELDS = [ :bit, :long, :longlong, :longstr, :octet, :short, :shortstr, :table, :timestamp, ] class Class class << self FIELDS.each do |f| class_eval %[ def #{f} name properties << [ :#{f}, name ] unless properties.include?([:#{f}, name]) attr_accessor name end ] end def properties() @properties ||= [] end def id() self::ID end def name() self::NAME.to_s end end class Method class << self FIELDS.each do |f| class_eval %[ def #{f} name arguments << [ :#{f}, name ] unless arguments.include?([:#{f}, name]) attr_accessor name end ] end def arguments() @arguments ||= [] end def parent() Protocol.const_get(self.to_s[/Protocol::(.+?)::/,1]) end def id() self::ID end def name() self::NAME.to_s end end def == b self.class.arguments.inject(true) do |eql, (type, name)| eql and __send__("#{name}") == b.__send__("#{name}") end end end def self.methods() @methods ||= {} end def self.Method(id, name) @_base_methods ||= {} @_base_methods[id] ||= ::Class.new(Method) do class_eval %[ def self.inherited klass klass.const_set(:ID, #{id}) klass.const_set(:NAME, :#{name.to_s}) klass.parent.methods[#{id}] = klass klass.parent.methods[klass::NAME] = klass end ] end end end def self.classes() @classes ||= {} end def self.Class(id, name) @_base_classes ||= {} @_base_classes[id] ||= ::Class.new(Class) do class_eval %[ def self.inherited klass klass.const_set(:ID, #{id}) klass.const_set(:NAME, :#{name.to_s}) Protocol.classes[#{id}] = klass Protocol.classes[klass::NAME] = klass end ] end end end end module Qrack module Protocol class Connection < Class( 10, :connection ); end class Channel < Class( 20, :channel ); end class Access < Class( 30, :access ); end class Exchange < Class( 40, :exchange ); end class Queue < Class( 50, :queue ); end class Basic < Class( 60, :basic ); end class File < Class( 70, :file ); end class Stream < Class( 80, :stream ); end class Tx < Class( 90, :tx ); end class Dtx < Class( 100, :dtx ); end class Tunnel < Class( 110, :tunnel ); end class Test < Class( 120, :test ); end class Connection class Start < Method( 10, :start ); end class StartOk < Method( 11, :start_ok ); end class Secure < Method( 20, :secure ); end class SecureOk < Method( 21, :secure_ok ); end class Tune < Method( 30, :tune ); end class TuneOk < Method( 31, :tune_ok ); end class Open < Method( 40, :open ); end class OpenOk < Method( 41, :open_ok ); end class Redirect < Method( 50, :redirect ); end class Close < Method( 60, :close ); end class CloseOk < Method( 61, :close_ok ); end class Start octet :version_major octet :version_minor table :server_properties longstr :mechanisms longstr :locales end class StartOk table :client_properties shortstr :mechanism longstr :response shortstr :locale end class Secure longstr :challenge end class SecureOk longstr :response end class Tune short :channel_max long :frame_max short :heartbeat end class TuneOk short :channel_max long :frame_max short :heartbeat end class Open shortstr :virtual_host shortstr :capabilities bit :insist end class OpenOk shortstr :known_hosts end class Redirect shortstr :host shortstr :known_hosts end class Close short :reply_code shortstr :reply_text short :class_id short :method_id end class CloseOk end end class Channel class Open < Method( 10, :open ); end class OpenOk < Method( 11, :open_ok ); end class Flow < Method( 20, :flow ); end class FlowOk < Method( 21, :flow_ok ); end class Alert < Method( 30, :alert ); end class Close < Method( 40, :close ); end class CloseOk < Method( 41, :close_ok ); end class Open shortstr :out_of_band end class OpenOk end class Flow bit :active end class FlowOk bit :active end class Alert short :reply_code shortstr :reply_text table :details end class Close short :reply_code shortstr :reply_text short :class_id short :method_id end class CloseOk end end class Access class Request < Method( 10, :request ); end class RequestOk < Method( 11, :request_ok ); end class Request shortstr :realm bit :exclusive bit :passive bit :active bit :write bit :read end class RequestOk short :ticket end end class Exchange class Declare < Method( 10, :declare ); end class DeclareOk < Method( 11, :declare_ok ); end class Delete < Method( 20, :delete ); end class DeleteOk < Method( 21, :delete_ok ); end class Declare short :ticket shortstr :exchange shortstr :type bit :passive bit :durable bit :auto_delete bit :internal bit :nowait table :arguments end class DeclareOk end class Delete short :ticket shortstr :exchange bit :if_unused bit :nowait end class DeleteOk end end class Queue class Declare < Method( 10, :declare ); end class DeclareOk < Method( 11, :declare_ok ); end class Bind < Method( 20, :bind ); end class BindOk < Method( 21, :bind_ok ); end class Purge < Method( 30, :purge ); end class PurgeOk < Method( 31, :purge_ok ); end class Delete < Method( 40, :delete ); end class DeleteOk < Method( 41, :delete_ok ); end class Unbind < Method( 50, :unbind ); end class UnbindOk < Method( 51, :unbind_ok ); end class Declare short :ticket shortstr :queue bit :passive bit :durable bit :exclusive bit :auto_delete bit :nowait table :arguments end class DeclareOk shortstr :queue long :message_count long :consumer_count end class Bind short :ticket shortstr :queue shortstr :exchange shortstr :routing_key bit :nowait table :arguments end class BindOk end class Purge short :ticket shortstr :queue bit :nowait end class PurgeOk long :message_count end class Delete short :ticket shortstr :queue bit :if_unused bit :if_empty bit :nowait end class DeleteOk long :message_count end class Unbind short :ticket shortstr :queue shortstr :exchange shortstr :routing_key table :arguments end class UnbindOk end end class Basic shortstr :content_type shortstr :content_encoding table :headers octet :delivery_mode octet :priority shortstr :correlation_id shortstr :reply_to shortstr :expiration shortstr :message_id timestamp :timestamp shortstr :type shortstr :user_id shortstr :app_id shortstr :cluster_id class Qos < Method( 10, :qos ); end class QosOk < Method( 11, :qos_ok ); end class Consume < Method( 20, :consume ); end class ConsumeOk < Method( 21, :consume_ok ); end class Cancel < Method( 30, :cancel ); end class CancelOk < Method( 31, :cancel_ok ); end class Publish < Method( 40, :publish ); end class Return < Method( 50, :return ); end class Deliver < Method( 60, :deliver ); end class Get < Method( 70, :get ); end class GetOk < Method( 71, :get_ok ); end class GetEmpty < Method( 72, :get_empty ); end class Ack < Method( 80, :ack ); end class Reject < Method( 90, :reject ); end class Recover < Method( 100, :recover ); end class Qos long :prefetch_size short :prefetch_count bit :global end class QosOk end class Consume short :ticket shortstr :queue shortstr :consumer_tag bit :no_local bit :no_ack bit :exclusive bit :nowait end class ConsumeOk shortstr :consumer_tag end class Cancel shortstr :consumer_tag bit :nowait end class CancelOk shortstr :consumer_tag end class Publish short :ticket shortstr :exchange shortstr :routing_key bit :mandatory bit :immediate end class Return short :reply_code shortstr :reply_text shortstr :exchange shortstr :routing_key end class Deliver shortstr :consumer_tag longlong :delivery_tag bit :redelivered shortstr :exchange shortstr :routing_key end class Get short :ticket shortstr :queue bit :no_ack end class GetOk longlong :delivery_tag bit :redelivered shortstr :exchange shortstr :routing_key long :message_count end class GetEmpty shortstr :cluster_id end class Ack longlong :delivery_tag bit :multiple end class Reject longlong :delivery_tag bit :requeue end class Recover bit :requeue end end class File shortstr :content_type shortstr :content_encoding table :headers octet :priority shortstr :reply_to shortstr :message_id shortstr :filename timestamp :timestamp shortstr :cluster_id class Qos < Method( 10, :qos ); end class QosOk < Method( 11, :qos_ok ); end class Consume < Method( 20, :consume ); end class ConsumeOk < Method( 21, :consume_ok ); end class Cancel < Method( 30, :cancel ); end class CancelOk < Method( 31, :cancel_ok ); end class Open < Method( 40, :open ); end class OpenOk < Method( 41, :open_ok ); end class Stage < Method( 50, :stage ); end class Publish < Method( 60, :publish ); end class Return < Method( 70, :return ); end class Deliver < Method( 80, :deliver ); end class Ack < Method( 90, :ack ); end class Reject < Method( 100, :reject ); end class Qos long :prefetch_size short :prefetch_count bit :global end class QosOk end class Consume short :ticket shortstr :queue shortstr :consumer_tag bit :no_local bit :no_ack bit :exclusive bit :nowait end class ConsumeOk shortstr :consumer_tag end class Cancel shortstr :consumer_tag bit :nowait end class CancelOk shortstr :consumer_tag end class Open shortstr :identifier longlong :content_size end class OpenOk longlong :staged_size end class Stage end class Publish short :ticket shortstr :exchange shortstr :routing_key bit :mandatory bit :immediate shortstr :identifier end class Return short :reply_code shortstr :reply_text shortstr :exchange shortstr :routing_key end class Deliver shortstr :consumer_tag longlong :delivery_tag bit :redelivered shortstr :exchange shortstr :routing_key shortstr :identifier end class Ack longlong :delivery_tag bit :multiple end class Reject longlong :delivery_tag bit :requeue end end class Stream shortstr :content_type shortstr :content_encoding table :headers octet :priority timestamp :timestamp class Qos < Method( 10, :qos ); end class QosOk < Method( 11, :qos_ok ); end class Consume < Method( 20, :consume ); end class ConsumeOk < Method( 21, :consume_ok ); end class Cancel < Method( 30, :cancel ); end class CancelOk < Method( 31, :cancel_ok ); end class Publish < Method( 40, :publish ); end class Return < Method( 50, :return ); end class Deliver < Method( 60, :deliver ); end class Qos long :prefetch_size short :prefetch_count long :consume_rate bit :global end class QosOk end class Consume short :ticket shortstr :queue shortstr :consumer_tag bit :no_local bit :exclusive bit :nowait end class ConsumeOk shortstr :consumer_tag end class Cancel shortstr :consumer_tag bit :nowait end class CancelOk shortstr :consumer_tag end class Publish short :ticket shortstr :exchange shortstr :routing_key bit :mandatory bit :immediate end class Return short :reply_code shortstr :reply_text shortstr :exchange shortstr :routing_key end class Deliver shortstr :consumer_tag longlong :delivery_tag shortstr :exchange shortstr :queue end end class Tx class Select < Method( 10, :select ); end class SelectOk < Method( 11, :select_ok ); end class Commit < Method( 20, :commit ); end class CommitOk < Method( 21, :commit_ok ); end class Rollback < Method( 30, :rollback ); end class RollbackOk < Method( 31, :rollback_ok ); end class Select end class SelectOk end class Commit end class CommitOk end class Rollback end class RollbackOk end end class Dtx class Select < Method( 10, :select ); end class SelectOk < Method( 11, :select_ok ); end class Start < Method( 20, :start ); end class StartOk < Method( 21, :start_ok ); end class Select end class SelectOk end class Start shortstr :dtx_identifier end class StartOk end end class Tunnel table :headers shortstr :proxy_name shortstr :data_name octet :durable octet :broadcast class Request < Method( 10, :request ); end class Request table :meta_data end end class Test class Integer < Method( 10, :integer ); end class IntegerOk < Method( 11, :integer_ok ); end class String < Method( 20, :string ); end class StringOk < Method( 21, :string_ok ); end class Table < Method( 30, :table ); end class TableOk < Method( 31, :table_ok ); end class Content < Method( 40, :content ); end class ContentOk < Method( 41, :content_ok ); end class Integer octet :integer_1 short :integer_2 long :integer_3 longlong :integer_4 octet :operation end class IntegerOk longlong :result end class String shortstr :string_1 longstr :string_2 octet :operation end class StringOk longstr :result end class Table table :table octet :integer_op octet :string_op end class TableOk longlong :integer_result longstr :string_result end class Content end class ContentOk long :content_checksum end end end end bunny-0.7.8/lib/qrack/protocol/protocol08.rb0000644000076400007640000000675611704323672020006 0ustar pravipravi# encoding: utf-8 module Qrack module Protocol #:stopdoc: class Class::Method def initialize *args opts = args.pop if args.last.is_a? Hash opts ||= {} if args.size == 1 and args.first.is_a? Transport::Buffer buf = args.shift else buf = nil end self.class.arguments.each do |type, name| val = buf ? buf.read(type) : args.shift || opts[name] || opts[name.to_s] instance_variable_set("@#{name}", val) end end def arguments self.class.arguments.inject({}) do |hash, (type, name)| hash.update name => instance_variable_get("@#{name}") end end def to_binary buf = Transport::Buffer.new buf.write :short, self.class.parent.id buf.write :short, self.class.id bits = [] self.class.arguments.each do |type, name| val = instance_variable_get("@#{name}") if type == :bit bits << (val || false) else unless bits.empty? buf.write :bit, bits bits = [] end buf.write type, val end end buf.write :bit, bits unless bits.empty? buf.rewind buf end def to_s to_binary.to_s end def to_frame channel = 0 Transport::Method.new(self, channel) end end class Header def initialize *args opts = args.pop if args.last.is_a? Hash opts ||= {} first = args.shift if first.is_a? ::Class and first.ancestors.include? Protocol::Class @klass = first @size = args.shift || 0 @weight = args.shift || 0 @properties = opts elsif first.is_a? Transport::Buffer or first.is_a? String buf = first buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer @klass = Protocol.classes[buf.read(:short)] @weight = buf.read(:short) @size = buf.read(:longlong) props = buf.read(:properties, *klass.properties.map{|type,_| type }) @properties = Hash[*klass.properties.map{|_,name| name }.zip(props).reject{|k,v| v.nil? }.flatten] else raise ArgumentError, 'Invalid argument' end end attr_accessor :klass, :size, :weight, :properties def to_binary buf = Transport::Buffer.new buf.write :short, klass.id buf.write :short, weight # XXX rabbitmq only supports weight == 0 buf.write :longlong, size buf.write :properties, (klass.properties.map do |type, name| [ type, properties[name] || properties[name.to_s] ] end) buf.rewind buf end def to_s to_binary.to_s end def to_frame channel = 0 Transport::Header.new(self, channel) end def == header [ :klass, :size, :weight, :properties ].inject(true) do |eql, field| eql and __send__(field) == header.__send__(field) end end def method_missing meth, *args, &blk @properties.has_key?(meth) || @klass.properties.find{|_,name| name == meth } ? @properties[meth] : super end end def self.parse buf buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer class_id, method_id = buf.read(:short, :short) classes[class_id].methods[method_id].new(buf) end end end bunny-0.7.8/lib/qrack/protocol/protocol09.rb0000644000076400007640000000702211704323672017772 0ustar pravipravi# encoding: utf-8 module Qrack module Protocol09 #:stopdoc: class Class::Method def initialize *args opts = args.pop if args.last.is_a? Hash opts ||= {} if args.size == 1 and args.first.is_a? Transport09::Buffer buf = args.shift else buf = nil end self.class.arguments.each do |type, name| val = buf ? buf.read(type) : args.shift || opts[name] || opts[name.to_s] instance_variable_set("@#{name}", val) end end def arguments self.class.arguments.inject({}) do |hash, (type, name)| hash.update name => instance_variable_get("@#{name}") end end def to_binary buf = Transport09::Buffer.new buf.write :short, self.class.parent.id buf.write :short, self.class.id bits = [] self.class.arguments.each do |type, name| val = instance_variable_get("@#{name}") if type == :bit bits << (val || false) else unless bits.empty? buf.write :bit, bits bits = [] end buf.write type, val end end buf.write :bit, bits unless bits.empty? buf.rewind buf end def to_s to_binary.to_s end def to_frame channel = 0 Transport09::Method.new(self, channel) end end class Header def initialize *args opts = args.pop if args.last.is_a? Hash opts ||= {} first = args.shift if first.is_a? ::Class and first.ancestors.include? Protocol09::Class @klass = first @size = args.shift || 0 @weight = args.shift || 0 @properties = opts elsif first.is_a? Transport09::Buffer or first.is_a? String buf = first buf = Transport09::Buffer.new(buf) unless buf.is_a? Transport09::Buffer @klass = Protocol09.classes[buf.read(:short)] @weight = buf.read(:short) @size = buf.read(:longlong) props = buf.read(:properties, *klass.properties.map{|type,_| type }) @properties = Hash[*klass.properties.map{|_,name| name }.zip(props).reject{|k,v| v.nil? }.flatten] else raise ArgumentError, 'Invalid argument' end end attr_accessor :klass, :size, :weight, :properties def to_binary buf = Transport09::Buffer.new buf.write :short, klass.id buf.write :short, weight # XXX rabbitmq only supports weight == 0 buf.write :longlong, size buf.write :properties, (klass.properties.map do |type, name| [ type, properties[name] || properties[name.to_s] ] end) buf.rewind buf end def to_s to_binary.to_s end def to_frame channel = 0 Transport09::Header.new(self, channel) end def == header [ :klass, :size, :weight, :properties ].inject(true) do |eql, field| eql and __send__(field) == header.__send__(field) end end def method_missing meth, *args, &blk @properties.has_key?(meth) || @klass.properties.find{|_,name| name == meth } ? @properties[meth] : super end end def self.parse buf buf = Transport09::Buffer.new(buf) unless buf.is_a? Transport09::Buffer class_id, method_id = buf.read(:short, :short) classes[class_id].methods[method_id].new(buf) end end end bunny-0.7.8/lib/qrack/channel.rb0000644000076400007640000000052711704323672015532 0ustar pravipravi# encoding: utf-8 module Qrack # Channel ancestor class class Channel attr_accessor :number, :active, :frame_buffer attr_reader :client def initialize(client) @frame_buffer = [] @client = client @number = client.channels.size @active = false client.channels[@number] = self end end end bunny-0.7.8/lib/qrack/transport/0000755000076400007640000000000011704323672015625 5ustar pravipravibunny-0.7.8/lib/qrack/transport/frame09.rb0000644000076400007640000000374111704323672017422 0ustar pravipravi # encoding: utf-8 #:stopdoc: # this file was autogenerated on 2011-07-21 07:07:06 +0100 # # DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb') module Qrack module Transport09 class Frame FOOTER = 206 ID = 0 @types = { 1 => 'Method', 2 => 'Header', 3 => 'Body', 8 => 'Heartbeat', } attr_accessor :channel, :payload def initialize payload = nil, channel = 0 @channel, @payload = channel, payload end def id self.class::ID end def to_binary buf = Transport09::Buffer.new buf.write :octet, id buf.write :short, channel buf.write :longstr, payload buf.write :octet, FOOTER buf.rewind buf end def to_s to_binary.to_s end def == frame [ :id, :channel, :payload ].inject(true) do |eql, field| eql and __send__(field) == frame.__send__(field) end end def self.parse buf buf = Transport09::Buffer.new(buf) unless buf.is_a? Transport09::Buffer buf.extract do id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet) Qrack::Transport09.const_get(@types[id]).new(payload, channel) if footer == FOOTER end end end class Method < Frame ID = 1 def initialize payload = nil, channel = 0 super unless @payload.is_a? Protocol09::Class::Method or @payload.nil? @payload = Protocol09.parse(@payload) end end end class Header < Frame ID = 2 def initialize payload = nil, channel = 0 super unless @payload.is_a? Protocol09::Header or @payload.nil? @payload = Protocol09::Header.new(@payload) end end end class Body < Frame ID = 3 end class Heartbeat < Frame ID = 8 end end end bunny-0.7.8/lib/qrack/transport/buffer09.rb0000644000076400007640000001663111704323672017603 0ustar pravipravi# encoding: utf-8 if [].map.respond_to? :with_index class Array #:nodoc: def enum_with_index each.with_index end end else require 'enumerator' end module Qrack module Transport09 #:nodoc: all class Buffer def initialize data = '' @data = data @pos = 0 end attr_reader :pos def data @data.clone end alias :contents :data alias :to_s :data def << data @data << data.to_s self end def length @data.bytesize end def empty? pos == length end def rewind @pos = 0 end def read_properties *types types.shift if types.first == :properties i = 0 values = [] while props = read(:short) (0..14).each do |n| # no more property types break unless types[i] # if flag is set if props & (1<<(15-n)) != 0 if types[i] == :bit # bit values exist in flags only values << true else # save type name for later reading values << types[i] end else # property not set or is false bit values << (types[i] == :bit ? false : nil) end i+=1 end # bit(0) == 0 means no more property flags break unless props & 1 == 1 end values.map do |value| value.is_a?(Symbol) ? read(value) : value end end def read *types if types.first == :properties return read_properties(*types) end values = types.map do |type| case type when :octet _read(1, 'C') when :short _read(2, 'n') when :long _read(4, 'N') when :longlong upper, lower = _read(8, 'NN') upper << 32 | lower when :shortstr _read read(:octet) when :longstr _read read(:long) when :timestamp Time.at read(:longlong) when :table t = Hash.new table = Buffer.new(read(:longstr)) until table.empty? key, type = table.read(:shortstr, :octet) key = key.intern t[key] ||= case type when 83 # 'S' table.read(:longstr) when 73 # 'I' table.read(:long) when 68 # 'D' exp = table.read(:octet) num = table.read(:long) num / 10.0**exp when 84 # 'T' table.read(:timestamp) when 70 # 'F' table.read(:table) when 116 # 't' table.read(:octet) end end t when :bit if (@bits ||= []).empty? val = read(:octet) @bits = (0..7).map{|i| (val & (1 << i)) != 0 } end @bits.shift else raise Qrack::InvalidTypeError, "Cannot read data of type #{type}" end end types.size == 1 ? values.first : values end def write type, data case type when :octet _write(data, 'C') when :short _write(data, 'n') when :long _write(data, 'N') when :longlong lower = data & 0xffffffff upper = (data & ~0xffffffff) >> 32 _write([upper, lower], 'NN') when :shortstr data = (data || '').to_s _write([data.bytesize, data], 'Ca*') when :longstr if data.is_a? Hash write(:table, data) else data = (data || '').to_s _write([data.bytesize, data], 'Na*') end when :timestamp write(:longlong, data.to_i) when :table data ||= {} write :longstr, (data.inject(Buffer.new) do |table, (key, value)| table.write(:shortstr, key.to_s) case value when String table.write(:octet, 83) # 'S' table.write(:longstr, value.to_s) when Fixnum table.write(:octet, 73) # 'I' table.write(:long, value) when Float table.write(:octet, 68) # 'D' # XXX there's gotta be a better way to do this.. exp = value.to_s.split('.').last.bytesize num = value * 10**exp table.write(:octet, exp) table.write(:long, num) when Time table.write(:octet, 84) # 'T' table.write(:timestamp, value) when Hash table.write(:octet, 70) # 'F' table.write(:table, value) end table end) when :bit [*data].to_enum(:each_slice, 8).each{|bits| write(:octet, bits.enum_with_index.inject(0){ |byte, (bit, i)| byte |= (1 << i) if bit byte }) } when :properties values = [] data.enum_with_index.inject(0) do |short, ((type, value), i)| n = i % 15 last = i+1 == data.size if (n == 0 and i != 0) or last if data.size > i+1 short |= (1 << 0) elsif last and value values << [type,value] short |= 1<<(15-n) end write(:short, short) short = 0 end if value and !last values << [type,value] short |= 1<<(15-n) end short end values.each do |type, value| write(type, value) unless type == :bit end else raise Qrack::InvalidTypeError, "Cannot write data of type #{type}" end self end def extract begin cur_data, cur_pos = @data.clone, @pos yield self rescue Qrack::BufferOverflowError @data, @pos = cur_data, cur_pos nil end end def _read(size, pack = nil) if @data.is_a?(Qrack::Client) raw = @data.read(size) return raw if raw.nil? or pack.nil? return raw.unpack(pack).first end if @pos + size > length raise Qrack::BufferOverflowError else data = @data[@pos,size] @data[@pos,size] = '' if pack data = data.unpack(pack) data = data.pop if data.size == 1 end data end end def _write data, pack = nil data = [*data].pack(pack) if pack @data[@pos,0] = data @pos += data.bytesize end end end end bunny-0.7.8/lib/qrack/transport/frame08.rb0000644000076400007640000000442711704323672017423 0ustar pravipravi # encoding: utf-8 #:stopdoc: # this file was autogenerated on 2011-07-21 07:15:33 +0100 # # DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb') module Qrack module Transport class Frame FOOTER = 206 ID = 0 @types = { 1 => 'Method', 2 => 'Header', 3 => 'Body', 4 => 'OobMethod', 5 => 'OobHeader', 6 => 'OobBody', 7 => 'Trace', 8 => 'Heartbeat', } attr_accessor :channel, :payload def initialize payload = nil, channel = 0 @channel, @payload = channel, payload end def id self.class::ID end def to_binary buf = Transport::Buffer.new buf.write :octet, id buf.write :short, channel buf.write :longstr, payload buf.write :octet, FOOTER buf.rewind buf end def to_s to_binary.to_s end def == frame [ :id, :channel, :payload ].inject(true) do |eql, field| eql and __send__(field) == frame.__send__(field) end end def self.parse buf buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer buf.extract do id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet) Qrack::Transport.const_get(@types[id]).new(payload, channel) if footer == FOOTER end end end class Method < Frame ID = 1 def initialize payload = nil, channel = 0 super unless @payload.is_a? Protocol::Class::Method or @payload.nil? @payload = Protocol.parse(@payload) end end end class Header < Frame ID = 2 def initialize payload = nil, channel = 0 super unless @payload.is_a? Protocol::Header or @payload.nil? @payload = Protocol::Header.new(@payload) end end end class Body < Frame ID = 3 end class OobMethod < Frame ID = 4 end class OobHeader < Frame ID = 5 end class OobBody < Frame ID = 6 end class Trace < Frame ID = 7 end class Heartbeat < Frame ID = 8 end end end bunny-0.7.8/lib/qrack/transport/buffer08.rb0000644000076400007640000001650111704323672017576 0ustar pravipravi# encoding: utf-8 if [].map.respond_to? :with_index class Array #:nodoc: def enum_with_index each.with_index end end else require 'enumerator' end module Qrack module Transport #:nodoc: all class Buffer def initialize data = '' @data = data @pos = 0 end attr_reader :pos def data @data.clone end alias :contents :data alias :to_s :data def << data @data << data.to_s self end def length @data.bytesize end def empty? pos == length end def rewind @pos = 0 end def read_properties *types types.shift if types.first == :properties i = 0 values = [] while props = read(:short) (0..14).each do |n| # no more property types break unless types[i] # if flag is set if props & (1<<(15-n)) != 0 if types[i] == :bit # bit values exist in flags only values << true else # save type name for later reading values << types[i] end else # property not set or is false bit values << (types[i] == :bit ? false : nil) end i+=1 end # bit(0) == 0 means no more property flags break unless props & 1 == 1 end values.map do |value| value.is_a?(Symbol) ? read(value) : value end end def read *types if types.first == :properties return read_properties(*types) end values = types.map do |type| case type when :octet _read(1, 'C') when :short _read(2, 'n') when :long _read(4, 'N') when :longlong upper, lower = _read(8, 'NN') upper << 32 | lower when :shortstr _read read(:octet) when :longstr _read read(:long) when :timestamp Time.at read(:longlong) when :table t = Hash.new table = Buffer.new(read(:longstr)) until table.empty? key, type = table.read(:shortstr, :octet) key = key.intern t[key] ||= case type when 83 # 'S' table.read(:longstr) when 73 # 'I' table.read(:long) when 68 # 'D' exp = table.read(:octet) num = table.read(:long) num / 10.0**exp when 84 # 'T' table.read(:timestamp) when 70 # 'F' table.read(:table) end end t when :bit if (@bits ||= []).empty? val = read(:octet) @bits = (0..7).map{|i| (val & (1 << i)) != 0 } end @bits.shift else raise Qrack::InvalidTypeError, "Cannot read data of type #{type}" end end types.size == 1 ? values.first : values end def write type, data case type when :octet _write(data, 'C') when :short _write(data, 'n') when :long _write(data, 'N') when :longlong lower = data & 0xffffffff upper = (data & ~0xffffffff) >> 32 _write([upper, lower], 'NN') when :shortstr data = (data || '').to_s _write([data.bytesize, data], 'Ca*') when :longstr if data.is_a? Hash write(:table, data) else data = (data || '').to_s _write([data.bytesize, data], 'Na*') end when :timestamp write(:longlong, data.to_i) when :table data ||= {} write :longstr, (data.inject(Buffer.new) do |table, (key, value)| table.write(:shortstr, key.to_s) case value when String table.write(:octet, 83) # 'S' table.write(:longstr, value.to_s) when Fixnum table.write(:octet, 73) # 'I' table.write(:long, value) when Float table.write(:octet, 68) # 'D' # XXX there's gotta be a better way to do this.. exp = value.to_s.split('.').last.bytesize num = value * 10**exp table.write(:octet, exp) table.write(:long, num) when Time table.write(:octet, 84) # 'T' table.write(:timestamp, value) when Hash table.write(:octet, 70) # 'F' table.write(:table, value) end table end) when :bit [*data].to_enum(:each_slice, 8).each{|bits| write(:octet, bits.enum_with_index.inject(0){ |byte, (bit, i)| byte |= (1 << i) if bit byte }) } when :properties values = [] data.enum_with_index.inject(0) do |short, ((type, value), i)| n = i % 15 last = i+1 == data.size if (n == 0 and i != 0) or last if data.size > i+1 short |= (1 << 0) elsif last and value values << [type,value] short |= 1<<(15-n) end write(:short, short) short = 0 end if value and !last values << [type,value] short |= 1<<(15-n) end short end values.each do |type, value| write(type, value) unless type == :bit end else raise Qrack::InvalidTypeError, "Cannot write data of type #{type}" end self end def extract begin cur_data, cur_pos = @data.clone, @pos yield self rescue Qrack::BufferOverflowError @data, @pos = cur_data, cur_pos nil end end def _read(size, pack = nil) if @data.is_a?(Qrack::Client) raw = @data.read(size) return raw if raw.nil? or pack.nil? return raw.unpack(pack).first end if @pos + size > length raise Qrack::BufferOverflowError else data = @data[@pos,size] @data[@pos,size] = '' if pack data = data.unpack(pack) data = data.pop if data.size == 1 end data end end def _write data, pack = nil data = [*data].pack(pack) if pack @data[@pos,0] = data @pos += data.bytesize end end end end bunny-0.7.8/lib/qrack/client.rb0000644000076400007640000001604211704323672015377 0ustar pravipravi# encoding: utf-8 begin # try loading AMQ::Client::Setttings form the amq client gem, if it has been already loaded # this avoids "warning: already initialized constant AMQP_PORTS" require "amq/client/settings" rescue LoadError require "qrack/amq-client-url" end module Qrack class ClientTimeout < Timeout::Error; end class ConnectionTimeout < Timeout::Error; end class FrameTimeout < Timeout::Error; end # Client ancestor class class Client CONNECT_TIMEOUT = 5.0 RETRY_DELAY = 10.0 attr_reader :status, :host, :vhost, :port, :logging, :spec, :heartbeat attr_accessor :channel, :logfile, :exchanges, :queues, :channels, :message_in, :message_out, :connecting # Temporary hack to make Bunny 0.7 work with port number in AMQP URL. # This is not necessary on Bunny 0.8 as it removes support of AMQP 0.8. attr_reader :__opts__ def initialize(connection_string_or_opts = Hash.new, opts = Hash.new) opts = case connection_string_or_opts when String then AMQ::Client::Settings.parse_amqp_url(connection_string_or_opts) when Hash then connection_string_or_opts else Hash.new end.merge(opts) # Temporary hack to make Bunny 0.7 work with port number in AMQP URL. # This is not necessary on Bunny 0.8 as it removes support of AMQP 0.8. @__opts__ = opts @host = opts[:host] || 'localhost' @user = opts[:user] || 'guest' @pass = opts[:pass] || 'guest' @vhost = opts[:vhost] || '/' @logfile = opts[:logfile] || nil @logging = opts[:logging] || false @ssl = opts[:ssl] || false @verify_ssl = opts[:verify_ssl].nil? || opts[:verify_ssl] @status = :not_connected @frame_max = opts[:frame_max] || 131072 @channel_max = opts[:channel_max] || 0 @heartbeat = opts[:heartbeat] || 0 @connect_timeout = opts[:connect_timeout] || CONNECT_TIMEOUT @read_write_timeout = opts[:socket_timeout] @read_write_timeout = nil if @read_write_timeout == 0 @disconnect_timeout = @read_write_timeout || @connect_timeout @logger = nil create_logger if @logging @message_in = false @message_out = false @connecting = false @channels ||= [] # Create channel 0 @channel = create_channel() @exchanges ||= {} @queues ||= {} end # Closes all active communication channels and connection. If an error occurs a @Bunny::ProtocolError@ is raised. If successful, @Client.status@ is set to @:not_connected@. # @return [Symbol] @:not_connected@ if successful. def close return if @socket.nil? || @socket.closed? # Close all active channels channels.each do |c| Bunny::Timer::timeout(@disconnect_timeout) { c.close } if c.open? end # Close connection to AMQP server Bunny::Timer::timeout(@disconnect_timeout) { close_connection } rescue Exception # http://cheezburger.com/Asset/View/4033311488 ensure # Clear the channels @channels = [] # Create channel 0 @channel = create_channel() # Close TCP Socket close_socket end alias stop close def connected? status == :connected end def connecting? connecting end def logging=(bool) @logging = bool create_logger if @logging end def next_payload(options = {}) res = next_frame(options) res.payload if res end alias next_method next_payload def read(*args) send_command(:read, *args) # Got a SIGINT while waiting; give any traps a chance to run rescue Errno::EINTR retry end # Checks to see whether or not an undeliverable message has been returned as a result of a publish # with the :immediate or :mandatory options. # @param [Hash] opts Options. # @option opts [Numeric] :timeout (0.1) The method will wait for a return message until this timeout interval is reached. # @return [Hash] @{:header => nil, :payload => :no_return, :return_details => nil}@ if message is not returned before timeout. @{:header, :return_details, :payload}@ if message is returned. @:return_details@ is a hash @{:reply_code, :reply_text, :exchange, :routing_key}@. def returned_message(opts = {}) begin frame = next_frame(:timeout => opts[:timeout] || 0.1) rescue Qrack::FrameTimeout return {:header => nil, :payload => :no_return, :return_details => nil} end method = frame.payload header = next_payload # If maximum frame size is smaller than message payload body then message # will have a message header and several message bodies msg = '' while msg.length < header.size msg << next_payload end # Return the message and related info {:header => header, :payload => msg, :return_details => method.arguments} end def switch_channel(chann) if (0...channels.size).include? chann @channel = channels[chann] chann else raise RuntimeError, "Invalid channel number - #{chann}" end end def write(*args) send_command(:write, *args) end private def close_socket(reason=nil) # Close the socket. The server is not considered dead. @socket.close if @socket and not @socket.closed? @socket = nil @status = :not_connected end def create_logger @logfile ? @logger = Logger.new("#{logfile}") : @logger = Logger.new(STDOUT) @logger.level = Logger::INFO @logger.datetime_format = "%Y-%m-%d %H:%M:%S" end def send_command(cmd, *args) begin raise Bunny::ConnectionError, 'No connection - socket has not been created' if !@socket if @read_write_timeout Bunny::Timer::timeout(@read_write_timeout, Qrack::ClientTimeout) do @socket.__send__(cmd, *args) end else @socket.__send__(cmd, *args) end rescue Errno::EPIPE, Errno::EAGAIN, Qrack::ClientTimeout, IOError => e # Ensure we close the socket when we are down to prevent further # attempts to write to a closed socket close_socket raise Bunny::ServerDownError, e.message end end def socket return @socket if @socket and (@status == :connected) and not @socket.closed? begin # Attempt to connect. @socket = Bunny::Timer::timeout(@connect_timeout, ConnectionTimeout) do TCPSocket.new(host, port) end if Socket.constants.include?('TCP_NODELAY') || Socket.constants.include?(:TCP_NODELAY) @socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 end if @ssl require 'openssl' unless defined? OpenSSL::SSL @socket = OpenSSL::SSL::SSLSocket.new(@socket) @socket.sync_close = true @socket.connect @socket.post_connection_check(host) if @verify_ssl @socket end rescue => e @status = :not_connected raise Bunny::ServerDownError, e.message end @socket end end end bunny-0.7.8/lib/qrack/queue.rb0000644000076400007640000000216411704323672015245 0ustar pravipravi# encoding: utf-8 module Qrack # Queue ancestor class class Queue # @return [AMQ::Client::Consumer] Default consumer (registered with {Queue#subscribe}). attr_accessor :default_consumer attr_reader :name, :client attr_accessor :delivery_tag # Returns consumer count from {Queue#status}. def consumer_count s = status s[:consumer_count] end # Returns message count from {Queue#status}. def message_count s = status s[:message_count] end # Publishes a message to the queue via the default nameless '' direct exchange. # @return [NilClass] nil # @deprecated # @note This method will be removed before 0.8 release. def publish(data, opts = {}) Bunny.deprecation_warning("Qrack::Queue#publish", "0.8", "Use direct_exchange = bunny.exchange(''); direct_exchange.publish('message', key: queue.name) if you want to publish directly to one given queue. For more informations see https://github.com/ruby-amqp/bunny/issues/15 and for more theoretical explanation check http://bit.ly/nOF1CK") exchange.publish(data, opts) end end end bunny-0.7.8/lib/qrack/qrack09.rb0000644000076400007640000000055011704323672015370 0ustar pravipravi# encoding: utf-8 $: << File.expand_path(File.dirname(__FILE__)) require 'protocol/spec09' require 'protocol/protocol09' require 'transport/buffer09' require 'transport/frame09' require 'qrack/client' require 'qrack/channel' require 'qrack/queue' require 'bunny/consumer' require 'qrack/errors' module Qrack include Protocol09 include Transport09 end bunny-0.7.8/lib/qrack/errors.rb0000644000076400007640000000017311704323672015433 0ustar pravipravimodule Qrack # Errors class BufferOverflowError < StandardError; end class InvalidTypeError < StandardError; end end bunny-0.7.8/lib/qrack/subscription.rb0000644000076400007640000000573511704323672016654 0ustar pravipravi# encoding: utf-8 ################################################# # WARNING: THIS CLASS IS DEPRECATED, DO NOT # # USE IT DIRECTLY! USE BUNNY::CONSUMER INSTEAD! # ################################################# module Qrack # Subscription ancestor class # @deprecated class Subscription attr_accessor :consumer_tag, :delivery_tag, :message_max, :timeout, :ack, :exclusive attr_reader :client, :queue, :message_count def initialize(client, queue, opts = {}) @client = client @queue = queue # Get timeout value @timeout = opts[:timeout] || nil # Get maximum amount of messages to process @message_max = opts[:message_max] || nil # If a consumer tag is not passed in the server will generate one @consumer_tag = opts[:consumer_tag] || nil # Ignore the :nowait option if passed, otherwise program will hang waiting for a # response from the server causing an error. opts.delete(:nowait) # Do we want to have to provide an acknowledgement? @ack = opts[:ack] || nil # Does this consumer want exclusive use of the queue? @exclusive = opts[:exclusive] || false # Initialize message counter @message_count = 0 # Store options @opts = opts end def start(&blk) # Do not process any messages if zero message_max if message_max == 0 return end # Notify server about new consumer setup_consumer # Start subscription loop loop do begin method = client.next_method(:timeout => timeout) rescue Qrack::FrameTimeout queue.unsubscribe break end # Increment message counter @message_count += 1 # get delivery tag to use for acknowledge queue.delivery_tag = method.delivery_tag if @ack header = client.next_payload # If maximum frame size is smaller than message payload body then message # will have a message header and several message bodies msg = '' while msg.length < header.size msg << client.next_payload end # If block present, pass the message info to the block for processing blk.call({:header => header, :payload => msg, :delivery_details => method.arguments}) if !blk.nil? # Exit loop if message_max condition met if (!message_max.nil? and message_count == message_max) # Stop consuming messages queue.unsubscribe() # Acknowledge receipt of the final message queue.ack() if @ack # Quit the loop break end # Have to do the ack here because the ack triggers the release of messages from the server # if you are using Client#qos prefetch and you will get extra messages sent through before # the unsubscribe takes effect to stop messages being sent to this consumer unless the ack is # deferred. queue.ack() if @ack end end end end bunny-0.7.8/lib/bunny/0000755000076400007640000000000011704323672013623 5ustar pravipravibunny-0.7.8/lib/bunny/queue09.rb0000644000076400007640000002751311704323672015455 0ustar pravipravi# encoding: utf-8 module Bunny # Queues store and forward messages. Queues can be configured in the server or created at runtime. # Queues must be attached to at least one exchange in order to receive messages from publishers. class Queue09 < Qrack::Queue def initialize(client, name, opts = {}) # check connection to server raise Bunny::ConnectionError, 'Not connected to server' if client.status == :not_connected @client = client @opts = opts @delivery_tag = nil # Queues without a given name are named by the server and are generally # bound to the process that created them. if !name opts = { :passive => false, :durable => false, :exclusive => true, :auto_delete => true, :deprecated_ticket => 0 }.merge(opts) end # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name || '', :nowait => false, :deprecated_ticket => 0 }.merge(opts) client.send_frame(Qrack::Protocol09::Queue::Declare.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol09::Queue::DeclareOk, "Error declaring queue #{name}") @name = method.queue client.queues[@name] = self end # @return [Bunny::Consumer] Default consumer associated with this queue (if any), or nil # @note Default consumer is the one registered with the convenience {Bunny::Queue#subscribe} method. It has no special properties of any kind. # @see Queue#subscribe # @see Bunny::Consumer # @api public def default_consumer @default_consumer end # @return [Class] # @private def self.consumer_class # Bunny::Consumer Bunny::Subscription09 end # self.consumer_class # Acknowledges one or more messages delivered via the _Deliver_ or _Get_-_Ok_ methods. The client can # ask to confirm a single message or a set of messages up to and including a specific message. # # @option opts [String] :delivery_tag # # @option opts [Boolean] :multiple (false) # If set to @true@, the delivery tag is treated as "up to and including", # so that the client can acknowledge multiple messages with a single method. # If set to @false@, the delivery tag refers to a single message. # If the multiple field is @true@, and the delivery tag is zero, # tells the server to acknowledge all outstanding messages. def ack(opts = {}) # Set delivery tag if delivery_tag.nil? and opts[:delivery_tag].nil? raise Bunny::AcknowledgementError, "No delivery tag received" else self.delivery_tag = opts[:delivery_tag] if delivery_tag.nil? end opts = {:delivery_tag => delivery_tag, :multiple => false}.merge(opts) client.send_frame(Qrack::Protocol09::Basic::Ack.new(opts)) # reset delivery tag self.delivery_tag = nil end # Binds a queue to an exchange. Until a queue is bound it won't receive # any messages. Queues are bound to the direct exchange '' by default. # If error occurs, a {Bunny::ProtocolError} is raised. # # @option opts [String] :key # Specifies the routing key for the binding. The routing key is used # for routing messages depending on the exchange configuration. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @return [Symbol] @:bind_ok@ if successful. def bind(exchange, opts = {}) exchange = exchange.respond_to?(:name) ? exchange.name : exchange # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name, :exchange => exchange, :routing_key => opts.delete(:key), :nowait => false, :deprecated_ticket => 0 }.merge(opts) client.send_frame(Qrack::Protocol09::Queue::Bind.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol09::Queue::BindOk, "Error binding queue: #{name} to exchange: #{exchange}") # return message :bind_ok end # Requests that a queue is deleted from broker/server. When a queue is deleted any pending messages # are sent to a dead-letter queue if this is defined in the server configuration. Removes reference # from queues if successful. If an error occurs raises @Bunny::ProtocolError@. # # @option opts [Boolean] :if_unused (false) # If set to @true@, the server will only delete the queue if it has no consumers. # If the queue has consumers the server does not delete it but raises a channel exception instead. # # @option opts [Boolean] :if_empty (false) # If set to @true@, the server will only delete the queue if it has no messages. # If the queue is not empty the server raises a channel exception. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @return [Symbol] @:delete_ok@ if successful def delete(opts = {}) # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name, :nowait => false, :deprecated_ticket => 0 }.merge(opts) client.send_frame(Qrack::Protocol09::Queue::Delete.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol09::Queue::DeleteOk, "Error deleting queue #{name}") client.queues.delete(name) # return confirmation :delete_ok end # Gets a message from a queue in a synchronous way. If error occurs, raises _Bunny_::_ProtocolError_. # # @option opts [Boolean] :ack (false) # If set to @false@, the server does not expect an acknowledgement message # from the client. If set to @true@, the server expects an acknowledgement # message from the client and will re-queue the message if it does not receive # one within a time specified by the server. # # @return [Hash] Hash with @:header@, @:payload@ and @:delivery_details@ keys. @:delivery_details@ is a hash @:consumer_tag@, @:delivery_tag@, @:redelivered@, @:exchange@ and @:routing_key@. If the queue is empty the returned hash will contain: @{:header => nil, :payload => :queue_empty, :delivery_details => nil}@. N.B. If a block is provided then the hash will be passed into the block and the return value will be nil. def pop(opts = {}, &blk) opts = { :queue => name, :consumer_tag => name, :no_ack => !opts[:ack], :nowait => true, :deprecated_ticket => 0 }.merge(opts) client.send_frame(Qrack::Protocol09::Basic::Get.new(opts)) method = client.next_method if method.is_a?(Qrack::Protocol09::Basic::GetEmpty) then queue_empty = true elsif !method.is_a?(Qrack::Protocol09::Basic::GetOk) raise Bunny::ProtocolError, "Error getting message from queue #{name}" end if !queue_empty # get delivery tag to use for acknowledge self.delivery_tag = method.delivery_tag if opts[:ack] header = client.next_payload # If maximum frame size is smaller than message payload body then message # will have a message header and several message bodies msg = '' while msg.length < header.size msg << client.next_payload end msg_hash = {:header => header, :payload => msg, :delivery_details => method.arguments} else msg_hash = {:header => nil, :payload => :queue_empty, :delivery_details => nil} end # Pass message hash to block or return message hash blk ? blk.call(msg_hash) : msg_hash end # Removes all messages from a queue. It does not cancel consumers. Purged messages are deleted # without any formal "undo" mechanism. If an error occurs raises {Bunny::ProtocolError}. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @return [Symbol] @:purge_ok@ if successful def purge(opts = {}) # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name, :nowait => false, :deprecated_ticket => 0 }.merge(opts) client.send_frame(Qrack::Protocol09::Queue::Purge.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol09::Queue::PurgeOk, "Error purging queue #{name}") # return confirmation :purge_ok end # @return [Hash] Hash with keys @:message_count@ and @consumer_count@. def status opts = { :queue => name, :passive => true, :deprecated_ticket => 0 } client.send_frame(Qrack::Protocol09::Queue::Declare.new(opts)) method = client.next_method {:message_count => method.message_count, :consumer_count => method.consumer_count} end def subscribe(opts = {}, &blk) raise RuntimeError.new("This queue already has default consumer. Please instantiate Bunny::Consumer directly and call its #consume method to register additional consumers.") if @default_consumer && ! opts[:consumer_tag] # Create a subscription. @default_consumer = self.class.consumer_class.new(client, self, opts) @default_consumer.consume(&blk) end # Removes a queue binding from an exchange. If error occurs, a _Bunny_::_ProtocolError_ is raised. # # @option opts [String] :key # Specifies the routing key for the binding. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @return [Symbol] @:unbind_ok@ if successful. def unbind(exchange, opts = {}) exchange = exchange.respond_to?(:name) ? exchange.name : exchange # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name, :exchange => exchange, :routing_key => opts.delete(:key), :nowait => false, :deprecated_ticket => 0 }.merge(opts) client.send_frame(Qrack::Protocol09::Queue::Unbind.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol09::Queue::UnbindOk, "Error unbinding queue #{name}") # return message :unbind_ok end # Cancels a consumer. This does not affect already delivered messages, but it does mean # the server will not send any more messages for that consumer. # # @option opts [String] :consumer_tag # Specifies the identifier for the consumer. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @return [Symbol] @:unsubscribe_ok@ if successful def unsubscribe(opts = {}) # Default consumer_tag from subscription if not passed in consumer_tag = @default_consumer ? @default_consumer.consumer_tag : opts[:consumer_tag] # Must have consumer tag to tell server what to unsubscribe raise Bunny::UnsubscribeError, "No consumer tag received" if !consumer_tag # Cancel consumer client.send_frame(Qrack::Protocol09::Basic::Cancel.new(:consumer_tag => consumer_tag, :nowait => false)) method = client.next_method client.check_response(method, Qrack::Protocol09::Basic::CancelOk, "Error unsubscribing from queue #{name}") # Reset subscription @default_consumer = nil # Return confirmation :unsubscribe_ok end private def exchange @exchange ||= Bunny::Exchange09.new(client, '', :type => :direct, :key => name, :reserved_1 => 0, :reserved_2 => false, :reserved_3 => false) end end end bunny-0.7.8/lib/bunny/version.rb0000644000076400007640000000007011704323672015632 0ustar pravipravi# encoding: utf-8 module Bunny VERSION = "0.7.8" end bunny-0.7.8/lib/bunny/exchange09.rb0000644000076400007640000001456011704323672016111 0ustar pravipravi# encoding: utf-8 module Bunny # *Exchanges* are the routing and distribution hub of AMQP. All messages that Bunny sends # to an AMQP broker/server @have_to pass through an exchange in order to be routed to a # destination queue. The AMQP specification defines the types of exchange that you can create. # # At the time of writing there are four (4) types of exchange defined: # # * @:direct@ # * @:fanout@ # * @:topic@ # * @:headers@ # # AMQP-compliant brokers/servers are required to provide default exchanges for the @direct@ and # @fanout@ exchange types. All default exchanges are prefixed with @'amq.'@, for example: # # * @amq.direct@ # * @amq.fanout@ # * @amq.topic@ # * @amq.match@ or @amq.headers@ # # If you want more information about exchanges, please consult the documentation for your # target broker/server or visit the "AMQP website":http://www.amqp.org to find the version of the # specification that applies to your target broker/server. class Exchange09 attr_reader :client, :type, :name, :opts, :key def initialize(client, name, opts = {}) # check connection to server raise Bunny::ConnectionError, 'Not connected to server' if client.status == :not_connected @client, @name, @opts = client, name, opts # set up the exchange type catering for default names if name =~ /^amq\.(.+)$/ predeclared = true new_type = $1 # handle 'amq.match' default new_type = 'headers' if new_type == 'match' @type = new_type.to_sym else @type = opts[:type] || :direct end @key = opts[:key] @client.exchanges[@name] ||= self # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) unless predeclared or name == '' opts = { :exchange => name, :type => type, :nowait => false, :deprecated_ticket => 0, :deprecated_auto_delete => false, :deprecated_internal => false }.merge(opts) client.send_frame(Qrack::Protocol09::Exchange::Declare.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol09::Exchange::DeclareOk, "Error declaring exchange #{name}: type = #{type}") end end # Requests that an exchange is deleted from broker/server. Removes reference from exchanges # if successful. If an error occurs raises {Bunny::ProtocolError}. # # @option opts [Boolean] :if_unused (false) # If set to @true@, the server will only delete the exchange if it has no queue bindings. If the exchange has queue bindings the server does not delete it but raises a channel exception instead. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @return [Symbol] @:delete_ok@ if successful. def delete(opts = {}) # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :exchange => name, :nowait => false, :deprecated_ticket => 0 }.merge(opts) client.send_frame(Qrack::Protocol09::Exchange::Delete.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol09::Exchange::DeleteOk, "Error deleting exchange #{name}") client.exchanges.delete(name) # return confirmation :delete_ok end # Publishes a message to a specific exchange. The message will be routed to queues as defined # by the exchange configuration and distributed to any active consumers when the transaction, # if any, is committed. # # @option opts [String] :key # Specifies the routing key for the message. The routing key is # used for routing messages depending on the exchange configuration. # # @option opts [String] :content_type # Specifies the content type for the message. # # @option opts [Boolean] :mandatory (false) # Tells the server how to react if the message cannot be routed to a queue. # If set to @true@, the server will return an unroutable message # with a Return method. If this flag is zero, the server silently drops the message. # # @option opts [Boolean] :immediate (false) # Tells the server how to react if the message cannot be routed to a queue consumer # immediately. If set to @true@, the server will return an undeliverable message with # a Return method. If set to @false@, the server will queue the message, but with no # guarantee that it will ever be consumed. # # @option opts [Boolean] :persistent (false) # Tells the server whether to persist the message. If set to @true@, the message will # be persisted to disk and not lost if the server restarts. If set to @false@, the message # will not be persisted across server restart. Setting to @true@ incurs a performance penalty # as there is an extra cost associated with disk access. # # @return [NilClass] nil def publish(data, opts = {}) opts = opts.dup out = [] # Set up options routing_key = opts.delete(:key) || key mandatory = opts.delete(:mandatory) immediate = opts.delete(:immediate) delivery_mode = opts.delete(:persistent) ? 2 : 1 content_type = opts.delete(:content_type) || 'application/octet-stream' out << Qrack::Protocol09::Basic::Publish.new({ :exchange => name, :routing_key => routing_key, :mandatory => mandatory, :immediate => immediate, :deprecated_ticket => 0 }) data = data.to_s out << Qrack::Protocol09::Header.new( Qrack::Protocol09::Basic, data.bytesize, { :content_type => content_type, :delivery_mode => delivery_mode, :priority => 0 }.merge(opts) ) out << Qrack::Transport09::Body.new(data) client.send_frame(*out) end end end bunny-0.7.8/lib/bunny/channel08.rb0000644000076400007640000000145611704323672015736 0ustar pravipravi# encoding: utf-8 module Bunny class Channel < Qrack::Channel def initialize(client) super end def open client.channel = self client.send_frame(Qrack::Protocol::Channel::Open.new) method = client.next_method client.check_response(method, Qrack::Protocol::Channel::OpenOk, "Cannot open channel #{number}") @active = true :open_ok end def close client.channel = self client.send_frame(Qrack::Protocol::Channel::Close.new(:reply_code => 200, :reply_text => 'bye', :method_id => 0, :class_id => 0)) method = client.next_method client.check_response(method, Qrack::Protocol::Channel::CloseOk, "Error closing channel #{number}") @active = false :close_ok end def open? active end end end bunny-0.7.8/lib/bunny/client09.rb0000644000076400007640000003407611704323672015611 0ustar pravipravi# encoding: utf-8 module Bunny # The Client class provides the major Bunny API methods. class Client09 < Qrack::Client # Sets up a Bunny::Client object ready for connection to a broker. # {Client.status} is set to @:not_connected@. # # @option opts [String] :host ("localhost") # @option opts [Integer] :port (5672 or 5671 if :ssl set to true) # @option opts [String] :vhost ("/") # @option opts [String] :user ("guest") # @option opts [String] :pass ("guest") # @option opts [Boolean] :ssl (false) # If set to @true@, ssl encryption will be used and port will default to 5671. # @option opts [Boolean] :verify_ssl (true) # If ssl is enabled, this will cause OpenSSL to validate # the server certificate unless this parameter is set to @false@. # @option opts [String] :logfile (nil) # @option opts [Boolean] :logging (false) # If set to @true@, session information is sent to STDOUT if @:logfile@ # has not been specified. Otherwise, session information is written to @:logfile@. # @option opts [Integer] :frame_max (131072) # Maximum frame size in bytes. # @option opts [Integer] :channel_max (0) # Maximum number of channels. Defaults to 0 which means no maximum. # @option opts [Integer] :heartbeat (0) # Number of seconds. Defaults to 0 which means no heartbeat. # @option opts [Integer] :connect_timeout (5) # Number of seconds before {Qrack::ConnectionTimeout} is raised.@ def initialize(connection_string_or_opts = Hash.new, opts = Hash.new) super @spec = '0-9-1' @port = self.__opts__[:port] || (self.__opts__[:ssl] ? Qrack::Protocol09::SSL_PORT : Qrack::Protocol09::PORT) end # Checks response from AMQP methods and takes appropriate action def check_response(received_method, expected_method, err_msg, err_class = Bunny::ProtocolError) case when received_method.is_a?(Qrack::Protocol09::Connection::Close) # Clean up the socket close_socket raise Bunny::ForcedConnectionCloseError, "Error Reply Code: #{received_method.reply_code}\nError Reply Text: #{received_method.reply_text}" when received_method.is_a?(Qrack::Protocol09::Channel::Close) # Clean up the channel channel.active = false raise Bunny::ForcedChannelCloseError, "Error Reply Code: #{received_method.reply_code}\nError Reply Text: #{received_method.reply_text}" when !received_method.is_a?(expected_method) raise err_class, err_msg else :response_ok end end def close_connection # Set client channel to zero switch_channel(0) send_frame(Qrack::Protocol09::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)) method = next_method check_response(method, Qrack::Protocol09::Connection::CloseOk, "Error closing connection") end def create_channel channels.each do |c| return c if (!c.open? and c.number != 0) end # If no channel to re-use instantiate new one Bunny::Channel09.new(self) end # Declares an exchange to the broker/server. If the exchange does not exist, a new one is created # using the arguments passed in. If the exchange already exists, a reference to it is created, provided # that the arguments passed in do not conflict with the existing attributes of the exchange. If an error # occurs a _Bunny_::_ProtocolError_ is raised. # # @option opts [Symbol] :type (:direct) # One of :direct@, @:fanout@, @:topic@, or @:headers@. # # @option opts [Boolean] :passive # If set to @true@, the server will not create the exchange. # The client can use this to check whether an exchange exists without modifying the server state. # # @option opts [Boolean] :durable (false) # If set to @true@ when creating a new exchange, the exchange # will be marked as durable. Durable exchanges remain active # when a server restarts. Non-durable exchanges (transient exchanges) # are purged if/when a server restarts. # # @option opts [Boolean] :auto_delete (false) # If set to @true@, the exchange is deleted when all queues have finished using it. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @return [Bunny::Exchange09] def exchange(name, opts = {}) exchanges[name] || Bunny::Exchange09.new(self, name, opts) end def init_connection write(Qrack::Protocol09::HEADER) write([0, Qrack::Protocol09::VERSION_MAJOR, Qrack::Protocol09::VERSION_MINOR, Qrack::Protocol09::REVISION].pack('C4')) frame = next_frame if frame.nil? or !frame.payload.is_a?(Qrack::Protocol09::Connection::Start) raise Bunny::ProtocolError, 'Connection initiation failed' end end def next_frame(opts = {}) frame = nil case when channel.frame_buffer.size > 0 frame = channel.frame_buffer.shift when (timeout = opts[:timeout]) && timeout > 0 Bunny::Timer::timeout(timeout, Qrack::FrameTimeout) do frame = Qrack::Transport09::Frame.parse(buffer) end else frame = Qrack::Transport09::Frame.parse(buffer) end @logger.info("received") { frame } if @logging raise Bunny::ConnectionError, 'No connection to server' if (frame.nil? and !connecting?) # Monitor server activity and discard heartbeats @message_in = true case when frame.is_a?(Qrack::Transport09::Heartbeat) next_frame(opts) when frame.nil? frame when ((frame.channel != channel.number) and (frame.channel != 0)) channel.frame_buffer << frame next_frame(opts) else frame end end def open_connection client_props = { :platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/ruby-amqp/bunny', :version => VERSION } start_opts = { :client_properties => client_props, :mechanism => 'PLAIN', :response => "\0" + @user + "\0" + @pass, :locale => 'en_US' } send_frame(Qrack::Protocol09::Connection::StartOk.new(start_opts)) frame = next_frame raise Bunny::ProtocolError, "Connection failed - user: #{@user}" if frame.nil? method = frame.payload if method.is_a?(Qrack::Protocol09::Connection::Tune) send_frame(Qrack::Protocol09::Connection::TuneOk.new(:channel_max => @channel_max, :frame_max => @frame_max, :heartbeat => @heartbeat)) end send_frame(Qrack::Protocol09::Connection::Open.new(:virtual_host => @vhost, :reserved_1 => 0, :reserved_2 => false)) raise Bunny::ProtocolError, 'Cannot open connection' unless next_method.is_a?(Qrack::Protocol09::Connection::OpenOk) end # Requests a specific quality of service. The QoS can be specified for the current channel # or for all channels on the connection. The particular properties and semantics of a QoS # method always depend on the content class semantics. Though the QoS method could in principle # apply to both peers, it is currently meaningful only for the server. # # @option opts [Integer] :prefetch_size (0) # Size in number of octets. The client can request that messages be sent in advance # so that when the client finishes processing a message, the following message is # already held locally, rather than needing to be sent down the channel. refetching # gives a performance improvement. This field specifies the prefetch window size # in octets. The server will send a message in advance if it is equal to or smaller # in size than the available prefetch size (and also falls into other prefetch limits). # May be set to zero, meaning "no specific limit", although other prefetch limits may # still apply. The prefetch-size is ignored if the no-ack option is set. # # @option opts [Integer] :prefetch_count (1) # Number of messages to prefetch. Specifies a prefetch window in terms of whole messages. # This field may be used in combination with the prefetch-size field; a message will only # be sent in advance if both prefetch windows (and those at the channel and connection level) # allow it. The prefetch-count is ignored if the no-ack option is set. # # @option opts [Boolean] :global (false) # By default the QoS settings apply to the current channel only. If set to true, # they are applied to the entire connection. # # @return [Symbol] @:qos_ok@ if successful. def qos(opts = {}) send_frame(Qrack::Protocol09::Basic::Qos.new({ :prefetch_size => 0, :prefetch_count => 1, :global => false }.merge(opts))) method = next_method check_response(method, Qrack::Protocol09::Basic::QosOk, "Error specifying Quality of Service") # return confirmation :qos_ok end # Declares a queue to the broker/server. If the queue does not exist, a new one is created # using the arguments passed in. If the queue already exists, a reference to it is created, provided # that the arguments passed in do not conflict with the existing attributes of the queue. If an error # occurs a {Bunny::ProtocolError} is raised. # # @option opts [Boolean] :passive (false) # If set to @true@, the server will not create the queue. The client can use this to check # whether a queue exists without modifying the server state. # # @option opts [Boolean] :durable (false) # If set to @true@ when creating a new queue, the queue will be marked as durable. # Durable queues remain active when a server restarts. Non-durable queues (transient ones) # are purged if/when a server restarts. Note that durable queues do not necessarily hold # persistent messages, although it does not make sense to send persistent messages # to a transient queue. # # @option opts [Boolean] :exclusive (false) # If set to @true@, requests an exclusive queue. Exclusive queues may only be consumed # from by the current connection. Setting the 'exclusive' flag always implies 'auto-delete'. # # @option opts [Boolean] :auto_delete (false) # If set to @true@, the queue is deleted when all consumers have finished using it. # Last consumer can be cancelled either explicitly or because its channel is closed. # If there has never been a consumer on the queue, it is not deleted. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @return [Bunny::Queue09] def queue(name = nil, opts = {}) if name.is_a?(Hash) opts = name name = nil end # Queue is responsible for placing itself in the list of queues queues[name] || Bunny::Queue09.new(self, name, opts) end # Asks the broker to redeliver all unacknowledged messages on a specified channel. Zero or # more messages may be redelivered. # # @option opts [Boolean] :requeue (false) # If set to @false@, the message will be redelivered to the original recipient. # If set to @true@, the server will attempt to requeue the message, potentially # then delivering it to an alternative subscriber. def recover(opts = {}) send_frame(Qrack::Protocol09::Basic::Recover.new({ :requeue => false }.merge(opts))) end def send_frame(*args) args.each do |data| data = data.to_frame(channel.number) unless data.is_a?(Qrack::Transport09::Frame) data.channel = channel.number @logger.info("send") { data } if @logging write(data.to_s) # Monitor client activity for heartbeat purposes @message_out = true end nil end def send_heartbeat # Create a new heartbeat frame hb = Qrack::Transport09::Heartbeat.new('') # Channel 0 must be used switch_channel(0) if @channel.number > 0 # Send the heartbeat to server send_frame(hb) end # Opens a communication channel and starts a connection. If an error occurs, a # {Bunny::ProtocolError} is raised. If successful, {Client.status} is set to @:connected@. # # @return [Symbol] @:connected@ if successful. def start_session @connecting = true # Create/get socket socket # Initiate connection init_connection # Open connection open_connection # Open another channel because channel zero is used for specific purposes c = create_channel() c.open @connecting = false # return status @status = :connected end alias start start_session # This method commits all messages published and acknowledged in # the current transaction. A new transaction starts immediately # after a commit. # # @return [Symbol] @:commit_ok@ if successful. def tx_commit send_frame(Qrack::Protocol09::Tx::Commit.new()) method = next_method check_response(method, Qrack::Protocol09::Tx::CommitOk, "Error commiting transaction") # return confirmation :commit_ok end # This method abandons all messages published and acknowledged in # the current transaction. A new transaction starts immediately # after a rollback. # # @return [Symbol] @:rollback_ok@ if successful. def tx_rollback send_frame(Qrack::Protocol09::Tx::Rollback.new()) method = next_method check_response(method, Qrack::Protocol09::Tx::RollbackOk, "Error rolling back transaction") # return confirmation :rollback_ok end # This method sets the channel to use standard transactions. The # client must use this method at least once on a channel before # using the Commit or Rollback methods. # # @return [Symbol] @:select_ok@ if successful. def tx_select send_frame(Qrack::Protocol09::Tx::Select.new()) method = next_method check_response(method, Qrack::Protocol09::Tx::SelectOk, "Error initiating transactions for current channel") # return confirmation :select_ok end private def buffer @buffer ||= Qrack::Transport09::Buffer.new(self) end end end bunny-0.7.8/lib/bunny/consumer.rb0000644000076400007640000000220011704323672015775 0ustar pravipravi# encoding: utf-8 #################################### # NOTE: THIS CLASS IS HERE TO MAKE # # TRANSITION TO AMQ CLIENT EASIER # #################################### require "qrack/subscription" # NOTE: This file is rather a temporary hack to fix # https://github.com/ruby-amqp/bunny/issues/9 then # some permanent solution. It's mostly copied from # the AMQP and AMQ Client gems. Later on we should # use AMQ Client directly and just inherit from # the AMQ::Client::Sync::Consumer class. module Bunny # AMQP consumers are entities that handle messages delivered # to them ("push API" as opposed to "pull API") by AMQP broker. # Every consumer is associated with a queue. Consumers can be # exclusive (no other consumers can be registered for the same # queue) or not (consumers share the queue). In the case of # multiple consumers per queue, messages are distributed in # round robin manner with respect to channel-level prefetch # setting). class Consumer < Qrack::Subscription def initialize(*args) super(*args) @consumer_tag ||= (1..32).to_a.shuffle.join end alias_method :consume, :start end end bunny-0.7.8/lib/bunny/channel09.rb0000644000076400007640000000147011704323672015733 0ustar pravipravi# encoding: utf-8 module Bunny class Channel09 < Qrack::Channel def initialize(client) super end def open client.channel = self client.send_frame(Qrack::Protocol09::Channel::Open.new) method = client.next_method client.check_response(method, Qrack::Protocol09::Channel::OpenOk, "Cannot open channel #{number}") @active = true :open_ok end def close client.channel = self client.send_frame(Qrack::Protocol09::Channel::Close.new(:reply_code => 200, :reply_text => 'bye', :method_id => 0, :class_id => 0)) method = client.next_method client.check_response(method, Qrack::Protocol09::Channel::CloseOk, "Error closing channel #{number}") @active = false :close_ok end def open? active end end end bunny-0.7.8/lib/bunny/subscription09.rb0000644000076400007640000000575211704323672017056 0ustar pravipravi# encoding: utf-8 module Bunny # Asks the server to start a "consumer", which is a transient request for messages from a specific # queue. Consumers last as long as the channel they were created on, or until the client cancels them # with an @unsubscribe@. Every time a message reaches the queue it is passed to the @blk@ for # processing. If error occurs, {Bunny::ProtocolError} is raised. # # @option opts [String] :consumer_tag # Specifies the identifier for the consumer. The consumer tag is # local to a connection, so two clients can use the same consumer tags. # If this option is not specified a server generated name is used. # # @option opts [Boolean] :ack (false) # If set to @false@, the server does not expect an acknowledgement message # from the client. If set to @true, the server expects an acknowledgement # message from the client and will re-queue the message if it does not # receive one within a time specified by the server. # # @option opts [Boolean] :exclusive (false) # Request exclusive consumer access, meaning only this consumer can access the queue. # # @option opts [Boolean] :nowait (false) # Ignored by Bunny, always @false@. # # @option opts [Numeric] :timeout # The subscribe loop will continue to wait for messages # until terminated (Ctrl-C or kill command) or this timeout interval is reached. # # @option opts [Integer] :message_max # When the required number of messages is processed subscribe loop is exited. # # h2. Operation # # Passes a hash of message information to the block, if one has been supplied. The hash contains # :header, :payload and :delivery_details. The structure of the data is as follows - # # :header has instance variables - # @klass # @size # @weight # @properties is a hash containing - # :content_type # :delivery_mode # :priority # # :payload contains the message contents # # :delivery details is a hash containing - # :consumer_tag # :delivery_tag # :redelivered # :exchange # :routing_key # # If the :timeout option is specified then the subscription will # automatically cease if the given number of seconds passes with no # message arriving. # # @example # my_queue.subscribe(timeout: 5) { |msg| puts msg[:payload] } # my_queue.subscribe(message_max: 10, ack: true) { |msg| puts msg[:payload] } class Subscription09 < Bunny::Consumer def setup_consumer subscription_options = { :deprecated_ticket => 0, :queue => queue.name, :consumer_tag => consumer_tag, :no_ack => !ack, :exclusive => exclusive, :nowait => false }.merge(@opts) client.send_frame(Qrack::Protocol09::Basic::Consume.new(subscription_options)) method = client.next_method client.check_response(method, Qrack::Protocol09::Basic::ConsumeOk, "Error subscribing to queue #{queue.name}") @consumer_tag = method.consumer_tag end end end bunny-0.7.8/lib/bunny/subscription08.rb0000644000076400007640000000553111704323672017050 0ustar pravipravi# encoding: utf-8 module Bunny =begin rdoc === DESCRIPTION: Asks the server to start a "consumer", which is a transient request for messages from a specific queue. Consumers last as long as the channel they were created on, or until the client cancels them with an _unsubscribe_. Every time a message reaches the queue it is passed to the _blk_ for processing. If error occurs, _Bunny_::_ProtocolError_ is raised. ==== OPTIONS: * :consumer_tag => '_tag_' - Specifies the identifier for the consumer. The consumer tag is local to a connection, so two clients can use the same consumer tags. If this option is not specified a server generated name is used. * :ack => false (_default_) or true - If set to _false_, the server does not expect an acknowledgement message from the client. If set to _true_, the server expects an acknowledgement message from the client and will re-queue the message if it does not receive one within a time specified by the server. * :exclusive => true or false (_default_) - Request exclusive consumer access, meaning only this consumer can access the queue. * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. * :timeout => number of seconds - The subscribe loop will continue to wait for messages until terminated (Ctrl-C or kill command) or this timeout interval is reached. * :message_max => max number messages to process - When the required number of messages is processed subscribe loop is exited. ==== OPERATION: Passes a hash of message information to the block, if one has been supplied. The hash contains :header, :payload and :delivery_details. The structure of the data is as follows - :header has instance variables - @klass @size @weight @properties is a hash containing - :content_type :delivery_mode :priority :payload contains the message contents :delivery details is a hash containing - :consumer_tag :delivery_tag :redelivered :exchange :routing_key If the :timeout option is specified then the subscription will automatically cease if the given number of seconds passes with no message arriving. ==== EXAMPLES my_queue.subscribe(:timeout => 5) {|msg| puts msg[:payload]} my_queue.subscribe(:message_max => 10, :ack => true) {|msg| puts msg[:payload]} =end class Subscription < Bunny::Consumer def setup_consumer subscription_options = { :queue => queue.name, :consumer_tag => consumer_tag, :no_ack => !ack, :exclusive => exclusive, :nowait => false }.merge(@opts) client.send_frame(Qrack::Protocol::Basic::Consume.new(subscription_options)) method = client.next_method client.check_response(method, Qrack::Protocol::Basic::ConsumeOk, "Error subscribing to queue #{queue.name}") @consumer_tag = method.consumer_tag end end end bunny-0.7.8/lib/bunny/exchange08.rb0000644000076400007640000001352711704323672016112 0ustar pravipravi# encoding: utf-8 module Bunny =begin rdoc === DESCRIPTION: *Exchanges* are the routing and distribution hub of AMQP. All messages that Bunny sends to an AMQP broker/server _have_ to pass through an exchange in order to be routed to a destination queue. The AMQP specification defines the types of exchange that you can create. At the time of writing there are four (4) types of exchange defined - * :direct * :fanout * :topic * :headers AMQP-compliant brokers/servers are required to provide default exchanges for the _direct_ and _fanout_ exchange types. All default exchanges are prefixed with 'amq.', for example - * amq.direct * amq.fanout * amq.topic * amq.match or amq.headers If you want more information about exchanges, please consult the documentation for your target broker/server or visit the {AMQP website}[http://www.amqp.org] to find the version of the specification that applies to your target broker/server. =end class Exchange attr_reader :client, :type, :name, :opts, :key def initialize(client, name, opts = {}) # check connection to server raise Bunny::ConnectionError, 'Not connected to server' if client.status == :not_connected @client, @name, @opts = client, name, opts # set up the exchange type catering for default names if name =~ /^amq\.(.+)$/ predeclared = true new_type = $1 # handle 'amq.match' default new_type = 'headers' if new_type == 'match' @type = new_type.to_sym else @type = opts[:type] || :direct end @key = opts[:key] @client.exchanges[@name] ||= self # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) unless predeclared or name == '' opts = { :exchange => name, :type => type, :nowait => false }.merge(opts) client.send_frame(Qrack::Protocol::Exchange::Declare.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol::Exchange::DeclareOk, "Error declaring exchange #{name}: type = #{type}") end end =begin rdoc === DESCRIPTION: Requests that an exchange is deleted from broker/server. Removes reference from exchanges if successful. If an error occurs raises _Bunny_::_ProtocolError_. ==== Options: * :if_unused => true or false (_default_) - If set to _true_, the server will only delete the exchange if it has no queue bindings. If the exchange has queue bindings the server does not delete it but raises a channel exception instead. * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. ==== Returns: :delete_ok if successful =end def delete(opts = {}) # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) client.send_frame(Qrack::Protocol::Exchange::Delete.new({ :exchange => name, :nowait => false }.merge(opts))) method = client.next_method client.check_response(method, Qrack::Protocol::Exchange::DeleteOk, "Error deleting exchange #{name}") client.exchanges.delete(name) # return confirmation :delete_ok end =begin rdoc === DESCRIPTION: Publishes a message to a specific exchange. The message will be routed to queues as defined by the exchange configuration and distributed to any active consumers when the transaction, if any, is committed. ==== OPTIONS: * :key => 'routing_key' - Specifies the routing key for the message. The routing key is used for routing messages depending on the exchange configuration. * :content_type => 'content/type' - Specifies the content type to use for the message. * :mandatory => true or false (_default_) - Tells the server how to react if the message cannot be routed to a queue. If set to _true_, the server will return an unroutable message with a Return method. If this flag is zero, the server silently drops the message. * :immediate => true or false (_default_) - Tells the server how to react if the message cannot be routed to a queue consumer immediately. If set to _true_, the server will return an undeliverable message with a Return method. If set to _false_, the server will queue the message, but with no guarantee that it will ever be consumed. * :persistent => true or false (_default_) - Tells the server whether to persist the message If set to _true_, the message will be persisted to disk and not lost if the server restarts. If set to _false_, the message will not be persisted across server restart. Setting to _true_ incurs a performance penalty as there is an extra cost associated with disk access. ==== RETURNS: nil =end def publish(data, opts = {}) opts = opts.dup out = [] # Set up options routing_key = opts.delete(:key) || key mandatory = opts.delete(:mandatory) immediate = opts.delete(:immediate) delivery_mode = opts.delete(:persistent) ? 2 : 1 content_type = opts.delete(:content_type) || 'application/octet-stream' out << Qrack::Protocol::Basic::Publish.new({ :exchange => name, :routing_key => routing_key, :mandatory => mandatory, :immediate => immediate }) data = data.to_s out << Qrack::Protocol::Header.new( Qrack::Protocol::Basic, data.bytesize, { :content_type => content_type, :delivery_mode => delivery_mode, :priority => 0 }.merge(opts) ) out << Qrack::Transport::Body.new(data) client.send_frame(*out) end end end bunny-0.7.8/lib/bunny/system_timer.rb0000644000076400007640000000031511704323672016673 0ustar pravipravi# encoding: utf-8 module Bunny # Used for ruby < 1.9.x class SystemTimer < ::SystemTimer def timeout(seconds, exception) timeout_after(seconds) do yield end end end endbunny-0.7.8/lib/bunny/client08.rb0000644000076400007640000003543411704323672015607 0ustar pravipravi# encoding: utf-8 module Bunny =begin rdoc === DESCRIPTION: The Client class provides the major Bunny API methods. =end class Client < Qrack::Client attr_accessor :ticket =begin rdoc === DESCRIPTION: Sets up a Bunny::Client object ready for connection to a broker/server. _Client_._status_ is set to :not_connected. ==== OPTIONS: * :host => '_hostname_' (default = 'localhost') * :port => _portno_ (default = 5672 or 5671 if :ssl set to true) * :vhost => '_vhostname_' (default = '/') * :user => '_username_' (default = 'guest') * :pass => '_password_' (default = 'guest') * :ssl => true or false (default = false) - If set to _true_, ssl encryption will be used and port will default to 5671. * :verify_ssl => true or false (default = true) - If ssl is enabled, this will cause OpenSSL to validate the server certificate unless this parameter is set to _false_. * :logfile => '_logfilepath_' (default = nil) * :logging => true or false (_default_) - If set to _true_, session information is sent to STDOUT if :logfile has not been specified. Otherwise, session information is written to :logfile. * :insist => true or false (_default_) - In a configuration with multiple load-sharing servers, the server may respond to a Connection::Open method with a Connection::Redirect. The insist option, if set to _true_, tells the server that the client is insisting on a connection to the specified server. * :frame_max => maximum frame size in bytes (default = 131072) * :channel_max => maximum number of channels (default = 0 no maximum) * :heartbeat => number of seconds (default = 0 no heartbeat) * :connect_timeout => number of seconds before Qrack::ConnectionTimeout is raised (default = 5) =end def initialize(connection_string_or_opts = Hash.new, opts = Hash.new) super @spec = '0-8' @port = self.__opts__[:port] || (self.__opts__[:ssl] ? Qrack::Protocol::SSL_PORT : Qrack::Protocol::PORT) @insist = self.__opts__[:insist] end =begin rdoc === DESCRIPTION: Checks response from AMQP methods and takes appropriate action =end def check_response(received_method, expected_method, err_msg, err_class = Bunny::ProtocolError) case when received_method.is_a?(Qrack::Protocol::Connection::Close) # Clean up the socket close_socket raise Bunny::ForcedConnectionCloseError, "Error Reply Code: #{received_method.reply_code}\nError Reply Text: #{received_method.reply_text}" when received_method.is_a?(Qrack::Protocol::Channel::Close) # Clean up the channel channel.active = false raise Bunny::ForcedChannelCloseError, "Error Reply Code: #{received_method.reply_code}\nError Reply Text: #{received_method.reply_text}" when !received_method.is_a?(expected_method) raise err_class, err_msg else :response_ok end end def close_connection # Set client channel to zero switch_channel(0) send_frame(Qrack::Protocol::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)) method = next_method check_response(method, Qrack::Protocol::Connection::CloseOk, "Error closing connection") end def create_channel channels.each do |c| return c if (!c.open? and c.number != 0) end # If no channel to re-use instantiate new one Bunny::Channel.new(self) end =begin rdoc === DESCRIPTION: Declares an exchange to the broker/server. If the exchange does not exist, a new one is created using the arguments passed in. If the exchange already exists, the existing object is returned. If an error occurs a _Bunny_::_ProtocolError_ is raised. ==== OPTIONS: * :type => one of :direct (_default_), :fanout, :topic, :headers * :passive => true or false - If set to _true_, the server will not create the exchange. The client can use this to check whether an exchange exists without modifying the server state. * :durable => true or false (_default_) - If set to _true_ when creating a new exchange, the exchange will be marked as durable. Durable exchanges remain active when a server restarts. Non-durable exchanges (transient exchanges) are purged if/when a server restarts. * :auto_delete => true or false (_default_) - If set to _true_, the exchange is deleted when all queues have finished using it. * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. ==== RETURNS: Exchange =end def exchange(name, opts = {}) exchanges[name] || Bunny::Exchange.new(self, name, opts) end def init_connection write(Qrack::Protocol::HEADER) write([1, 1, Qrack::Protocol::VERSION_MAJOR, Qrack::Protocol::VERSION_MINOR].pack('C4')) frame = next_frame if frame.nil? or !frame.payload.is_a?(Qrack::Protocol::Connection::Start) raise Bunny::ProtocolError, 'Connection initiation failed' end end def next_frame(opts = {}) frame = nil case when channel.frame_buffer.size > 0 frame = channel.frame_buffer.shift when (timeout = opts[:timeout]) && timeout > 0 Bunny::Timer::timeout(timeout, Qrack::FrameTimeout) do frame = Qrack::Transport::Frame.parse(buffer) end else frame = Qrack::Transport::Frame.parse(buffer) end @logger.info("received") { frame } if @logging raise Bunny::ConnectionError, 'No connection to server' if (frame.nil? and !connecting?) # Monitor server activity and discard heartbeats @message_in = true case when frame.is_a?(Qrack::Transport::Heartbeat) next_frame(opts) when frame.nil? frame when ((frame.channel != channel.number) and (frame.channel != 0)) channel.frame_buffer << frame next_frame(opts) else frame end end def open_connection client_opts = { :platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/ruby-amqp/bunny', :version => VERSION } send_frame(Qrack::Protocol::Connection::StartOk.new(client_opts, 'AMQPLAIN', {:LOGIN => @user, :PASSWORD => @pass}, 'en_US')) frame = next_frame raise Bunny::ProtocolError, "Connection failed - user: #{@user}" if frame.nil? method = frame.payload if method.is_a?(Qrack::Protocol::Connection::Tune) send_frame(Qrack::Protocol::Connection::TuneOk.new( :channel_max => @channel_max, :frame_max => @frame_max, :heartbeat => @heartbeat)) end send_frame(Qrack::Protocol::Connection::Open.new(:virtual_host => @vhost, :capabilities => '', :insist => @insist)) case method = next_method when Qrack::Protocol::Connection::OpenOk :ok when Qrack::Protocol::Connection::Redirect raise Bunny::ConnectionError, "Cannot connect to the specified server - host: #{@host}, port: #{@port}" if @insist @host, @port = method.host.split(':') close_socket else raise Bunny::ProtocolError, 'Cannot open connection' end end =begin rdoc === DESCRIPTION: Requests a specific quality of service. The QoS can be specified for the current channel or for all channels on the connection. The particular properties and semantics of a QoS method always depend on the content class semantics. Though the QoS method could in principle apply to both peers, it is currently meaningful only for the server. ==== Options: * :prefetch_size => size in no. of octets (default = 0) - The client can request that messages be sent in advance so that when the client finishes processing a message, the following message is already held locally, rather than needing to be sent down the channel. Prefetching gives a performance improvement. This field specifies the prefetch window size in octets. The server will send a message in advance if it is equal to or smaller in size than the available prefetch size (and also falls into other prefetch limits). May be set to zero, meaning "no specific limit", although other prefetch limits may still apply. The prefetch-size is ignored if the no-ack option is set. * :prefetch_count => no. messages (default = 1) - Specifies a prefetch window in terms of whole messages. This field may be used in combination with the prefetch-size field; a message will only be sent in advance if both prefetch windows (and those at the channel and connection level) allow it. The prefetch-count is ignored if the no-ack option is set. * :global => true or false (_default_) - By default the QoS settings apply to the current channel only. If set to true, they are applied to the entire connection. ==== RETURNS: :qos_ok if successful. =end def qos(opts = {}) send_frame(Qrack::Protocol::Basic::Qos.new({ :prefetch_size => 0, :prefetch_count => 1, :global => false }.merge(opts))) method = next_method check_response(method, Qrack::Protocol::Basic::QosOk, "Error specifying Quality of Service") # return confirmation :qos_ok end =begin rdoc === DESCRIPTION: Declares a queue to the broker/server. If the queue does not exist, a new one is created using the arguments passed in. If the queue already exists, a reference to it is created, provided that the arguments passed in do not conflict with the existing attributes of the queue. If an error occurs a _Bunny_::_ProtocolError_ is raised. ==== OPTIONS: * :passive => true or false (_default_) - If set to _true_, the server will not create the queue. The client can use this to check whether a queue exists without modifying the server state. * :durable => true or false (_default_) - If set to _true_ when creating a new queue, the queue will be marked as durable. Durable queues remain active when a server restarts. Non-durable queues (transient queues) are purged if/when a server restarts. Note that durable queues do not necessarily hold persistent messages, although it does not make sense to send persistent messages to a transient queue. * :exclusive => true or false (_default_) - If set to _true_, requests an exclusive queue. Exclusive queues may only be consumed from by the current connection. Setting the 'exclusive' flag always implies 'auto-delete'. * :auto_delete => true or false (_default_) - If set to _true_, the queue is deleted when all consumers have finished using it. Last consumer can be cancelled either explicitly or because its channel is closed. If there has never been a consumer on the queue, it is not deleted. * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. ==== RETURNS: Queue =end def queue(name = nil, opts = {}) if name.is_a?(Hash) opts = name name = nil end # Queue is responsible for placing itself in the list of queues queues[name] || Bunny::Queue.new(self, name, opts) end =begin rdoc === DESCRIPTION: Asks the broker to redeliver all unacknowledged messages on a specified channel. Zero or more messages may be redelivered. ==== Options: * :requeue => true or false (_default_) - If set to _false_, the message will be redelivered to the original recipient. If set to _true_, the server will attempt to requeue the message, potentially then delivering it to an alternative subscriber. =end def recover(opts = {}) send_frame(Qrack::Protocol::Basic::Recover.new({ :requeue => false }.merge(opts))) end def request_access send_frame(Qrack::Protocol::Access::Request.new(:realm => '/data', :read => true, :write => true, :active => true, :passive => true)) method = next_method check_response(method, Qrack::Protocol::Access::RequestOk, "Access denied") self.ticket = method.ticket end def send_frame(*args) args.each do |data| data.ticket = ticket if ticket and data.respond_to?(:ticket=) data = data.to_frame(channel.number) unless data.is_a?(Qrack::Transport::Frame) data.channel = channel.number @logger.info("send") { data } if @logging write(data.to_s) # Monitor client activity for heartbeat purposes @message_out = true end nil end def send_heartbeat # Create a new heartbeat frame hb = Qrack::Transport::Heartbeat.new('') # Channel 0 must be used switch_channel(0) if @channel.number > 0 # Send the heartbeat to server send_frame(hb) end =begin rdoc === DESCRIPTION: Opens a communication channel and starts a connection. If an error occurs, a _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to :connected. ==== RETURNS: :connected if successful. =end def start_session @connecting = true loop do # Create/get socket socket # Initiate connection init_connection # Open connection break if open_connection == :ok end # Open another channel because channel zero is used for specific purposes c = create_channel() c.open # Get access ticket request_access @connecting = false # return status @status = :connected end alias start start_session =begin rdoc === DESCRIPTION: This method commits all messages published and acknowledged in the current transaction. A new transaction starts immediately after a commit. ==== RETURNS: :commit_ok if successful. =end def tx_commit send_frame(Qrack::Protocol::Tx::Commit.new()) method = next_method check_response(method, Qrack::Protocol::Tx::CommitOk, "Error commiting transaction") # return confirmation :commit_ok end =begin rdoc === DESCRIPTION: This method abandons all messages published and acknowledged in the current transaction. A new transaction starts immediately after a rollback. ==== RETURNS: :rollback_ok if successful. =end def tx_rollback send_frame(Qrack::Protocol::Tx::Rollback.new()) method = next_method check_response(method, Qrack::Protocol::Tx::RollbackOk, "Error rolling back transaction") # return confirmation :rollback_ok end =begin rdoc === DESCRIPTION: This method sets the channel to use standard transactions. The client must use this method at least once on a channel before using the Commit or Rollback methods. ==== RETURNS: :select_ok if successful. =end def tx_select send_frame(Qrack::Protocol::Tx::Select.new()) method = next_method check_response(method, Qrack::Protocol::Tx::SelectOk, "Error initiating transactions for current channel") # return confirmation :select_ok end private def buffer @buffer ||= Qrack::Transport::Buffer.new(self) end end end bunny-0.7.8/lib/bunny/queue08.rb0000644000076400007640000002733511704323672015456 0ustar pravipravi# encoding: utf-8 module Bunny =begin rdoc === DESCRIPTION: Queues store and forward messages. Queues can be configured in the server or created at runtime. Queues must be attached to at least one exchange in order to receive messages from publishers. =end class Queue < Qrack::Queue def initialize(client, name, opts = {}) # check connection to server raise Bunny::ConnectionError, 'Not connected to server' if client.status == :not_connected @client = client @opts = opts @delivery_tag = nil @subscription = nil # Queues without a given name are named by the server and are generally # bound to the process that created them. if !name opts = { :passive => false, :durable => false, :exclusive => true, :auto_delete => true }.merge(opts) end # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name || '', :nowait => false }.merge(opts) client.send_frame(Qrack::Protocol::Queue::Declare.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol::Queue::DeclareOk, "Error declaring queue #{name}") @name = method.queue client.queues[@name] = self end # @return [Bunny::Consumer] Default consumer associated with this queue (if any), or nil # @note Default consumer is the one registered with the convenience {Bunny::Queue#subscribe} method. It has no special properties of any kind. # @see Queue#subscribe # @see Bunny::Consumer # @api public def default_consumer @default_consumer end # @return [Class] # @private def self.consumer_class # Bunny::Consumer Bunny::Subscription end # self.consumer_class =begin rdoc === DESCRIPTION: Acknowledges one or more messages delivered via the _Deliver_ or _Get_-_Ok_ methods. The client can ask to confirm a single message or a set of messages up to and including a specific message. ==== OPTIONS: * :delivery_tag * :multiple => true or false (_default_) - If set to _true_, the delivery tag is treated as "up to and including", so that the client can acknowledge multiple messages with a single method. If set to _false_, the delivery tag refers to a single message. If the multiple field is _true_, and the delivery tag is zero, tells the server to acknowledge all outstanding messages. =end def ack(opts={}) # Set delivery tag if delivery_tag.nil? and opts[:delivery_tag].nil? raise Bunny::AcknowledgementError, "No delivery tag received" else self.delivery_tag = opts[:delivery_tag] if delivery_tag.nil? end opts = {:delivery_tag => delivery_tag, :multiple => false}.merge(opts) client.send_frame(Qrack::Protocol::Basic::Ack.new(opts)) # reset delivery tag self.delivery_tag = nil end =begin rdoc === DESCRIPTION: Binds a queue to an exchange. Until a queue is bound it will not receive any messages. Queues are bound to the direct exchange '' by default. If error occurs, a _Bunny_::_ProtocolError_ is raised. * :key => 'routing key'* :key => 'routing_key' - Specifies the routing key for the binding. The routing key is used for routing messages depending on the exchange configuration. * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. ==== RETURNS: :bind_ok if successful. =end def bind(exchange, opts = {}) exchange = exchange.respond_to?(:name) ? exchange.name : exchange # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name, :exchange => exchange, :routing_key => opts.delete(:key), :nowait => false }.merge(opts) client.send_frame(Qrack::Protocol::Queue::Bind.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol::Queue::BindOk, "Error binding queue: #{name} to exchange: #{exchange}") # return message :bind_ok end =begin rdoc === DESCRIPTION: Requests that a queue is deleted from broker/server. When a queue is deleted any pending messages are sent to a dead-letter queue if this is defined in the server configuration. Removes reference from queues if successful. If an error occurs raises _Bunny_::_ProtocolError_. ==== Options: * :if_unused => true or false (_default_) - If set to _true_, the server will only delete the queue if it has no consumers. If the queue has consumers the server does not delete it but raises a channel exception instead. * :if_empty => true or false (_default_) - If set to _true_, the server will only delete the queue if it has no messages. If the queue is not empty the server raises a channel exception. * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. ==== Returns: :delete_ok if successful =end def delete(opts = {}) # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name, :nowait => false }.merge(opts) client.send_frame(Qrack::Protocol::Queue::Delete.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol::Queue::DeleteOk, "Error deleting queue #{name}") client.queues.delete(name) # return confirmation :delete_ok end =begin rdoc === DESCRIPTION: Gets a message from a queue in a synchronous way. If error occurs, raises _Bunny_::_ProtocolError_. ==== OPTIONS: * :ack => false (_default_) or true - If set to _false_, the server does not expect an acknowledgement message from the client. If set to _true_, the server expects an acknowledgement message from the client and will re-queue the message if it does not receive one within a time specified by the server. ==== RETURNS: Hash {:header, :payload, :delivery_details}. :delivery_details is a hash {:consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key}. If the queue is empty the returned hash will contain the values - :header => nil :payload => :queue_empty :delivery_details => nil N.B. If a block is provided then the hash will be passed into the block and the return value will be nil. =end def pop(opts = {}, &blk) # do we want to have to provide an acknowledgement? ack = opts.delete(:ack) opts = { :queue => name, :consumer_tag => name, :no_ack => !ack, :nowait => true }.merge(opts) client.send_frame(Qrack::Protocol::Basic::Get.new(opts)) method = client.next_method if method.is_a?(Qrack::Protocol::Basic::GetEmpty) then queue_empty = true elsif !method.is_a?(Qrack::Protocol::Basic::GetOk) raise Bunny::ProtocolError, "Error getting message from queue #{name}" end if !queue_empty # get delivery tag to use for acknowledge self.delivery_tag = method.delivery_tag if ack header = client.next_payload # If maximum frame size is smaller than message payload body then message # will have a message header and several message bodies msg = '' while msg.length < header.size msg << client.next_payload end msg_hash = {:header => header, :payload => msg, :delivery_details => method.arguments} else msg_hash = {:header => nil, :payload => :queue_empty, :delivery_details => nil} end # Pass message hash to block or return message hash blk ? blk.call(msg_hash) : msg_hash end =begin rdoc === DESCRIPTION: Removes all messages from a queue. It does not cancel consumers. Purged messages are deleted without any formal "undo" mechanism. If an error occurs raises _Bunny_::_ProtocolError_. ==== Options: * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. ==== Returns: :purge_ok if successful =end def purge(opts = {}) # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name, :nowait => false }.merge(opts) client.send_frame(Qrack::Protocol::Queue::Purge.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol::Queue::PurgeOk, "Error purging queue #{name}") # return confirmation :purge_ok end =begin rdoc === DESCRIPTION: Returns hash {:message_count, :consumer_count}. =end def status client.send_frame(Qrack::Protocol::Queue::Declare.new(:queue => name, :passive => true)) method = client.next_method {:message_count => method.message_count, :consumer_count => method.consumer_count} end def subscribe(opts = {}, &blk) raise RuntimeError.new("This queue already has default consumer. Please instantiate Bunny::Consumer directly and call its #consume method to register additional consumers.") if @default_consumer && ! opts[:consumer_tag] # Create a subscription. @default_consumer = self.class.consumer_class.new(client, self, opts) @default_consumer.consume(&blk) end =begin rdoc === DESCRIPTION: Cancels a consumer. This does not affect already delivered messages, but it does mean the server will not send any more messages for that consumer. ==== OPTIONS: * :consumer_tag => '_tag_' - Specifies the identifier for the consumer. * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. ==== Returns: :unsubscribe_ok if successful =end def unsubscribe(opts = {}) # Default consumer_tag from subscription if not passed in consumer_tag = @default_consumer ? @default_consumer.consumer_tag : opts[:consumer_tag] # Must have consumer tag to tell server what to unsubscribe raise Bunny::UnsubscribeError, "No consumer tag received" if !consumer_tag # Cancel consumer client.send_frame(Qrack::Protocol::Basic::Cancel.new(:consumer_tag => consumer_tag,:nowait => false)) method = client.next_method client.check_response(method, Qrack::Protocol::Basic::CancelOk, "Error unsubscribing from queue #{name}") # Reset subscription @default_consumer = nil # Return confirmation :unsubscribe_ok end =begin rdoc === DESCRIPTION: Removes a queue binding from an exchange. If error occurs, a _Bunny_::_ProtocolError_ is raised. ==== OPTIONS: * :key => 'routing key'* :key => 'routing_key' - Specifies the routing key for the binding. * :nowait => true or false (_default_) - Ignored by Bunny, always _false_. ==== RETURNS: :unbind_ok if successful. =end def unbind(exchange, opts = {}) exchange = exchange.respond_to?(:name) ? exchange.name : exchange # ignore the :nowait option if passed, otherwise program will hang waiting for a # response that will not be sent by the server opts.delete(:nowait) opts = { :queue => name, :exchange => exchange, :routing_key => opts.delete(:key), :nowait => false }.merge(opts) client.send_frame(Qrack::Protocol::Queue::Unbind.new(opts)) method = client.next_method client.check_response(method, Qrack::Protocol::Queue::UnbindOk, "Error unbinding queue #{name}") # return message :unbind_ok end private def exchange @exchange ||= Bunny::Exchange.new(client, '', {:type => :direct, :key => name}) end end end bunny-0.7.8/lib/bunny.rb0000644000076400007640000000522511704323672014154 0ustar pravipravi# encoding: utf-8 require "socket" require "thread" require "timeout" require "logger" require File.expand_path("../bunny/version", __FILE__) # if we don't require the version file the same way as in the gemspec, # the version file will be loaded twice. and we hate warnings. module Bunny class ConnectionError < StandardError; end class ForcedChannelCloseError < StandardError; end class ForcedConnectionCloseError < StandardError; end class MessageError < StandardError; end class ProtocolError < StandardError; end class ServerDownError < StandardError; end class UnsubscribeError < StandardError; end class AcknowledgementError < StandardError; end # Returns the Bunny version number def self.version VERSION end # Print deprecation warning. def self.deprecation_warning(method, version, explanation) warn "~ #{method} will be removed in Bunny #{version}. #{explanation}" end # Instantiates new Bunny::Client def self.new(connection_string_or_opts = Hash.new, opts = Hash.new) # Set up Bunny according to AMQP spec version required if connection_string_or_opts.respond_to?(:keys) && opts.empty? opts = connection_string_or_opts end spec_version = opts[:spec] || '08' # Return client setup(spec_version, connection_string_or_opts, opts) end # Runs a code block using a short-lived connection def self.run(opts = {}, &block) raise ArgumentError, 'Bunny#run requires a block' unless block # Set up Bunny according to AMQP spec version required spec_version = opts[:spec] || '08' client = setup(spec_version, opts) begin client.start block.call(client) ensure client.stop end # Return success :run_ok end Timer = if RUBY_VERSION < "1.9" begin require File.expand_path(File.join(File.dirname(__FILE__), 'system_timer.rb')) Bunny::SystemTimer rescue LoadError Timeout end else Timeout end private def self.setup(version, *args) if version == '08' # AMQP 0-8 specification require 'qrack/qrack08' require 'bunny/client08' require 'bunny/exchange08' require 'bunny/queue08' require 'bunny/channel08' require 'bunny/subscription08' client = Bunny::Client.new(*args) else # AMQP 0-9-1 specification require 'qrack/qrack09' require 'bunny/client09' require 'bunny/exchange09' require 'bunny/queue09' require 'bunny/channel09' require 'bunny/subscription09' client = Bunny::Client09.new(*args) end include Qrack client end end bunny-0.7.8/README.textile0000644000076400007640000000264111704323672014262 0ustar pravipravih1. About Bunny is a synchronous "AMQP":http://bit.ly/hw2ELX client. It supports Ruby 1.9.2, 1.8.7, Ruby Enterprise Edition and JRuby. Protocol-wise, Bunny supports AMQP 0.9.1 and 0.8. Support for AMQP 0.8 will be dropped in the next version of Bunny (0.7) because most of popular AMQP brokers such as RabbitMQ already stopped or planning to stop supporting it in the near future. Bunny is based on a great deal of useful code from the "amqp Ruby gem":http://github.com/ruby-amqp/amqp and "Carrot":http://github.com/famoseagle/carrot. You can use Bunny to: * Create and delete exchanges * Create and delete queues * Publish and consume messages h1. Quick Start
require "bunny"

b = Bunny.new(:logging => true)

# start a communication session with the amqp server
b.start

# declare a queue
q = b.queue("test1")

# publish a message to the queue
q.publish("Hello everybody!")

# get message from the queue
msg = q.pop[:payload]

puts "This is the message: " + msg + "\n\n"

# close the connection
b.stop
... or just:
require "bunny"

# Create a direct queue named "my_testq"
Bunny.run { |c| c.queue("my_testq") }
Please see the @examples@ directory for additional usage information. h1. Links * "Source code":http://github.com/ruby-amqp/bunny * "@rubyamqp":http://twitter.com/rubyamqp at Twitter * "Ruby AMQP Google Group":http://groups.google.com/group/ruby-amqp * "Blog":http://bunnyamqp.wordpress.com bunny-0.7.8/examples/0000755000076400007640000000000011704323672013540 5ustar pravipravibunny-0.7.8/examples/simple_08.rb0000644000076400007640000000136011704323672015665 0ustar pravipravi# encoding: utf-8 # simple_08.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true) # start a communication session with the amqp server b.start # declare a queue q = b.queue('test1') # publish a message to the queue q.publish('➸ Hello everybody ☺!') # get message from the queue msg = q.pop[:payload] puts 'This is the message: ' + msg + "\n\n" # close the client connection b.stop bunny-0.7.8/examples/simple_topic_08.rb0000644000076400007640000000357611704323672017076 0ustar pravipravi# encoding: utf-8 # simple_topic_08.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new # start a communication session with the amqp server b.start # declare queues soccer = b.queue('topic_soccer') cricket = b.queue('topic_cricket') rugby = b.queue('topic_rugby') allsport = b.queue('topic_allsport') # create a topic exchange sports_results = b.exchange('sports_results', :type => :topic) # bind the queues to the exchange soccer.bind(sports_results, :key => 'soccer.*') cricket.bind(sports_results, :key => 'cricket.*') rugby.bind(sports_results, :key => 'rugby.*') allsport.bind(sports_results, :key => '*.result') # publish messages to the exchange sports_results.publish('Manchester United 1 : Hull City 4', :key => 'soccer.result') sports_results.publish('England beat Australia by 5 wickets in first test', :key => 'cricket.result') sports_results.publish('British Lions 15 : South Africa 12', :key => 'rugby.result') # get message from the queues # soccer queue got the soccer message msg = soccer.pop[:payload] puts 'This is a message from the soccer q: ' + msg + "\n\n" # cricket queue got the cricket message msg = cricket.pop[:payload] puts 'This is a message from the cricket q: ' + msg + "\n\n" # rugby queue got the rugby message msg = rugby.pop[:payload] puts 'This is a message from the rugby q: ' + msg + "\n\n" # allsport queue got all of the messages until msg == :queue_empty do msg = allsport.pop[:payload] puts 'This is a message from the allsport q: ' + msg + "\n\n" unless msg == :queue_empty end # close the client connection b.stop bunny-0.7.8/examples/simple_publisher_09.rb0000644000076400007640000000153011704323672017742 0ustar pravipravi# encoding: utf-8 # simple_publisher.rb # N.B. To be used in conjunction with simple_consumer.rb. See simple_consumer.rb for explanation. # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true, :spec => '09') # start a communication session with the amqp server b.start # create/get exchange exch = b.exchange('sorting_room') # publish message to exchange exch.publish('This is a message from the publisher', :key => 'fred') # message should now be picked up by the consumer so we can stop b.stop bunny-0.7.8/examples/simple_09.rb0000644000076400007640000000137711704323672015676 0ustar pravipravi# encoding: utf-8 # simple_09.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true, :spec => '09') # start a communication session with the amqp server b.start # declare a queue q = b.queue('test1') # publish a message to the queue q.publish('➸ Hello everybody ☺!') # get message from the queue msg = q.pop[:payload] puts 'This is the message: ' + msg + "\n\n" # close the client connection b.stop bunny-0.7.8/examples/simple_publisher_08.rb0000644000076400007640000000151711704323672017746 0ustar pravipravi# encoding: utf-8 # simple_publisher_08.rb # N.B. To be used in conjunction with simple_consumer_08.rb. See simple_consumer.rb for explanation. # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true) # start a communication session with the amqp server b.start # create/get exchange exch = b.exchange('sorting_room') # publish message to exchange exch.publish('This is a message from the publisher', :key => 'fred') # message should now be picked up by the consumer so we can stop b.stop bunny-0.7.8/examples/simple_consumer_08.rb0000644000076400007640000000300311704323672017574 0ustar pravipravi# encoding: utf-8 # simple_consumer_08.rb # N.B. To be used in conjunction with simple_publisher.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') # How this example works #======================= # # Open up two console windows start this program in one of them by typing - # # ruby simple_consumer_08.rb # # Then switch to the other console window and type - # # ruby simple_publisher_08.rb # # A message will be printed out by the simple_consumer and it will wait for the next message # until the timeout interval is reached. # # Run simple_publisher as many times as you like. When you want the program to stop just stop # sending messages and the subscribe loop will timeout after 30 seconds, the program will # unsubscribe from the queue and close the connection to the server. $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true) # start a communication session with the amqp server b.start # create/get queue q = b.queue('po_box') # create/get exchange exch = b.exchange('sorting_room') # bind queue to exchange q.bind(exch, :key => 'fred') # subscribe to queue q.subscribe(:consumer_tag => 'testtag1', :timeout => 30) do |msg| puts "#{q.subscription.message_count}: #{msg[:payload]}" end # Close client b.stop bunny-0.7.8/examples/simple_headers_08.rb0000644000076400007640000000221411704323672017357 0ustar pravipravi# encoding: utf-8 # simple_headers_08.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new # start a communication session with the amqp server b.start # declare queues q = b.queue('header_q1') # create a headers exchange header_exch = b.exchange('header_exch', :type => :headers) # bind the queue to the exchange q.bind(header_exch, :arguments => {'h1'=>'a','x-match'=>'all'}) # publish messages to the exchange header_exch.publish('Headers test msg 1', :headers => {'h1'=>'a'}) header_exch.publish('Headers test msg 2', :headers => {'h1'=>'z'}) # get messages from the queue - should only be msg 1 that got through msg = "" until msg == :queue_empty do msg = q.pop[:payload] puts 'This is a message from the header_q1 queue: ' + msg + "\n" unless msg == :queue_empty end # close the client connection b.stop bunny-0.7.8/examples/simple_consumer_09.rb0000644000076400007640000000302211704323672017576 0ustar pravipravi# encoding: utf-8 # simple_consumer_09.rb # N.B. To be used in conjunction with simple_publisher.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') # How this example works #======================= # # Open up two console windows start this program in one of them by typing - # # ruby simple_consumer_09.rb # # Then switch to the other console window and type - # # ruby simple_publisher_09.rb # # A message will be printed out by the simple_consumer and it will wait for the next message # until the timeout interval is reached. # # Run simple_publisher as many times as you like. When you want the program to stop just stop # sending messages and the subscribe loop will timeout after 30 seconds, the program will # unsubscribe from the queue and close the connection to the server. $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true, :spec => '09') # start a communication session with the amqp server b.start # create/get queue q = b.queue('po_box') # create/get exchange exch = b.exchange('sorting_room') # bind queue to exchange q.bind(exch, :key => 'fred') # subscribe to queue q.subscribe(:consumer_tag => 'testtag1', :timeout => 30) do |msg| puts "#{q.subscription.message_count}: #{msg[:payload]}" end # Close client b.stop bunny-0.7.8/examples/simple_ack_09.rb0000644000076400007640000000147111704323672016507 0ustar pravipravi# encoding: utf-8 # simple_ack_09.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true, :spec => '09') # start a communication session with the amqp server b.start # declare a queue q = b.queue('test1') # publish a message to the queue q.publish('Testing acknowledgements') # get message from the queue msg = q.pop(:ack => true)[:payload] # acknowledge receipt of message q.ack puts 'This is the message: ' + msg + "\n\n" # close the client connection b.stop bunny-0.7.8/examples/simple_fanout_09.rb0000644000076400007640000000202011704323672017234 0ustar pravipravi# encoding: utf-8 # simple_fanout_09.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true, :spec => '09') # start a communication session with the amqp server b.start # declare queues q1 = b.queue('test_fan1') q2 = b.queue('test_fan2') # create a fanout exchange exch = b.exchange('test_fan', :type => :fanout) # bind the queues to the exchange q1.bind(exch) q2.bind(exch) # publish a message to the exchange exch.publish('This message will be fanned out') # get message from the queues msg = q1.pop[:payload] puts 'This is the message from q1: ' + msg + "\n\n" msg = q2.pop[:payload] puts 'This is the message from q2: ' + msg + "\n\n" # close the client connection b.stop bunny-0.7.8/examples/simple_ack_08.rb0000644000076400007640000000145211704323672016505 0ustar pravipravi# encoding: utf-8 # simple_ack_08.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true) # start a communication session with the amqp server b.start # declare a queue q = b.queue('test1') # publish a message to the queue q.publish('Testing acknowledgements') # get message from the queue msg = q.pop(:ack => true)[:payload] # acknowledge receipt of message q.ack puts 'This is the message: ' + msg + "\n\n" # close the client connection b.stop bunny-0.7.8/examples/simple_topic_09.rb0000644000076400007640000000361511704323672017071 0ustar pravipravi# encoding: utf-8 # simple_topic_09.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:spec => '09') # start a communication session with the amqp server b.start # declare queues soccer = b.queue('topic_soccer') cricket = b.queue('topic_cricket') rugby = b.queue('topic_rugby') allsport = b.queue('topic_allsport') # create a topic exchange sports_results = b.exchange('sports_results', :type => :topic) # bind the queues to the exchange soccer.bind(sports_results, :key => 'soccer.*') cricket.bind(sports_results, :key => 'cricket.*') rugby.bind(sports_results, :key => 'rugby.*') allsport.bind(sports_results, :key => '*.result') # publish messages to the exchange sports_results.publish('Manchester United 1 : Hull City 4', :key => 'soccer.result') sports_results.publish('England beat Australia by 5 wickets in first test', :key => 'cricket.result') sports_results.publish('British Lions 15 : South Africa 12', :key => 'rugby.result') # get message from the queues # soccer queue got the soccer message msg = soccer.pop[:payload] puts 'This is a message from the soccer q: ' + msg + "\n\n" # cricket queue got the cricket message msg = cricket.pop[:payload] puts 'This is a message from the cricket q: ' + msg + "\n\n" # rugby queue got the rugby message msg = rugby.pop[:payload] puts 'This is a message from the rugby q: ' + msg + "\n\n" # allsport queue got all of the messages until msg == :queue_empty do msg = allsport.pop[:payload] puts 'This is a message from the allsport q: ' + msg + "\n\n" unless msg == :queue_empty end # close the client connection b.stop bunny-0.7.8/examples/simple_headers_09.rb0000644000076400007640000000223311704323672017361 0ustar pravipravi# encoding: utf-8 # simple_headers_09.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:spec => '09') # start a communication session with the amqp server b.start # declare queues q = b.queue('header_q1') # create a headers exchange header_exch = b.exchange('header_exch', :type => :headers) # bind the queue to the exchange q.bind(header_exch, :arguments => {'h1'=>'a','x-match'=>'all'}) # publish messages to the exchange header_exch.publish('Headers test msg 1', :headers => {'h1'=>'a'}) header_exch.publish('Headers test msg 2', :headers => {'h1'=>'z'}) # get messages from the queue - should only be msg 1 that got through msg = "" until msg == :queue_empty do msg = q.pop[:payload] puts 'This is a message from the header_q1 queue: ' + msg + "\n" unless msg == :queue_empty end # close the client connection b.stop bunny-0.7.8/examples/simple_fanout_08.rb0000644000076400007640000000200111704323672017232 0ustar pravipravi# encoding: utf-8 # simple_fanout_08.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') $:.unshift File.dirname(__FILE__) + '/../lib' require 'bunny' b = Bunny.new(:logging => true) # start a communication session with the amqp server b.start # declare queues q1 = b.queue('test_fan1') q2 = b.queue('test_fan2') # create a fanout exchange exch = b.exchange('test_fan', :type => :fanout) # bind the queues to the exchange q1.bind(exch) q2.bind(exch) # publish a message to the exchange exch.publish('This message will be fanned out') # get message from the queues msg = q1.pop[:payload] puts 'This is the message from q1: ' + msg + "\n\n" msg = q2.pop[:payload] puts 'This is the message from q2: ' + msg + "\n\n" # close the client connection b.stop bunny-0.7.8/metadata.yml0000644000076400007640000000645211704323672014234 0ustar pravipravi--- !ruby/object:Gem::Specification name: bunny version: !ruby/object:Gem::Version version: 0.7.8 prerelease: platform: ruby authors: - Chris Duncan - Eric Lindvall - Jakub Stastny aka botanicus - Michael S. Klishin - Stefan Kaes autorequire: bindir: bin cert_chain: [] date: 2011-10-11 00:00:00.000000000 +02:00 default_executable: dependencies: [] description: A synchronous Ruby AMQP client that enables interaction with AMQP-compliant brokers. email: - celldee@gmail.com - eric@5stops.com - stastny@101ideas.cz - michael@novemberain.com - skaes@railsexpress.de executables: [] extensions: [] extra_rdoc_files: - README.textile files: - .gitignore - .rspec - .travis.yml - .yardopts - CHANGELOG - Gemfile - LICENSE - README.textile - Rakefile - bunny.gemspec - examples/simple_08.rb - examples/simple_09.rb - examples/simple_ack_08.rb - examples/simple_ack_09.rb - examples/simple_consumer_08.rb - examples/simple_consumer_09.rb - examples/simple_fanout_08.rb - examples/simple_fanout_09.rb - examples/simple_headers_08.rb - examples/simple_headers_09.rb - examples/simple_publisher_08.rb - examples/simple_publisher_09.rb - examples/simple_topic_08.rb - examples/simple_topic_09.rb - ext/amqp-0.8.json - ext/amqp-0.9.1.json - ext/config.yml - ext/qparser.rb - lib/bunny.rb - lib/bunny/channel08.rb - lib/bunny/channel09.rb - lib/bunny/client08.rb - lib/bunny/client09.rb - lib/bunny/consumer.rb - lib/bunny/exchange08.rb - lib/bunny/exchange09.rb - lib/bunny/queue08.rb - lib/bunny/queue09.rb - lib/bunny/subscription08.rb - lib/bunny/subscription09.rb - lib/bunny/system_timer.rb - lib/bunny/version.rb - lib/qrack/amq-client-url.rb - lib/qrack/channel.rb - lib/qrack/client.rb - lib/qrack/errors.rb - lib/qrack/protocol/protocol08.rb - lib/qrack/protocol/protocol09.rb - lib/qrack/protocol/spec08.rb - lib/qrack/protocol/spec09.rb - lib/qrack/qrack08.rb - lib/qrack/qrack09.rb - lib/qrack/queue.rb - lib/qrack/subscription.rb - lib/qrack/transport/buffer08.rb - lib/qrack/transport/buffer09.rb - lib/qrack/transport/frame08.rb - lib/qrack/transport/frame09.rb - spec/spec_08/bunny_spec.rb - spec/spec_08/connection_spec.rb - spec/spec_08/exchange_spec.rb - spec/spec_08/queue_spec.rb - spec/spec_09/amqp_url_spec.rb - spec/spec_09/bunny_spec.rb - spec/spec_09/connection_spec.rb - spec/spec_09/exchange_spec.rb - spec/spec_09/queue_spec.rb has_rdoc: true homepage: http://github.com/ruby-amqp/bunny licenses: [] post_install_message: ! "[\e[32mVersion 0.7.8\e[0m] test suite cleanup (eliminated some race conditions related to queue.message_count)\n" rdoc_options: - --main - README.rdoc require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: bunny-amqp rubygems_version: 1.6.2 signing_key: specification_version: 3 summary: Synchronous Ruby AMQP 0.9.1 client test_files: - spec/spec_08/bunny_spec.rb - spec/spec_08/connection_spec.rb - spec/spec_08/exchange_spec.rb - spec/spec_08/queue_spec.rb - spec/spec_09/amqp_url_spec.rb - spec/spec_09/bunny_spec.rb - spec/spec_09/connection_spec.rb - spec/spec_09/exchange_spec.rb - spec/spec_09/queue_spec.rb bunny-0.7.8/LICENSE0000644000076400007640000000221011704323672012722 0ustar pravipraviCopyright (c) 2009 – 2011 Chris Duncan, Jakub Stastny aka botanicus, Michael S. Klishin, Eric Lindvall, Stefan Kaes and contributors. 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. bunny-0.7.8/ext/0000755000076400007640000000000011704323672012522 5ustar pravipravibunny-0.7.8/ext/qparser.rb0000644000076400007640000003120611704323672014526 0ustar pravipravi# encoding: utf-8 require 'json' require 'erb' require 'pathname' require 'yaml' def spec_v8_0_0?(spec) spec['major'] == '8' && spec['minor'] == '0' && spec['revision'] == '0' end def spec_details(spec) meta = {} meta['major'] = spec['major-version'] meta['minor'] = spec['minor-version'] meta['revision'] = spec['revision'] || '0' meta['port'] = spec['port'] meta['comment'] = "AMQ Protocol version #{meta['major']}.#{meta['minor']}.#{meta['revision']}" meta end def process_constants(spec) # AMQP constants frame_constants = {} other_constants = {} spec['constants'].each do |constant| if constant['name'].match(/^frame/i) frame_constants[constant['value'].to_i] = constant['name'].sub(/^frame./i,'').split(/\s|-/).map{|w| w.downcase.capitalize}.join else other_constants[constant['value']] = constant['name'] end end [frame_constants.sort, other_constants.sort] end def domain_types(spec, major, minor, revision) # AMQP domain types # add types that may be missing in the spec version dt_arr = add_types(spec) spec["domains"].each do |domain| # JSON spec gives domain types as two element arrays like ["channel-id", "longstr"] dt_arr << domain.last end # Return sorted array dt_arr.uniq.sort end def classes(spec, major, minor, revision) # AMQP classes spec['classes'].map do |amqp_class| cls_hash = {} cls_hash[:name] = amqp_class['name'] cls_hash[:index] = amqp_class['id'] # Get fields for class cls_hash[:fields] = fields(amqp_class) # are these amqp_class["properties"] ? # Get methods for class meth_arr = class_methods(amqp_class) # Add missing methods add_arr =[] add_arr = add_methods(spec) if cls_hash[:name] == 'queue' method_arr = meth_arr + add_arr # Add array to class hash cls_hash[:methods] = method_arr cls_hash end end # Get methods for class def class_methods(amqp_class) amqp_class['methods'].map do |method| meth_hash = {} meth_hash[:name] = method['name'] meth_hash[:index] = method['id'] # Get fields for method meth_hash[:fields] = fields(method) meth_hash end end # Get the fields for a class or method def fields(element) # The JSON spec puts these in "properties" for a class and "arguments" for a # method (element['arguments'] || element['properties'] || []).map do |field| field_hash = {} field_hash[:name] = field['name'].tr(' ', '-') field_hash[:domain] = field['type'] || field['domain'] # Convert domain type if necessary conv_arr = convert_type(field_hash[:domain]) field_hash[:domain] = conv_arr.last unless conv_arr.empty? field_hash end end def add_types(spec) spec_v8_0_0?(spec) ? ['long', 'longstr', 'octet', 'timestamp'] : [] end def add_methods(spec) meth_arr = [] if spec_v8_0_0?(spec) # Add Queue Unbind method meth_hash = {:name => 'unbind', :index => '50', :fields => [{:name => 'ticket', :domain => 'short'}, {:name => 'queue', :domain => 'shortstr'}, {:name => 'exchange', :domain => 'shortstr'}, {:name => 'routing_key', :domain => 'shortstr'}, {:name => 'arguments', :domain => 'table'} ] } meth_arr << meth_hash # Add Queue Unbind-ok method meth_hash = {:name => 'unbind-ok', :index => '51', :fields => [] } meth_arr << meth_hash end # Return methods meth_arr end def convert_type(name) type_arr = @type_conversion.select {|k,v| k == name}.flatten end # Start of Main program # Read in config options CONFIG = YAML::load(File.read('config.yml')) # Get path to the spec file and the spec file name on its own specpath = CONFIG[:spec_in] path = Pathname.new(specpath) specfile = path.basename.to_s # Read in the spec file spec = JSON.parse(IO.read(specpath)) # Declare type conversion hash @type_conversion = {'path' => 'shortstr', 'known hosts' => 'shortstr', 'known-hosts' => 'shortstr', 'reply code' => 'short', 'reply-code' => 'short', 'reply text' => 'shortstr', 'reply-text' => 'shortstr', 'class id' => 'short', 'class-id' => 'short', 'method id' => 'short', 'method-id' => 'short', 'channel-id' => 'longstr', 'access ticket' => 'short', 'access-ticket' => 'short', 'exchange name' => 'shortstr', 'exchange-name' => 'shortstr', 'queue name' => 'shortstr', 'queue-name' => 'shortstr', 'consumer tag' => 'shortstr', 'consumer-tag' => 'shortstr', 'delivery tag' => 'longlong', 'delivery-tag' => 'longlong', 'redelivered' => 'bit', 'no ack' => 'bit', 'no-ack' => 'bit', 'no local' => 'bit', 'no-local' => 'bit', 'peer properties' => 'table', 'peer-properties' => 'table', 'destination' => 'shortstr', 'duration' => 'longlong', 'security-token' => 'longstr', 'reject-code' => 'short', 'reject-text' => 'shortstr', 'offset' => 'longlong', 'no-wait' => 'bit', 'message-count' => 'long' } # Spec details spec_info = spec_details(spec) # Constants constants = process_constants(spec) # Frame constants frame_constants = constants[0].select {|k,v| k <= 8} frame_footer = constants[0].select {|k,v| v == 'End'}[0][0] # Other constants other_constants = constants[1] # Domain types data_types = domain_types(spec, spec_info['major'], spec_info['minor'], spec_info['revision']) # Classes class_defs = classes(spec, spec_info['major'], spec_info['minor'], spec_info['revision']) # Generate spec.rb spec_rb = File.open(CONFIG[:spec_out], 'w') spec_rb.puts( ERB.new(%q[ # encoding: utf-8 #:stopdoc: # this file was autogenerated on <%= Time.now.to_s %> # using <%= specfile.ljust(16) %> (mtime: <%= File.mtime(specpath) %>) # # DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb') module Qrack module Protocol HEADER = "AMQP".freeze VERSION_MAJOR = <%= spec_info['major'] %> VERSION_MINOR = <%= spec_info['minor'] %> REVISION = <%= spec_info['revision'] %> PORT = <%= spec_info['port'] %> RESPONSES = { <%- other_constants.each do |value, name| -%> <%= value %> => :<%= name.gsub(/\s|-/, '_').upcase -%>, <%- end -%> } FIELDS = [ <%- data_types.each do |d| -%> :<%= d -%>, <%- end -%> ] class Class class << self FIELDS.each do |f| class_eval %[ def #{f} name properties << [ :#{f}, name ] unless properties.include?([:#{f}, name]) attr_accessor name end ] end def properties() @properties ||= [] end def id() self::ID end def name() self::NAME.to_s end end class Method class << self FIELDS.each do |f| class_eval %[ def #{f} name arguments << [ :#{f}, name ] unless arguments.include?([:#{f}, name]) attr_accessor name end ] end def arguments() @arguments ||= [] end def parent() Protocol.const_get(self.to_s[/Protocol::(.+?)::/,1]) end def id() self::ID end def name() self::NAME.to_s end end def == b self.class.arguments.inject(true) do |eql, (type, name)| eql and __send__("#{name}") == b.__send__("#{name}") end end end def self.methods() @methods ||= {} end def self.Method(id, name) @_base_methods ||= {} @_base_methods[id] ||= ::Class.new(Method) do class_eval %[ def self.inherited klass klass.const_set(:ID, #{id}) klass.const_set(:NAME, :#{name.to_s}) klass.parent.methods[#{id}] = klass klass.parent.methods[klass::NAME] = klass end ] end end end def self.classes() @classes ||= {} end def self.Class(id, name) @_base_classes ||= {} @_base_classes[id] ||= ::Class.new(Class) do class_eval %[ def self.inherited klass klass.const_set(:ID, #{id}) klass.const_set(:NAME, :#{name.to_s}) Protocol.classes[#{id}] = klass Protocol.classes[klass::NAME] = klass end ] end end end end module Qrack module Protocol <%- class_defs.each do |h| -%> class <%= h[:name].capitalize.ljust(12) %> < Class( <%= h[:index].to_s.rjust(3) %>, :<%= h[:name].ljust(12) %> ); end <%- end -%> <%- class_defs.each do |c| -%> class <%= c[:name].capitalize %> <%- c[:fields].each do |p| -%> <%= p[:domain].ljust(10) %> :<%= p[:name].tr('-','_') %> <%- end if c[:fields] -%> <%- c[:methods].each do |m| -%> class <%= m[:name].capitalize.gsub(/-(.)/){ "#{$1.upcase}"}.ljust(12) %> < Method( <%= m[:index].to_s.rjust(3) %>, :<%= m[:name].tr('- ','_').ljust(14) %> ); end <%- end -%> <%- c[:methods].each do |m| -%> class <%= m[:name].capitalize.gsub(/-(.)/){ "#{$1.upcase}"} %> <%- m[:fields].each do |a| -%> <%- if a[:domain] -%> <%= a[:domain].ljust(16) %> :<%= a[:name].tr('- ','_') %> <%- end -%> <%- end -%> end <%- end -%> end <%- end -%> end end ].gsub!(/^ /,''), nil, '>-%').result(binding) ) # Close spec.rb file spec_rb.close # Generate frame.rb file frame_rb = File.open(CONFIG[:frame_out], 'w') frame_rb.puts( ERB.new(%q[ # encoding: utf-8 #:stopdoc: # this file was autogenerated on <%= Time.now.to_s %> # # DO NOT EDIT! (edit ext/qparser.rb and config.yml instead, and run 'ruby qparser.rb') module Qrack module Transport class Frame FOOTER = <%= frame_footer %> ID = 0 @types = { <%- frame_constants.each do |value, name| -%> <%= value %> => '<%= name %>', <%- end -%> } attr_accessor :channel, :payload def initialize payload = nil, channel = 0 @channel, @payload = channel, payload end def id self.class::ID end def to_binary buf = Transport::Buffer.new buf.write :octet, id buf.write :short, channel buf.write :longstr, payload buf.write :octet, FOOTER buf.rewind buf end def to_s to_binary.to_s end def == frame [ :id, :channel, :payload ].inject(true) do |eql, field| eql and __send__(field) == frame.__send__(field) end end def self.parse buf buf = Transport::Buffer.new(buf) unless buf.is_a? Transport::Buffer buf.extract do id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet) Qrack::Transport.const_get(@types[id]).new(payload, channel) if footer == FOOTER end end end class Method < Frame ID = 1 def initialize payload = nil, channel = 0 super unless @payload.is_a? Protocol::Class::Method or @payload.nil? @payload = Protocol.parse(@payload) end end end class Header < Frame ID = 2 def initialize payload = nil, channel = 0 super unless @payload.is_a? Protocol::Header or @payload.nil? @payload = Protocol::Header.new(@payload) end end end <%- frame_constants.each do |value, name| -%> <%- if value > 2 -%> class <%= name %> < Frame ID = <%= value %> end <%- end -%> <%- end -%> end end ].gsub!(/^ /,''), nil, '>-%').result(binding) ) # Close frame.rb file frame_rb.close bunny-0.7.8/ext/amqp-0.9.1.json0000644000076400007640000003760411704323672015030 0ustar pravipravi{ "name": "AMQP", "major-version": 0, "minor-version": 9, "revision": 1, "port": 5672, "copyright": [ "Copyright (C) 2008-2009 LShift Ltd, Cohesive Financial Technologies LLC,\n", "and Rabbit Technologies Ltd\n", "\n", "Permission is hereby granted, free of charge, to any person\n", "obtaining a copy of this file (the \"Software\"), to deal in the\n", "Software without restriction, including without limitation the \n", "rights to use, copy, modify, merge, publish, distribute, \n", "sublicense, and/or sell copies of the Software, and to permit \n", "persons to whom the Software is furnished to do so, subject to \n", "the following conditions:\n", "\n", "The above copyright notice and this permission notice shall be\n", "included in all copies or substantial portions of the Software.\n", "\n", "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n", "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n", "OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n", "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n", "HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n", "WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n", "FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n", "OTHER DEALINGS IN THE SOFTWARE.\n", "\n", "Class information entered from amqp_xml0-8.pdf and domain types from amqp-xml-doc0-9.pdf\n", "Updated for 0-9-1 by Tony Garnock-Jones\n", "\n", "b3cb053f15e7b98808c0ccc67f23cb3e amqp_xml0-8.pdf\n", "http://www.twiststandards.org/index.php?option=com_docman&task=cat_view&gid=28&&Itemid=90\n", "8444db91e2949dbecfb2585e9eef6d64 amqp-xml-doc0-9.pdf\n", "https://jira.amqp.org/confluence/download/attachments/720900/amqp-xml-doc0-9.pdf?version=1\n"], "domains": [ ["bit", "bit"], ["channel-id", "longstr"], ["class-id", "short"], ["consumer-tag", "shortstr"], ["delivery-tag", "longlong"], ["destination", "shortstr"], ["duration", "longlong"], ["exchange-name", "shortstr"], ["long", "long"], ["longlong", "longlong"], ["longstr", "longstr"], ["method-id", "short"], ["no-ack", "bit"], ["no-local", "bit"], ["octet", "octet"], ["offset", "longlong"], ["path", "shortstr"], ["peer-properties", "table"], ["queue-name", "shortstr"], ["redelivered", "bit"], ["reference", "longstr"], ["reject-code", "short"], ["reject-text", "shortstr"], ["reply-code", "short"], ["reply-text", "shortstr"], ["security-token", "longstr"], ["short", "short"], ["shortstr", "shortstr"], ["table", "table"], ["timestamp", "timestamp"] ], "constants": [ {"name": "FRAME-METHOD", "value": 1}, {"name": "FRAME-HEADER", "value": 2}, {"name": "FRAME-BODY", "value": 3}, {"name": "FRAME-HEARTBEAT", "value": 8}, {"name": "FRAME-MIN-SIZE", "value": 4096}, {"name": "FRAME-END", "value": 206}, {"name": "REPLY-SUCCESS", "value": 200}, {"name": "CONTENT-TOO-LARGE", "value": 311, "class": "soft-error"}, {"name": "NO-ROUTE", "value": 312, "class": "soft-error"}, {"name": "NO-CONSUMERS", "value": 313, "class": "soft-error"}, {"name": "ACCESS-REFUSED", "value": 403, "class": "soft-error"}, {"name": "NOT-FOUND", "value": 404, "class": "soft-error"}, {"name": "RESOURCE-LOCKED", "value": 405, "class": "soft-error"}, {"name": "PRECONDITION-FAILED", "value": 406, "class": "soft-error"}, {"name": "CONNECTION-FORCED", "value": 320, "class": "hard-error"}, {"name": "INVALID-PATH", "value": 402, "class": "hard-error"}, {"name": "FRAME-ERROR", "value": 501, "class": "hard-error"}, {"name": "SYNTAX-ERROR", "value": 502, "class": "hard-error"}, {"name": "COMMAND-INVALID", "value": 503, "class": "hard-error"}, {"name": "CHANNEL-ERROR", "value": 504, "class": "hard-error"}, {"name": "UNEXPECTED-FRAME", "value": 505, "class": "hard-error"}, {"name": "RESOURCE-ERROR", "value": 506, "class": "hard-error"}, {"name": "NOT-ALLOWED", "value": 530, "class": "hard-error"}, {"name": "NOT-IMPLEMENTED", "value": 540, "class": "hard-error"}, {"name": "INTERNAL-ERROR", "value": 541, "class": "hard-error"} ], "classes": [ { "id": 10, "methods": [{"id": 10, "arguments": [{"type": "octet", "name": "version-major", "default-value": 0}, {"type": "octet", "name": "version-minor", "default-value": 8}, {"domain": "peer-properties", "name": "server properties"}, {"type": "longstr", "name": "mechanisms", "default-value": "PLAIN"}, {"type": "longstr", "name": "locales", "default-value": "en_US"}], "name": "start"}, {"id": 11, "arguments": [{"domain": "peer-properties", "name": "client-properties"}, {"type": "shortstr", "name": "mechanism", "default-value": "PLAIN"}, {"type": "longstr", "name": "response"}, {"type": "shortstr", "name": "locale", "default-value": "en_US"}], "name": "start-ok"}, {"id": 20, "arguments": [{"type": "longstr", "name": "challenge"}], "name": "secure"}, {"id": 21, "arguments": [{"type": "longstr", "name": "response"}], "name": "secure-ok"}, {"id": 30, "arguments": [{"type": "short", "name": "channel-max", "default-value": 0}, {"type": "long", "name": "frame-max", "default-value": 0}, {"type": "short", "name": "heartbeat", "default-value": 0}], "name": "tune"}, {"id": 31, "arguments": [{"type": "short", "name": "channel-max", "default-value": 0}, {"type": "long", "name": "frame-max", "default-value": 0}, {"type": "short", "name": "heartbeat", "default-value": 0}], "name": "tune-ok"}, {"id": 40, "arguments": [{"type": "shortstr", "name": "virtual-host", "default-value": "/"}, {"type": "shortstr", "name": "deprecated-capabilities", "default-value": ""}, {"type": "bit", "name": "deprecated-insist", "default-value": false}], "name": "open"}, {"id": 41, "arguments": [{"type": "shortstr", "name": "deprecated-known-hosts", "default-value": ""}], "name": "open-ok"}, {"id": 50, "arguments": [{"type": "short", "name": "reply-code"}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "short", "name": "class-id"}, {"type": "short", "name": "method-id"}], "name": "close"}, {"id": 51, "arguments": [], "name": "close-ok"}], "name": "connection", "properties": [] }, { "id": 20, "methods": [{"id": 10, "arguments": [{"type": "shortstr", "name": "deprecated-out-of-band", "default-value": ""}], "name": "open"}, {"id": 11, "arguments": [{"type": "longstr", "name": "deprecated-channel-id", "default-value": ""}], "name": "open-ok"}, {"id": 20, "arguments": [{"type": "bit", "name": "active"}], "name": "flow"}, {"id": 21, "arguments": [{"type": "bit", "name": "active"}], "name": "flow-ok"}, {"id": 40, "arguments": [{"type": "short", "name": "reply-code"}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "short", "name": "class-id"}, {"type": "short", "name": "method-id"}], "name": "close"}, {"id": 41, "arguments": [], "name": "close-ok"}], "name": "channel" }, { "id": 40, "methods": [{"id": 10, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "type", "default-value": "direct"}, {"type": "bit", "name": "passive", "default-value": false}, {"type": "bit", "name": "durable", "default-value": false}, {"type": "bit", "name": "deprecated-auto-delete", "default-value": false}, {"type": "bit", "name": "deprecated-internal", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}, {"type": "table", "name": "arguments", "default-value": {}}], "name": "declare"}, {"id": 11, "arguments": [], "name": "declare-ok"}, {"id": 20, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "exchange"}, {"type": "bit", "name": "if-unused", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "delete"}, {"id": 21, "arguments": [], "name": "delete-ok"}], "name": "exchange" }, { "id": 50, "methods": [{"id": 10, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "queue", "default-value": ""}, {"type": "bit", "name": "passive", "default-value": false}, {"type": "bit", "name": "durable", "default-value": false}, {"type": "bit", "name": "exclusive", "default-value": false}, {"type": "bit", "name": "auto-delete", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}, {"type": "table", "name": "arguments", "default-value": {}}], "name": "declare"}, {"id": 11, "arguments": [{"type": "shortstr", "name": "queue"}, {"type": "long", "name": "message-count"}, {"type": "long", "name": "consumer-count"}], "name": "declare-ok"}, {"id": 20, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}, {"type": "bit", "name": "nowait", "default-value": false}, {"type": "table", "name": "arguments", "default-value": {}}], "name": "bind"}, {"id": 21, "arguments": [], "name": "bind-ok"}, {"id": 30, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "purge"}, {"id": 31, "arguments": [{"type": "long", "name": "message-count"}], "name": "purge-ok"}, {"id": 40, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "bit", "name": "if-unused", "default-value": false}, {"type": "bit", "name": "if-empty", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "delete"}, {"id": 41, "arguments": [{"type": "long", "name": "message-count"}], "name": "delete-ok"}, {"id": 50, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}, {"type": "table", "name": "arguments"}], "name": "unbind"}, {"id": 51, "arguments": [], "name": "unbind-ok"} ], "name": "queue" }, { "id": 60, "methods": [{"id": 10, "arguments": [{"type": "long", "name": "prefetch-size", "default-value": 0}, {"type": "short", "name": "prefetch-count", "default-value": 0}, {"type": "bit", "name": "global", "default-value": false}], "name": "qos"}, {"id": 11, "arguments": [], "name": "qos-ok"}, {"id": 20, "arguments": [{"domain": "short", "name": "deprecated-ticket", "default-value": 1}, {"domain": "queue-name", "name": "queue"}, {"type": "shortstr", "name": "consumer-tag"}, {"type": "bit", "name": "no-local", "default-value": false}, {"type": "bit", "name": "no-ack", "default-value": false}, {"type": "bit", "name": "exclusive", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}, {"type": "table", "name": "filter", "default-value": {}}], "name": "consume"}, {"id": 21, "arguments": [{"type": "shortstr", "name": "consumer-tag"}], "name": "consume-ok"}, {"id": 30, "arguments": [{"type": "shortstr", "name": "consumer-tag"}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "cancel"}, {"id": 31, "arguments": [{"type": "shortstr", "name": "consumer-tag"}], "name": "cancel-ok"}, {"content": true, "id": 40, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "exchange", "default-value": ""}, {"type": "shortstr", "name": "routing-key"}, {"type": "bit", "name": "mandatory", "default-value": false}, {"type": "bit", "name": "immediate", "default-value": false}], "name": "publish"}, {"content": true, "id": 50, "arguments": [{"type": "short", "name": "reply-code"}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}], "name": "return"}, {"content": true, "id": 60, "arguments": [{"type": "shortstr", "name": "consumer-tag"}, {"type": "longlong", "name": "delivery-tag"}, {"type": "bit", "name": "redelivered", "default-value": false}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}], "name": "deliver"}, {"id": 70, "arguments": [{"type": "short", "name": "deprecated-ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "bit", "name": "no-ack", "default-value": false}], "name": "get"}, {"content": true, "id": 71, "arguments": [{"type": "longlong", "name": "delivery-tag"}, {"type": "bit", "name": "redelivered", "default-value": false}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}, {"type": "long", "name": "message-count"}], "name": "get-ok"}, {"id": 72, "arguments": [{"type": "shortstr", "name": "deprecated-cluster-id", "default-value": ""}], "name": "get-empty"}, {"id": 80, "arguments": [{"type": "longlong", "name": "delivery-tag", "default-value": 0}, {"type": "bit", "name": "multiple", "default-value": true}], "name": "ack"}, {"id": 90, "arguments": [{"type": "longlong", "name": "delivery-tag"}, {"type": "bit", "name": "requeue", "default-value": true}], "name": "reject"}, {"id": 100, "arguments": [{"type": "bit", "name": "requeue", "default-value": false}], "name": "recover-async"}, {"id": 110, "arguments": [{"type": "bit", "name": "requeue", "default-value": false}], "name": "recover"}, {"id": 111, "arguments": [], "name": "recover-ok"}], "name": "basic", "properties": [{"type": "shortstr", "name": "content-type"}, {"type": "shortstr", "name": "content-encoding"}, {"type": "table", "name": "headers"}, {"type": "octet", "name": "delivery-mode"}, {"type": "octet", "name": "priority"}, {"type": "shortstr", "name": "correlation-id"}, {"type": "shortstr", "name": "reply-to"}, {"type": "shortstr", "name": "expiration"}, {"type": "shortstr", "name": "message-id"}, {"type": "timestamp", "name": "timestamp"}, {"type": "shortstr", "name": "type"}, {"type": "shortstr", "name": "user-id"}, {"type": "shortstr", "name": "app-id"}, {"type": "shortstr", "name": "deprecated-cluster-id"}] }, { "id": 90, "methods": [{"id": 10, "arguments": [], "name": "select"}, {"id": 11, "arguments": [], "name": "select-ok"}, {"id": 20, "arguments": [], "name": "commit"}, {"id": 21, "arguments": [], "name": "commit-ok"}, {"id": 30, "arguments": [], "name": "rollback"}, {"id": 31, "arguments": [], "name": "rollback-ok"}], "name": "tx" } ] } bunny-0.7.8/ext/config.yml0000644000076400007640000000017311704323672014513 0ustar pravipravi--- :spec_out: '../lib/qrack/protocol/spec08.rb' :frame_out: '../lib/qrack/transport/frame08.rb' :spec_in: 'amqp-0.8.json' bunny-0.7.8/ext/amqp-0.8.json0000644000076400007640000006122711704323672014666 0ustar pravipravi{ "name": "AMQP", "major-version": 8, "minor-version": 0, "port": 5672, "copyright": [ "Copyright (C) 2008-2009 LShift Ltd, Cohesive Financial Technologies LLC,\n", "and Rabbit Technologies Ltd\n", "\n", "Permission is hereby granted, free of charge, to any person\n", "obtaining a copy of this file (the \"Software\"), to deal in the\n", "Software without restriction, including without limitation the \n", "rights to use, copy, modify, merge, publish, distribute, \n", "sublicense, and/or sell copies of the Software, and to permit \n", "persons to whom the Software is furnished to do so, subject to \n", "the following conditions:\n", "\n", "The above copyright notice and this permission notice shall be\n", "included in all copies or substantial portions of the Software.\n", "\n", "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n", "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n", "OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n", "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n", "HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n", "WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n", "FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n", "OTHER DEALINGS IN THE SOFTWARE.\n", "\n", "Class information entered from amqp_xml0-8.pdf and domain types from amqp-xml-doc0-9.pdf\n", "\n", "b3cb053f15e7b98808c0ccc67f23cb3e amqp_xml0-8.pdf\n", "http://www.twiststandards.org/index.php?option=com_docman&task=cat_view&gid=28&&Itemid=90\n", "8444db91e2949dbecfb2585e9eef6d64 amqp-xml-doc0-9.pdf\n", "https://jira.amqp.org/confluence/download/attachments/720900/amqp-xml-doc0-9.pdf?version=1\n"], "domains": [ ["access-ticket", "short"], ["bit", "bit"], ["channel-id", "longstr"], ["class-id", "short"], ["consumer-tag", "shortstr"], ["delivery-tag", "longlong"], ["destination", "shortstr"], ["duration", "longlong"], ["exchange-name", "shortstr"], ["known-hosts", "shortstr"], ["long", "long"], ["longlong", "longlong"], ["longstr", "longstr"], ["method-id", "short"], ["no-ack", "bit"], ["no-local", "bit"], ["octet", "octet"], ["offset", "longlong"], ["path", "shortstr"], ["peer-properties", "table"], ["queue-name", "shortstr"], ["redelivered", "bit"], ["reference", "longstr"], ["reject-code", "short"], ["reject-text", "shortstr"], ["reply-code", "short"], ["reply-text", "shortstr"], ["security-token", "longstr"], ["short", "short"], ["shortstr", "shortstr"], ["table", "table"], ["timestamp", "timestamp"] ], "constants": [ {"name": "FRAME-METHOD", "value": 1}, {"name": "FRAME-HEADER", "value": 2}, {"name": "FRAME-BODY", "value": 3}, {"name": "FRAME-OOB-METHOD", "value": 4}, {"name": "FRAME-OOB-HEADER", "value": 5}, {"name": "FRAME-OOB-BODY", "value": 6}, {"name": "FRAME-TRACE", "value": 7}, {"name": "FRAME-HEARTBEAT", "value": 8}, {"name": "FRAME-MIN-SIZE", "value": 4096}, {"name": "FRAME-END", "value": 206}, {"name": "REPLY-SUCCESS", "value": 200}, {"name": "NOT-DELIVERED", "value": 310, "class": "soft-error"}, {"name": "CONTENT-TOO-LARGE", "value": 311, "class": "soft-error"}, {"name": "NO-ROUTE", "value": 312, "class": "soft-error"}, {"name": "NO-CONSUMERS", "value": 313, "class": "soft-error"}, {"name": "ACCESS-REFUSED", "value": 403, "class": "soft-error"}, {"name": "NOT-FOUND", "value": 404, "class": "soft-error"}, {"name": "RESOURCE-LOCKED", "value": 405, "class": "soft-error"}, {"name": "PRECONDITION-FAILED", "value": 406, "class": "soft-error"}, {"name": "CONNECTION-FORCED", "value": 320, "class": "hard-error"}, {"name": "INVALID-PATH", "value": 402, "class": "hard-error"}, {"name": "FRAME-ERROR", "value": 501, "class": "hard-error"}, {"name": "SYNTAX-ERROR", "value": 502, "class": "hard-error"}, {"name": "COMMAND-INVALID", "value": 503, "class": "hard-error"}, {"name": "CHANNEL-ERROR", "value": 504, "class": "hard-error"}, {"name": "RESOURCE-ERROR", "value": 506, "class": "hard-error"}, {"name": "NOT-ALLOWED", "value": 530, "class": "hard-error"}, {"name": "NOT-IMPLEMENTED", "value": 540, "class": "hard-error"}, {"name": "INTERNAL-ERROR", "value": 541, "class": "hard-error"} ], "classes": [ { "id": 10, "methods": [{"id": 10, "arguments": [{"type": "octet", "name": "version-major", "default-value": 0}, {"type": "octet", "name": "version-minor", "default-value": 8}, {"domain": "peer-properties", "name": "server properties"}, {"type": "longstr", "name": "mechanisms", "default-value": "PLAIN"}, {"type": "longstr", "name": "locales", "default-value": "en_US"}], "name": "start"}, {"id": 11, "arguments": [{"domain": "peer-properties", "name": "client-properties"}, {"type": "shortstr", "name": "mechanism", "default-value": "PLAIN"}, {"type": "longstr", "name": "response"}, {"type": "shortstr", "name": "locale", "default-value": "en_US"}], "name": "start-ok"}, {"id": 20, "arguments": [{"type": "longstr", "name": "challenge"}], "name": "secure"}, {"id": 21, "arguments": [{"type": "longstr", "name": "response"}], "name": "secure-ok"}, {"id": 30, "arguments": [{"type": "short", "name": "channel-max", "default-value": 0}, {"type": "long", "name": "frame-max", "default-value": 0}, {"type": "short", "name": "heartbeat", "default-value": 0}], "name": "tune"}, {"id": 31, "arguments": [{"type": "short", "name": "channel-max", "default-value": 0}, {"type": "long", "name": "frame-max", "default-value": 0}, {"type": "short", "name": "heartbeat", "default-value": 0}], "name": "tune-ok"}, {"id": 40, "arguments": [{"type": "shortstr", "name": "virtual-host", "default-value": "/"}, {"type": "shortstr", "name": "capabilities", "default-value": ""}, {"type": "bit", "name": "insist", "default-value": false}], "name": "open"}, {"id": 41, "arguments": [{"type": "shortstr", "name": "known-hosts", "default-value": ""}], "name": "open-ok"}, {"id": 50, "arguments": [{"type": "shortstr", "name": "host"}, {"type": "shortstr", "name": "known-hosts", "default-value": ""}], "name": "redirect"}, {"id": 60, "arguments": [{"type": "short", "name": "reply-code"}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "short", "name": "class-id"}, {"type": "short", "name": "method-id"}], "name": "close"}, {"id": 61, "arguments": [], "name": "close-ok"}], "name": "connection", "properties": [] }, { "id": 20, "methods": [{"id": 10, "arguments": [{"type": "shortstr", "name": "out-of-band", "default-value": ""}], "name": "open"}, {"id": 11, "arguments": [], "name": "open-ok"}, {"id": 20, "arguments": [{"type": "bit", "name": "active"}], "name": "flow"}, {"id": 21, "arguments": [{"type": "bit", "name": "active"}], "name": "flow-ok"}, {"id": 30, "arguments": [{"type": "short", "name": "reply-code"}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "table", "name": "details", "default-value": {}}], "name": "alert"}, {"id": 40, "arguments": [{"type": "short", "name": "reply-code"}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "short", "name": "class-id"}, {"type": "short", "name": "method-id"}], "name": "close"}, {"id": 41, "arguments": [], "name": "close-ok"}], "name": "channel" }, { "id": 30, "methods": [{"id": 10, "arguments": [{"type": "shortstr", "name": "realm", "default-value": "/data"}, {"type": "bit", "name": "exclusive", "default-value": false}, {"type": "bit", "name": "passive", "default-value": true}, {"type": "bit", "name": "active", "default-value": true}, {"type": "bit", "name": "write", "default-value": true}, {"type": "bit", "name": "read", "default-value": true}], "name": "request"}, {"id": 11, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}], "name": "request-ok"}], "name": "access" }, { "id": 40, "methods": [{"id": 10, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "type", "default-value": "direct"}, {"type": "bit", "name": "passive", "default-value": false}, {"type": "bit", "name": "durable", "default-value": false}, {"type": "bit", "name": "auto-delete", "default-value": false}, {"type": "bit", "name": "internal", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}, {"type": "table", "name": "arguments", "default-value": {}}], "name": "declare"}, {"id": 11, "arguments": [], "name": "declare-ok"}, {"id": 20, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "exchange"}, {"type": "bit", "name": "if-unused", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "delete"}, {"id": 21, "arguments": [], "name": "delete-ok"}], "name": "exchange" }, { "id": 50, "methods": [{"id": 10, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "queue", "default-value": ""}, {"type": "bit", "name": "passive", "default-value": false}, {"type": "bit", "name": "durable", "default-value": false}, {"type": "bit", "name": "exclusive", "default-value": false}, {"type": "bit", "name": "auto-delete", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}, {"type": "table", "name": "arguments", "default-value": {}}], "name": "declare"}, {"id": 11, "arguments": [{"type": "shortstr", "name": "queue"}, {"type": "long", "name": "message-count"}, {"type": "long", "name": "consumer-count"}], "name": "declare-ok"}, {"id": 20, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}, {"type": "bit", "name": "nowait", "default-value": false}, {"type": "table", "name": "arguments", "default-value": {}}], "name": "bind"}, {"id": 21, "arguments": [], "name": "bind-ok"}, {"id": 30, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "purge"}, {"id": 31, "arguments": [{"type": "long", "name": "message-count"}], "name": "purge-ok"}, {"id": 40, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "bit", "name": "if-unused", "default-value": false}, {"type": "bit", "name": "if-empty", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "delete"}, {"id": 41, "arguments": [{"type": "long", "name": "message-count"}], "name": "delete-ok"}, {"id": 50, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}, {"type": "table", "name": "arguments"}], "name": "unbind"}, {"id": 51, "arguments": [], "name": "unbind-ok"} ], "name": "queue" }, { "id": 60, "methods": [{"id": 10, "arguments": [{"type": "long", "name": "prefetch-size", "default-value": 0}, {"type": "short", "name": "prefetch-count", "default-value": 0}, {"type": "bit", "name": "global", "default-value": false}], "name": "qos"}, {"id": 11, "arguments": [], "name": "qos-ok"}, {"id": 20, "arguments": [{"domain": "access-ticket", "name": "ticket", "default-value": 1}, {"domain": "queue-name", "name": "queue"}, {"type": "shortstr", "name": "consumer-tag"}, {"type": "bit", "name": "no-local", "default-value": false}, {"type": "bit", "name": "no-ack", "default-value": false}, {"type": "bit", "name": "exclusive", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "consume"}, {"id": 21, "arguments": [{"type": "shortstr", "name": "consumer-tag"}], "name": "consume-ok"}, {"id": 30, "arguments": [{"type": "shortstr", "name": "consumer-tag"}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "cancel"}, {"id": 31, "arguments": [{"type": "shortstr", "name": "consumer-tag"}], "name": "cancel-ok"}, {"content": true, "id": 40, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "exchange", "default-value": ""}, {"type": "shortstr", "name": "routing-key"}, {"type": "bit", "name": "mandatory", "default-value": false}, {"type": "bit", "name": "immediate", "default-value": false}], "name": "publish"}, {"content": true, "id": 50, "arguments": [{"type": "short", "name": "reply-code"}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}], "name": "return"}, {"content": true, "id": 60, "arguments": [{"type": "shortstr", "name": "consumer-tag"}, {"type": "longlong", "name": "delivery-tag"}, {"type": "bit", "name": "redelivered", "default-value": false}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}], "name": "deliver"}, {"id": 70, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "bit", "name": "no-ack", "default-value": false}], "name": "get"}, {"content": true, "id": 71, "arguments": [{"type": "longlong", "name": "delivery-tag"}, {"type": "bit", "name": "redelivered", "default-value": false}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}, {"type": "long", "name": "message-count"}], "name": "get-ok"}, {"id": 72, "arguments": [{"type": "shortstr", "name": "cluster-id", "default-value": ""}], "name": "get-empty"}, {"id": 80, "arguments": [{"type": "longlong", "name": "delivery-tag", "default-value": 0}, {"type": "bit", "name": "multiple", "default-value": true}], "name": "ack"}, {"id": 90, "arguments": [{"type": "longlong", "name": "delivery-tag"}, {"type": "bit", "name": "requeue", "default-value": true}], "name": "reject"}, {"id": 100, "arguments": [{"type": "bit", "name": "requeue", "default-value": false}], "name": "recover"}], "name": "basic", "properties": [{"type": "shortstr", "name": "content-type"}, {"type": "shortstr", "name": "content-encoding"}, {"type": "table", "name": "headers"}, {"type": "octet", "name": "delivery-mode"}, {"type": "octet", "name": "priority"}, {"type": "shortstr", "name": "correlation-id"}, {"type": "shortstr", "name": "reply-to"}, {"type": "shortstr", "name": "expiration"}, {"type": "shortstr", "name": "message-id"}, {"type": "timestamp", "name": "timestamp"}, {"type": "shortstr", "name": "type"}, {"type": "shortstr", "name": "user-id"}, {"type": "shortstr", "name": "app-id"}, {"type": "shortstr", "name": "cluster-id"}] }, { "id": 70, "methods": [{"id": 10, "arguments": [{"type": "long", "name": "prefetch-size", "default-value": 0}, {"type": "short", "name": "prefetch-count", "default-value": 0}, {"type": "bit", "name": "global", "default-value": false}], "name": "qos"}, {"id": 11, "arguments": [], "name": "qos-ok"}, {"id": 20, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "shortstr", "name": "consumer-tag"}, {"type": "bit", "name": "no-local", "default-value": false}, {"type": "bit", "name": "no-ack", "default-value": false}, {"type": "bit", "name": "exclusive", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "consume"}, {"id": 21, "arguments": [{"type": "shortstr", "name": "consumer-tag"}], "name": "consume-ok"}, {"id": 30, "arguments": [{"type": "shortstr", "name": "consumer-tag"}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "cancel"}, {"id": 31, "arguments": [{"type": "shortstr", "name": "consumer-tag"}], "name": "cancel-ok"}, {"id": 40, "arguments": [{"type": "shortstr", "name": "identifier"}, {"type": "longlong", "name": "content-size"}], "name": "open"}, {"id": 41, "arguments": [{"type": "longlong", "name": "staged-size"}], "name": "open-ok"}, {"content": true, "id": 50, "arguments": [], "name": "stage"}, {"id": 60, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "exchange", "default-value": ""}, {"type": "shortstr", "name": "routing-key"}, {"type": "bit", "name": "mandatory", "default-value": false}, {"type": "bit", "name": "immediate", "default-value": false}, {"type": "shortstr", "name": "identifier"}], "name": "publish"}, {"content": true, "id": 70, "arguments": [{"type": "short", "name": "reply-code", "default-value": 200}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}], "name": "return"}, {"id": 80, "arguments": [{"type": "shortstr", "name": "consumer-tag"}, {"type": "longlong", "name": "delivery-tag"}, {"type": "bit", "name": "redelivered", "default-value": false}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}, {"type": "shortstr", "name": "identifier"}], "name": "deliver"}, {"id": 90, "arguments": [{"type": "longlong", "name": "delivery-tag", "default-value": 0}, {"type": "bit", "name": "multiple", "default-value": true}], "name": "ack"}, {"id": 100, "arguments": [{"type": "longlong", "name": "delivery-tag"}, {"type": "bit", "name": "requeue", "default-value": true}], "name": "reject"}], "name": "file", "properties": [{"type": "shortstr", "name": "content-type"}, {"type": "shortstr", "name": "content-encoding"}, {"type": "table", "name": "headers"}, {"type": "octet", "name": "priority"}, {"type": "shortstr", "name": "reply-to"}, {"type": "shortstr", "name": "message-id"}, {"type": "shortstr", "name": "filename"}, {"type": "timestamp", "name": "timestamp"}, {"type": "shortstr", "name": "cluster-id"}] }, { "id": 80, "methods": [{"id": 10, "arguments": [{"type": "long", "name": "prefetch-size", "default-value": 0}, {"type": "short", "name": "prefetch-count", "default-value": 0}, {"type": "long", "name": "consume-rate", "default-value": 0}, {"type": "bit", "name": "global", "default-value": false}], "name": "qos"}, {"id": 11, "arguments": [], "name": "qos-ok"}, {"id": 20, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "queue"}, {"type": "shortstr", "name": "consumer-tag", "default-value": ""}, {"type": "bit", "name": "no-local", "default-value": false}, {"type": "bit", "name": "exclusive", "default-value": false}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "consume"}, {"id": 21, "arguments": [{"type": "shortstr", "name": "consumer-tag"}], "name": "consume-ok"}, {"id": 30, "arguments": [{"type": "shortstr", "name": "consumer-tag"}, {"type": "bit", "name": "nowait", "default-value": false}], "name": "cancel"}, {"id": 31, "arguments": [{"type": "shortstr", "name": "consumer-tag"}], "name": "cancel-ok"}, {"content": true, "id": 40, "arguments": [{"type": "short", "name": "ticket", "default-value": 1}, {"type": "shortstr", "name": "exchange", "default-value": ""}, {"type": "shortstr", "name": "routing-key"}, {"type": "bit", "name": "mandatory", "default-value": false}, {"type": "bit", "name": "immediate", "default-value": false}], "name": "publish"}, {"content": true, "id": 50, "arguments": [{"type": "short", "name": "reply-code", "default-value": 200}, {"type": "shortstr", "name": "reply-text", "default-value": ""}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "routing-key"}], "name": "return"}, {"content": true, "id": 60, "arguments": [{"type": "shortstr", "name": "consumer-tag"}, {"type": "longlong", "name": "delivery-tag"}, {"type": "shortstr", "name": "exchange"}, {"type": "shortstr", "name": "queue"}], "name": "deliver"}], "name": "stream", "properties": [{"type": "shortstr", "name": "content-type"}, {"type": "shortstr", "name": "content-encoding"}, {"type": "table", "name": "headers"}, {"type": "octet", "name": "priority"}, {"type": "timestamp", "name": "timestamp"}] }, { "id": 90, "methods": [{"id": 10, "arguments": [], "name": "select"}, {"id": 11, "arguments": [], "name": "select-ok"}, {"id": 20, "arguments": [], "name": "commit"}, {"id": 21, "arguments": [], "name": "commit-ok"}, {"id": 30, "arguments": [], "name": "rollback"}, {"id": 31, "arguments": [], "name": "rollback-ok"}], "name": "tx" }, { "id": 100, "methods": [{"id": 10, "arguments": [], "name": "select"}, {"id": 11, "arguments": [], "name": "select-ok"}, {"id": 20, "arguments": [{"type": "shortstr", "name": "dtx-identifier"}], "name": "start"}, {"id": 21, "arguments": [], "name": "start-ok"}], "name": "dtx" }, { "id": 110, "methods": [{"content": true, "id": 10, "arguments": [{"type": "table", "name": "meta-data"}], "name": "request"}], "name": "tunnel", "properties": [{"type": "table", "name": "headers"}, {"type": "shortstr", "name": "proxy-name"}, {"type": "shortstr", "name": "data-name"}, {"type": "octet", "name": "durable"}, {"type": "octet", "name": "broadcast"}] }, { "id": 120, "methods": [{"id": 10, "arguments": [{"type": "octet", "name": "integer-1"}, {"type": "short", "name": "integer-2"}, {"type": "long", "name": "integer-3"}, {"type": "longlong", "name": "integer-4"}, {"type": "octet", "name": "operation"}], "name": "integer"}, {"id": 11, "arguments": [{"type": "longlong", "name": "result"}], "name": "integer-ok"}, {"id": 20, "arguments": [{"type": "shortstr", "name": "string-1"}, {"type": "longstr", "name": "string-2"}, {"type": "octet", "name": "operation"}], "name": "string"}, {"id": 21, "arguments": [{"type": "longstr", "name": "result"}], "name": "string-ok"}, {"id": 30, "arguments": [{"type": "table", "name": "table"}, {"type": "octet", "name": "integer-op"}, {"type": "octet", "name": "string-op"}], "name": "table"}, {"id": 31, "arguments": [{"type": "longlong", "name": "integer-result"}, {"type": "longstr", "name": "string-result"}], "name": "table-ok"}, {"content": true, "id": 40, "arguments": [], "name": "content"}, {"content": true, "id": 41, "arguments": [{"type": "long", "name": "content-checksum"}], "name": "content-ok"}], "name": "test" } ] } bunny-0.7.8/.gitignore0000644000076400007640000000011611704323672013710 0ustar pravipravi.DS_Store .*.swp *.class *.rbc *.gem /doc/ .yardoc .rvmrc Gemfile.lock .rbx/* bunny-0.7.8/bunny.gemspec0000755000076400007640000000232611704323672014430 0ustar pravipravi#!/usr/bin/env gem build # encoding: utf-8 require "base64" require File.expand_path("../lib/bunny/version", __FILE__) Gem::Specification.new do |s| s.name = "bunny" s.version = Bunny::VERSION.dup s.homepage = "http://github.com/ruby-amqp/bunny" s.summary = "Synchronous Ruby AMQP 0.9.1 client" s.description = "A synchronous Ruby AMQP client that enables interaction with AMQP-compliant brokers." # Sorted alphabetically. s.authors = [ "Chris Duncan", "Eric Lindvall", "Jakub Stastny aka botanicus", "Michael S. Klishin", "Stefan Kaes"] s.email = [ "Y2VsbGRlZUBnbWFpbC5jb20=\n", "ZXJpY0A1c3RvcHMuY29t\n", "c3Rhc3RueUAxMDFpZGVhcy5jeg==\n", "bWljaGFlbEBub3ZlbWJlcmFpbi5jb20=\n", "c2thZXNAcmFpbHNleHByZXNzLmRl\n"]. map { |mail| Base64.decode64(mail) } # Files. s.has_rdoc = true s.extra_rdoc_files = ["README.textile"] s.rdoc_options = ["--main", "README.rdoc"] s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- spec/*`.split("\n") s.require_paths = ["lib"] begin require "changelog" s.post_install_message = CHANGELOG.new.version_changes rescue LoadError end # RubyForge s.rubyforge_project = "bunny-amqp" end bunny-0.7.8/spec/0000755000076400007640000000000011704323672012654 5ustar pravipravibunny-0.7.8/spec/spec_08/0000755000076400007640000000000011704323672014115 5ustar pravipravibunny-0.7.8/spec/spec_08/bunny_spec.rb0000644000076400007640000000376411704323672016621 0ustar pravipravi# encoding: utf-8 # bunny_spec.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. lib bunny])) describe Bunny do before(:each) do @b = Bunny.new @b.start end after(:each) do begin @b.stop rescue Exception ensure @b = nil end end it "should connect to an AMQP server" do @b.status.should == :connected end it "should be able to create and open a new channel" do c = @b.create_channel c.number.should == 2 c.should be_an_instance_of(Bunny::Channel) @b.channels.size.should == 3 c.open.should == :open_ok @b.channel.number.should == 2 end it "should be able to switch between channels" do @b.channel.number.should == 1 @b.switch_channel(0) @b.channel.number.should == 0 end it "should raise an error if trying to switch to a non-existent channel" do lambda { @b.switch_channel(5)}.should raise_error(RuntimeError) end it "should be able to create an exchange" do exch = @b.exchange('test_exchange') exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'test_exchange' @b.exchanges.has_key?('test_exchange').should be(true) end it "should be able to create a queue" do q = @b.queue('test1') q.should be_an_instance_of(Bunny::Queue) q.name.should == 'test1' @b.queues.has_key?('test1').should be(true) end # Current RabbitMQ has not implemented some functionality it "should raise an error if setting of QoS fails" do lambda { @b.qos(:global => true) }.should raise_error(Bunny::ForcedConnectionCloseError) @b.status.should == :not_connected end it "should be able to set QoS" do @b.qos.should == :qos_ok end end bunny-0.7.8/spec/spec_08/queue_spec.rb0000644000076400007640000001571311704323672016607 0ustar pravipravi# encoding: utf-8 # queue_spec.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. lib bunny])) describe 'Queue' do def expect_deprecation_warning_for_publishing_on_queue(q, n=1) Bunny.should_receive(:deprecation_warning).with("Qrack::Queue#publish", "0.8", anything).exactly(n).times end def message_count(queue, sleep_time = 0.1) sleep sleep_time queue.message_count end before(:each) do @b = Bunny.new @b.start end after(:each) do begin @b.stop rescue Exception ensure @b = nil end end it "should ignore the :nowait option when instantiated" do q = @b.queue('test0', :nowait => true) end it "should ignore the :nowait option when binding to an exchange" do exch = @b.exchange('direct_exch') q = @b.queue('test0') q.bind(exch, :nowait => true).should == :bind_ok end it "should raise an error when trying to bind to a non-existent exchange" do q = @b.queue('test1') lambda {q.bind('bogus')}.should raise_error(Bunny::ForcedChannelCloseError) @b.channel.active.should == false end it "should be able to bind to an existing exchange" do exch = @b.exchange('direct_exch') q = @b.queue('test1') q.bind(exch).should == :bind_ok end it "should ignore the :nowait option when unbinding from an exchange" do exch = @b.exchange('direct_exch') q = @b.queue('test0') q.unbind(exch, :nowait => true).should == :unbind_ok end it "should raise an error if unbinding from a non-existent exchange" do q = @b.queue('test1') lambda {q.unbind('bogus')}.should raise_error(Bunny::ForcedChannelCloseError) @b.channel.active.should == false end it "should be able to unbind from an existing exchange" do exch = @b.exchange('direct_exch') q = @b.queue('test1') q.unbind(exch).should == :unbind_ok end it "should be able to publish a message" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q) q.publish('This is a test message') message_count(q).should == 1 end it "should be able to pop a message complete with header and delivery details" do q = @b.queue('test1') msg = q.pop() msg.should be_an_instance_of(Hash) msg[:header].should be_an_instance_of(Bunny::Protocol::Header) msg[:payload].should == 'This is a test message' msg[:delivery_details].should be_an_instance_of(Hash) message_count(q).should == 0 end it "should be able to pop a message and just get the payload" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q) q.publish('This is another test message') msg = q.pop[:payload] msg.should == 'This is another test message' message_count(q).should == 0 end it "should be able to pop a message where body length exceeds max frame size" do q = @b.queue('test1') lg_msg = 'z' * 142000 expect_deprecation_warning_for_publishing_on_queue(q) q.publish(lg_msg) msg = q.pop[:payload] msg.should == lg_msg end it "should be able call a block when popping a message" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q) q.publish('This is another test message') q.pop { |msg| msg[:payload].should == 'This is another test message' } q.pop { |msg| msg[:payload].should == :queue_empty } end it "should raise an error if purge fails" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q, 5) 5.times {q.publish('This is another test message')} message_count(q).should == 5 lambda {q.purge(:queue => 'bogus')}.should raise_error(Bunny::ForcedChannelCloseError) end it "should be able to be purged to remove all of its messages" do q = @b.queue('test1') message_count(q).should == 5 q.purge.should == :purge_ok message_count(q).should == 0 end it "should return an empty message when popping an empty queue" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q) q.publish('This is another test message') q.pop msg = q.pop[:payload] msg.should == :queue_empty end it "should stop subscription without processing messages if max specified is 0" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q, 5) 5.times {q.publish('Yet another test message')} message_count(q).should == 5 q.subscribe(:message_max => 0) message_count(q).should == 5 q.purge.should == :purge_ok end it "should stop subscription after processing number of messages specified > 0" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q, 5) 5.times {q.publish('Yet another test message')} message_count(q).should == 5 q.subscribe(:message_max => 5) end it "should stop subscription after processing message_max messages < total in queue" do q = @b.queue('test1') @b.qos() expect_deprecation_warning_for_publishing_on_queue(q, 10) 10.times {q.publish('Yet another test message')} message_count(q).should == 10 q.subscribe(:message_max => 5, :ack => true) message_count(q).should == 5 q.purge.should == :purge_ok end it "should raise an error when delete fails" do q = @b.queue('test1') lambda {q.delete(:queue => 'bogus')}.should raise_error(Bunny::ForcedChannelCloseError) @b.channel.active.should == false end it "should pass correct block parameters through on subscribe" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q) q.publish("messages pop\'n") q.subscribe do |msg| msg[:header].should be_an_instance_of Qrack::Protocol::Header msg[:payload].should == "messages pop'n" msg[:delivery_details].should_not be_nil q.unsubscribe break end end it "should finish processing subscription messages if break is called in block" do q = @b.queue('test1') expect_deprecation_warning_for_publishing_on_queue(q, 6) q.publish('messages in my quezen') q.subscribe do |msg| msg[:payload].should == 'messages in my quezen' q.unsubscribe break end 5.times {|i| q.publish("#{i}")} q.subscribe do |msg| if msg[:payload] == '4' q.unsubscribe break end end end it "should be able to be deleted" do q = @b.queue('test1') res = q.delete res.should == :delete_ok @b.queues.has_key?('test1').should be(false) end it "should ignore the :nowait option when deleted" do q = @b.queue('test0') q.delete(:nowait => true) end it "should support server named queues" do q = @b.queue q.name.should_not == nil @b.queue(q.name).should == q q.delete end end bunny-0.7.8/spec/spec_08/connection_spec.rb0000644000076400007640000000116411704323672017615 0ustar pravipravi# encoding: utf-8 # connection_spec.rb require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. lib bunny])) describe Bunny do it "should raise an error if the wrong user name or password is used" do b = Bunny.new(:user => 'wrong') lambda { b.start}.should raise_error(Bunny::ProtocolError) end it "should be able to open a TCPSocket with a timeout" do b = Bunny.new(:spec => "0.8") connect_timeout = 5 lambda { Bunny::Timer::timeout(connect_timeout, Qrack::ConnectionTimeout) do TCPSocket.new(b.host, b.port) end }.should_not raise_error(Exception) end end bunny-0.7.8/spec/spec_08/exchange_spec.rb0000644000076400007640000001367311704323672017250 0ustar pravipravi# encoding: utf-8 # exchange_spec.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. lib bunny])) describe 'Exchange' do before(:each) do @b = Bunny.new @b.start end after(:each) do begin @b.stop rescue Exception ensure @b = nil end end it "should raise an error if instantiated as non-existent type" do lambda { @b.exchange('bogus_ex', :type => :bogus) }.should raise_error(Bunny::ForcedConnectionCloseError) @b.status.should == :not_connected end it "should allow a default direct exchange to be instantiated by specifying :type" do exch = @b.exchange('amq.direct', :type => :direct) exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'amq.direct' exch.type.should == :direct @b.exchanges.has_key?('amq.direct').should be(true) end it "should allow a default direct exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.direct') exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'amq.direct' exch.type.should == :direct @b.exchanges.has_key?('amq.direct').should be(true) end it "should allow a default fanout exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.fanout') exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'amq.fanout' exch.type.should == :fanout @b.exchanges.has_key?('amq.fanout').should be(true) end it "should allow a default topic exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.topic') exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'amq.topic' exch.type.should == :topic @b.exchanges.has_key?('amq.topic').should be(true) end it "should allow a default headers (amq.match) exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.match') exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'amq.match' exch.type.should == :headers @b.exchanges.has_key?('amq.match').should be(true) end it "should allow a default headers (amq.headers) exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.headers') exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'amq.headers' exch.type.should == :headers @b.exchanges.has_key?('amq.headers').should be(true) end it "should create an exchange as direct by default" do exch = @b.exchange('direct_defaultex') exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'direct_defaultex' exch.type.should == :direct @b.exchanges.has_key?('direct_defaultex').should be(true) end it "should be able to be instantiated as a direct exchange" do exch = @b.exchange('direct_exchange', :type => :direct) exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'direct_exchange' exch.type.should == :direct @b.exchanges.has_key?('direct_exchange').should be(true) end it "should be able to be instantiated as a topic exchange" do exch = @b.exchange('topic_exchange', :type => :topic) exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'topic_exchange' exch.type.should == :topic @b.exchanges.has_key?('topic_exchange').should be(true) end it "should be able to be instantiated as a fanout exchange" do exch = @b.exchange('fanout_exchange', :type => :fanout) exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'fanout_exchange' exch.type.should == :fanout @b.exchanges.has_key?('fanout_exchange').should be(true) end it "should be able to be instantiated as a headers exchange" do exch = @b.exchange('headers_exchange', :type => :headers) exch.should be_an_instance_of(Bunny::Exchange) exch.name.should == 'headers_exchange' exch.type.should == :headers @b.exchanges.has_key?('headers_exchange').should be(true) end it "should ignore the :nowait option when instantiated" do exch = @b.exchange('direct2_exchange', :nowait => true) end it "should be able to publish a message" do exch = @b.exchange('direct_exchange') exch.publish('This is a published message') end it "should not modify the passed options hash when publishing a message" do exch = @b.exchange('direct_exchange') opts = {:key => 'a', :persistent => true} exch.publish('', opts) opts.should == {:key => 'a', :persistent => true} end it "should be able to return an undeliverable message" do exch = @b.exchange('return_exch') exch.publish('This message should be undeliverable', :immediate => true) ret_msg = @b.returned_message ret_msg.should be_an_instance_of(Hash) ret_msg[:payload].should == 'This message should be undeliverable' end it "should be able to return a message that exceeds maximum frame size" do exch = @b.exchange('return_exch') lg_msg = 'z' * 142000 exch.publish(lg_msg, :immediate => true) ret_msg = @b.returned_message ret_msg.should be_an_instance_of(Hash) ret_msg[:payload].should == lg_msg end it "should report an error if delete fails" do exch = @b.exchange('direct_exchange') lambda { exch.delete(:exchange => 'bogus_ex') }.should raise_error(Bunny::ForcedChannelCloseError) @b.channel.active.should == false end it "should be able to be deleted" do exch = @b.exchange('direct_exchange') res = exch.delete res.should == :delete_ok @b.exchanges.has_key?('direct_exchange').should be(false) end it "should ignore the :nowait option when deleted" do exch = @b.exchange('direct2_exchange') exch.delete(:nowait => true) end end bunny-0.7.8/spec/spec_09/0000755000076400007640000000000011704323672014116 5ustar pravipravibunny-0.7.8/spec/spec_09/bunny_spec.rb0000644000076400007640000000371011704323672016611 0ustar pravipravi# encoding: utf-8 # bunny_spec.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') require "bunny" describe Bunny do before(:each) do @b = Bunny.new(:spec => '09') @b.start end after(:each) do begin @b.stop rescue Exception ensure @b = nil end end it "should connect to an AMQP server" do @b.status.should == :connected end it "should be able to create and open a new channel" do c = @b.create_channel c.number.should == 2 c.should be_an_instance_of(Bunny::Channel09) @b.channels.size.should == 3 c.open.should == :open_ok @b.channel.number.should == 2 end it "should be able to switch between channels" do @b.channel.number.should == 1 @b.switch_channel(0) @b.channel.number.should == 0 end it "should raise an error if trying to switch to a non-existent channel" do lambda { @b.switch_channel(5) }.should raise_error(RuntimeError) end it "should be able to create an exchange" do exch = @b.exchange('test_exchange') exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'test_exchange' @b.exchanges.has_key?('test_exchange').should be(true) end it "should be able to create a queue" do q = @b.queue('test1') q.should be_an_instance_of(Bunny::Queue09) q.name.should == 'test1' @b.queues.has_key?('test1').should be(true) end # Current RabbitMQ has not implemented some functionality it "should raise an error if setting of QoS fails" do lambda { @b.qos(:global => true) }.should raise_error(Bunny::ForcedConnectionCloseError) @b.status.should == :not_connected end it "should be able to set QoS" do @b.qos.should == :qos_ok end end bunny-0.7.8/spec/spec_09/queue_spec.rb0000644000076400007640000001464611704323672016614 0ustar pravipravi# encoding: utf-8 # queue_spec.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') require "bunny" describe 'Queue' do before(:each) do @b = Bunny.new(:spec => '09') @b.start @default_exchange = @b.exchange("") end after(:each) do begin @b.stop rescue Exception ensure @b = nil end end def message_count(queue, sleep_time = 0.1) sleep sleep_time queue.message_count end it "should ignore the :nowait option when instantiated" do q = @b.queue('test0', :nowait => true) end it "should ignore the :nowait option when binding to an exchange" do exch = @b.exchange('direct_exch') q = @b.queue('test0') q.bind(exch, :nowait => true).should == :bind_ok end it "should raise an error when trying to bind to a non-existent exchange" do q = @b.queue('test1') lambda {q.bind('bogus')}.should raise_error(Bunny::ForcedChannelCloseError) @b.channel.active.should == false end it "should be able to bind to an existing exchange" do exch = @b.exchange('direct_exch') q = @b.queue('test1') q.bind(exch).should == :bind_ok end it "should ignore the :nowait option when unbinding from an existing exchange" do exch = @b.exchange('direct_exch') q = @b.queue('test0') q.unbind(exch, :nowait => true).should == :unbind_ok end it "should raise an error if unbinding from a non-existent exchange" do q = @b.queue('test1') lambda {q.unbind('bogus')}.should raise_error(Bunny::ForcedChannelCloseError) @b.channel.active.should == false end it "should be able to unbind from an exchange" do exch = @b.exchange('direct_exch') q = @b.queue('test1') q.unbind(exch).should == :unbind_ok end it "should be able to pop a message complete with header and delivery details" do q = @b.queue('test1') @default_exchange.publish('This is a test message', :key => 'test1') msg = q.pop() msg.should be_an_instance_of(Hash) msg[:header].should be_an_instance_of(Bunny::Protocol09::Header) msg[:payload].should == 'This is a test message' msg[:delivery_details].should be_an_instance_of(Hash) message_count(q).should == 0 end it "should be able to pop a message and just get the payload" do q = @b.queue('test1') @default_exchange.publish('This is another test message', :key => 'test1') msg = q.pop[:payload] msg.should == 'This is another test message' message_count(q).should == 0 end it "should be able to pop a message where body length exceeds max frame size" do q = @b.queue('test1') lg_msg = 'z' * 142000 @default_exchange.publish(lg_msg, :key => 'test1') msg = q.pop[:payload] msg.should == lg_msg end it "should be able call a block when popping a message" do q = @b.queue('test1') @default_exchange.publish('This is another test message', :key => 'test1') q.pop { |msg| msg[:payload].should == 'This is another test message' } q.pop { |msg| msg[:payload].should == :queue_empty } end it "should raise an error if purge fails" do q = @b.queue('test1') 5.times { @default_exchange.publish('This is another test message', :key => 'test1') } message_count(q).should == 5 lambda {q.purge(:queue => 'bogus')}.should raise_error(Bunny::ForcedChannelCloseError) end it "should be able to be purged to remove all of its messages" do q = @b.queue('test1') message_count(q).should == 5 q.purge.should == :purge_ok message_count(q).should == 0 end it "should return an empty message when popping an empty queue" do q = @b.queue('test1') @default_exchange.publish('This is another test message', :key => 'test1') q.pop msg = q.pop[:payload] msg.should == :queue_empty end it "should stop subscription without processing messages if max specified is 0" do q = @b.queue('test1') 5.times { @default_exchange.publish('Yet another test message', :key => 'test1') } message_count(q).should == 5 q.subscribe(:message_max => 0) message_count(q).should == 5 q.purge.should == :purge_ok end it "should stop subscription after processing number of messages specified > 0" do q = @b.queue('test1') 5.times { @default_exchange.publish('Yet another test message', :key => 'test1') } message_count(q).should == 5 q.subscribe(:message_max => 5) end it "should stop subscription after processing message_max messages < total in queue" do q = @b.queue('test1') @b.qos() 10.times { @default_exchange.publish('Yet another test message', :key => 'test1') } message_count(q).should == 10 q.subscribe(:message_max => 5, :ack => true) message_count(q).should == 5 q.purge.should == :purge_ok end it "should raise an error when delete fails" do q = @b.queue('test1') lambda {q.delete(:queue => 'bogus')}.should raise_error(Bunny::ForcedChannelCloseError) @b.channel.active.should == false end it "should pass correct block parameters through on subscribe" do q = @b.queue('test1') @default_exchange.publish("messages pop'n", :key => 'test1') q.subscribe do |msg| msg[:header].should be_an_instance_of Qrack::Protocol09::Header msg[:payload].should == "messages pop'n" msg[:delivery_details].should_not be_nil q.unsubscribe break end end it "should finish processing subscription messages if break is called in block" do q = @b.queue('test1') @default_exchange.publish('messages in my quezen', :key => 'test1') q.subscribe do |msg| msg[:payload].should == 'messages in my quezen' q.unsubscribe break end 5.times {|i| @default_exchange.publish("#{i}", :key => 'test1') } q.subscribe do |msg| if msg[:payload] == '4' q.unsubscribe break end end end it "should be able to be deleted" do q = @b.queue('test1') res = q.delete res.should == :delete_ok @b.queues.has_key?('test1').should be(false) end it "should ignore the :nowait option when deleted" do q = @b.queue('test0') q.delete(:nowait => true) end it "should support server named queues" do q = @b.queue q.name.should_not == nil @b.queue(q.name).should == q q.delete end end bunny-0.7.8/spec/spec_09/connection_spec.rb0000644000076400007640000000135111704323672017614 0ustar pravipravi# encoding: utf-8 # connection_spec.rb require "bunny" describe Bunny do it "should raise an error if the wrong user name or password is used" do b = Bunny.new(:spec => '0.9', :user => 'wrong') lambda { b.start}.should raise_error(Bunny::ProtocolError) end it "should merge custom settings from AMQP URL with default settings" do b = Bunny.new("amqp://tagadab", :spec => "0.9") b.host.should eql("tagadab") end it "should be able to open a TCPSocket with a timeout" do b = Bunny.new(:spec => "0.9") connect_timeout = 5 lambda { Bunny::Timer::timeout(connect_timeout, Qrack::ConnectionTimeout) do TCPSocket.new(b.host, b.port) end }.should_not raise_error(Exception) end end bunny-0.7.8/spec/spec_09/exchange_spec.rb0000644000076400007640000001363711704323672017251 0ustar pravipravi# encoding: utf-8 # exchange_spec.rb # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') require "bunny" describe 'Exchange' do before(:each) do @b = Bunny.new(:spec => '09') @b.start end after(:each) do begin @b.stop rescue Exception ensure @b = nil end end it "should raise an error if instantiated as non-existent type" do lambda { @b.exchange('bogus_ex', :type => :bogus) }.should raise_error(Bunny::ForcedConnectionCloseError) @b.status.should == :not_connected end it "should allow a default direct exchange to be instantiated by specifying :type" do exch = @b.exchange('amq.direct', :type => :direct) exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'amq.direct' exch.type.should == :direct @b.exchanges.has_key?('amq.direct').should be(true) end it "should allow a default direct exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.direct') exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'amq.direct' exch.type.should == :direct @b.exchanges.has_key?('amq.direct').should be(true) end it "should allow a default fanout exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.fanout') exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'amq.fanout' exch.type.should == :fanout @b.exchanges.has_key?('amq.fanout').should be(true) end it "should allow a default topic exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.topic') exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'amq.topic' exch.type.should == :topic @b.exchanges.has_key?('amq.topic').should be(true) end it "should allow a default headers (amq.match) exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.match') exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'amq.match' exch.type.should == :headers @b.exchanges.has_key?('amq.match').should be(true) end it "should allow a default headers (amq.headers) exchange to be instantiated without specifying :type" do exch = @b.exchange('amq.headers') exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'amq.headers' exch.type.should == :headers @b.exchanges.has_key?('amq.headers').should be(true) end it "should create an exchange as direct by default" do exch = @b.exchange('direct_defaultex') exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'direct_defaultex' exch.type.should == :direct @b.exchanges.has_key?('direct_defaultex').should be(true) end it "should be able to be instantiated as a direct exchange" do exch = @b.exchange('direct_exchange', :type => :direct) exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'direct_exchange' exch.type.should == :direct @b.exchanges.has_key?('direct_exchange').should be(true) end it "should be able to be instantiated as a topic exchange" do exch = @b.exchange('topic_exchange', :type => :topic) exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'topic_exchange' exch.type.should == :topic @b.exchanges.has_key?('topic_exchange').should be(true) end it "should be able to be instantiated as a fanout exchange" do exch = @b.exchange('fanout_exchange', :type => :fanout) exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'fanout_exchange' exch.type.should == :fanout @b.exchanges.has_key?('fanout_exchange').should be(true) end it "should be able to be instantiated as a headers exchange" do exch = @b.exchange('headers_exchange', :type => :headers) exch.should be_an_instance_of(Bunny::Exchange09) exch.name.should == 'headers_exchange' exch.type.should == :headers @b.exchanges.has_key?('headers_exchange').should be(true) end it "should ignore the :nowait option when instantiated" do exch = @b.exchange('direct2_exchange', :nowait => true) end it "should be able to publish a message" do exch = @b.exchange('direct_exchange') exch.publish('This is a published message') end it "should not modify the passed options hash when publishing a message" do exch = @b.exchange('direct_exchange') opts = {:key => 'a', :persistent => true} exch.publish('', opts) opts.should == {:key => 'a', :persistent => true} end it "should be able to return an undeliverable message" do exch = @b.exchange('return_exch') exch.publish('This message should be undeliverable', :immediate => true) ret_msg = @b.returned_message ret_msg.should be_an_instance_of(Hash) ret_msg[:payload].should == 'This message should be undeliverable' end it "should be able to return a message that exceeds maximum frame size" do exch = @b.exchange('return_exch') lg_msg = 'z' * 142000 exch.publish(lg_msg, :immediate => true) ret_msg = @b.returned_message ret_msg.should be_an_instance_of(Hash) ret_msg[:payload].should == lg_msg end it "should report an error if delete fails" do exch = @b.exchange('direct_exchange') lambda { exch.delete(:exchange => 'bogus_ex') }.should raise_error(Bunny::ForcedChannelCloseError) @b.channel.active.should == false end it "should be able to be deleted" do exch = @b.exchange('direct_exchange') res = exch.delete res.should == :delete_ok @b.exchanges.has_key?('direct_exchange').should be(false) end it "should ignore the :nowait option when deleted" do exch = @b.exchange('direct2_exchange') exch.delete(:nowait => true) end end bunny-0.7.8/spec/spec_09/amqp_url_spec.rb0000644000076400007640000000105611704323672017277 0ustar pravipravi# encoding: utf-8 # Assumes that target message broker/server has a user called 'guest' with a password 'guest' # and that it is running on 'localhost'. # If this is not the case, please change the 'Bunny.new' call below to include # the relevant arguments e.g. @b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar') require "bunny" describe Bunny do context "AMQP URL parsing" do it "handles port properly" do bunny = Bunny.new("amqp://dev.rabbitmq.com:1212") bunny.port.should eql(1212) bunny.stop end end end bunny-0.7.8/Gemfile0000644000076400007640000000146411704323672013222 0ustar pravipravi# 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 "SystemTimer", "1.2", :platform => :ruby_18 group :development do gem "rake" gem "yard", ">= 0.7.2" # Yard tags this buddy along. gem "RedCloth", :platform => :mri gem "changelog" end group :test do gem "rspec", "~> 2.6.0" end gemspec bunny-0.7.8/.yardopts0000644000076400007640000000021411704323672013565 0ustar pravipravi--no-private --protected --markup="textile" lib/**/*.rb --main README.textile --asset examples:examples --hide-tag todo - LICENSE CHANGELOG bunny-0.7.8/CHANGELOG0000644000076400007640000000107311704323672013135 0ustar pravipravi= Version 0.7.8 * test suite cleanup (eliminated some race conditions related to queue.message_count) = Version 0.7.7 * avoid warnings caused by duplicating code from the amq-client gem = Version 0.7.6 * API mismatch between Timer/SystemTimer on Ruby 1.9 vs Ruby 1.8 is resolved. = Version 0.7.3 * AMQP connection URI parser now respects port = Version 0.7.2 * Fixes for irb tab completion = Version 0.7.0 * Added :content_type option to Exchange#publish * Lots of minor fixes = Version 0.6.3 * Encoding of source files is set to UTF-8 on Ruby 1.9. bunny-0.7.8/.rspec0000644000076400007640000000003211704323672013032 0ustar pravipravi--color --format progress