amq-protocol-0.9.2/0000755000175000017500000000000011772516231013450 5ustar tfheentfheenamq-protocol-0.9.2/generate.rb0000755000175000017500000000054511772516231015576 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 def sh(*args) system(*args) end spec = "vendor/rabbitmq-codegen/amqp-rabbitmq-0.9.1.json" unless File.exist?(spec) sh "git submodule update --init" end path = "lib/amq/protocol/client.rb" sh "./codegen.py client #{spec} #{path}" if File.file?(path) sh "./post-processing.rb #{path}" sh "ruby -c #{path}" end amq-protocol-0.9.2/__init__.py0000644000175000017500000000000011772516231015547 0ustar tfheentfheenamq-protocol-0.9.2/post-processing.rb0000755000175000017500000000073111772516231017140 0ustar tfheentfheen#!/usr/bin/env ruby # encoding: utf-8 # helpers def pass; end # main buffer = ARGF.inject(String.new) do |buffer, line| # line filters line.gsub!(/\s*\n$/, "\n") line.gsub!("'", '"') line.gsub!('u"', '"') if line =~ /^\s*# \[/ buffer += line end # buffer filters buffer.gsub!(/\n{2,}/m, "\n\n") pass while buffer.gsub!(/(\n( *) end)\n{2,}(\2end)/m, "\\1\n\\3") # Make sure there's only one \n at the end pass while buffer.chomp! buffer += "\n" puts buffer amq-protocol-0.9.2/spec/0000755000175000017500000000000011772516231014402 5ustar tfheentfheenamq-protocol-0.9.2/spec/amq/0000755000175000017500000000000011772516231015160 5ustar tfheentfheenamq-protocol-0.9.2/spec/amq/hacks_spec.rb0000644000175000017500000000342311772516231017612 0ustar tfheentfheen# encoding: binary require File.expand_path('../../spec_helper', __FILE__) module AMQ describe Hacks do context "64-bit big-endian packing / unpacking" do let(:examples) { { 0x0000000000000000 => "\x00\x00\x00\x00\x00\x00\x00\x00", 0x000000000000000A => "\x00\x00\x00\x00\x00\x00\x00\x0A", 0x00000000000000A0 => "\x00\x00\x00\x00\x00\x00\x00\xA0", 0x000000000000B0A0 => "\x00\x00\x00\x00\x00\x00\xB0\xA0", 0x00000000000CB0AD => "\x00\x00\x00\x00\x00\x0C\xB0\xAD", 0x8BADF00DDEFEC8ED => "\x8B\xAD\xF0\x0D\xDE\xFE\xC8\xED", 0x0D15EA5EFEE1DEAD => "\x0D\x15\xEA\x5E\xFE\xE1\xDE\xAD", 0xDEADBEEFDEADBABE => "\xDE\xAD\xBE\xEF\xDE\xAD\xBA\xBE" } } it "packs integers into big-endian string" do examples.each do |key, value| described_class.pack_64_big_endian(key).should == value end end it "should unpack string representation into integer" do examples.each do |key, value| described_class.unpack_64_big_endian(value)[0].should == key end end if RUBY_VERSION < '1.9' describe "with utf encoding" do before do $KCODE = 'u' end after do $KCODE = 'NONE' end it "packs integers into big-endian string" do examples.each do |key, value| described_class.pack_64_big_endian(key).should == value end end it "should unpack string representation into integer" do examples.each do |key, value| described_class.unpack_64_big_endian(value)[0].should == key end end end end end end endamq-protocol-0.9.2/spec/amq/protocol_spec.rb0000644000175000017500000006205611772516231020371 0ustar tfheentfheen# encoding: binary require File.expand_path('../../spec_helper', __FILE__) module AMQ describe Protocol do it "should have PROTOCOL_VERSION constant" do Protocol::PROTOCOL_VERSION.should match(/^\d+\.\d+\.\d$/) end it "should have DEFAULT_PORT constant" do Protocol::DEFAULT_PORT.should be_kind_of(Integer) end it "should have PREAMBLE constant" do Protocol::PREAMBLE.should be_kind_of(String) end describe Protocol::Error do it "should be an exception class" do Protocol::Error.should < Exception end end describe Protocol::Connection do it "should be a subclass of Class" do Protocol::Connection.superclass.should == Protocol::Class end it "should have name equal to connection" do Protocol::Connection.name.should eql("connection") end it "should have method id equal to 10" do Protocol::Connection.method_id.should == 10 end describe Protocol::Connection::Start do it "should be a subclass of Method" do Protocol::Connection::Start.superclass.should == Protocol::Method end it "should have method name equal to connection.start" do Protocol::Connection::Start.name.should eql("connection.start") end it "should have method id equal to 10" do Protocol::Connection::Start.method_id.should == 10 end end describe Protocol::Connection::StartOk do it "should be a subclass of Method" do Protocol::Connection::StartOk.superclass.should == Protocol::Method end it "should have method name equal to connection.start-ok" do Protocol::Connection::StartOk.name.should eql("connection.start-ok") end it "has method id equal to 11" do Protocol::Connection::StartOk.method_id.should == 11 end end describe Protocol::Connection::Secure do it "should be a subclass of Method" do Protocol::Connection::Secure.superclass.should == Protocol::Method end it "should have method name equal to connection.secure" do Protocol::Connection::Secure.name.should eql("connection.secure") end it "has method id equal to 20" do Protocol::Connection::Secure.method_id.should == 20 end end describe Protocol::Connection::SecureOk do it "should be a subclass of Method" do Protocol::Connection::SecureOk.superclass.should == Protocol::Method end it "should have method name equal to connection.secure-ok" do Protocol::Connection::SecureOk.name.should eql("connection.secure-ok") end it "has method id equal to 21" do Protocol::Connection::SecureOk.method_id.should == 21 end end describe Protocol::Connection::Tune do it "should be a subclass of Method" do Protocol::Connection::Tune.superclass.should == Protocol::Method end it "should have method name equal to connection.tune" do Protocol::Connection::Tune.name.should eql("connection.tune") end it "has method id equal to 30" do Protocol::Connection::Tune.method_id.should == 30 end end describe Protocol::Connection::TuneOk do it "should be a subclass of Method" do Protocol::Connection::TuneOk.superclass.should == Protocol::Method end it "should have method name equal to connection.tune-ok" do Protocol::Connection::TuneOk.name.should eql("connection.tune-ok") end it "has method id equal to 31" do Protocol::Connection::TuneOk.method_id.should == 31 end describe ".encode" do it do frame = Protocol::Connection::TuneOk.encode(0, 131072, 0) frame.payload.should eql("\x00\n\x00\x1F\x00\x00\x00\x02\x00\x00\x00\x00") end end end describe Protocol::Connection::Open do it "should be a subclass of Method" do Protocol::Connection::Open.superclass.should == Protocol::Method end it "should have method name equal to connection.open" do Protocol::Connection::Open.name.should eql("connection.open") end it "has method id equal to 40" do Protocol::Connection::Open.method_id.should == 40 end end describe Protocol::Connection::OpenOk do it "should be a subclass of Method" do Protocol::Connection::OpenOk.superclass.should == Protocol::Method end it "should have method name equal to connection.open-ok" do Protocol::Connection::OpenOk.name.should eql("connection.open-ok") end it "has method id equal to 41" do Protocol::Connection::OpenOk.method_id.should == 41 end end describe Protocol::Connection::Close do it "should be a subclass of Method" do Protocol::Connection::Close.superclass.should == Protocol::Method end it "should have method name equal to connection.close" do Protocol::Connection::Close.name.should eql("connection.close") end it "has method id equal to 50" do Protocol::Connection::Close.method_id.should == 50 end end describe Protocol::Connection::CloseOk do it "should be a subclass of Method" do Protocol::Connection::CloseOk.superclass.should == Protocol::Method end it "should have method name equal to connection.close-ok" do Protocol::Connection::CloseOk.name.should eql("connection.close-ok") end it "has method id equal to 51" do Protocol::Connection::CloseOk.method_id.should == 51 end end end describe Protocol::Channel do it "should be a subclass of Class" do Protocol::Channel.superclass.should == Protocol::Class end it "should have name equal to channel" do Protocol::Channel.name.should eql("channel") end it "has method id equal to 20" do Protocol::Channel.method_id.should == 20 end describe Protocol::Channel::Open do it "should be a subclass of Method" do Protocol::Channel::Open.superclass.should == Protocol::Method end it "should have method name equal to channel.open" do Protocol::Channel::Open.name.should eql("channel.open") end it "has method id equal to 10" do Protocol::Channel::Open.method_id.should == 10 end end describe Protocol::Channel::OpenOk do it "should be a subclass of Method" do Protocol::Channel::OpenOk.superclass.should == Protocol::Method end it "should have method name equal to channel.open-ok" do Protocol::Channel::OpenOk.name.should eql("channel.open-ok") end it "has method id equal to 11" do Protocol::Channel::OpenOk.method_id.should == 11 end end describe Protocol::Channel::Flow do it "should be a subclass of Method" do Protocol::Channel::Flow.superclass.should == Protocol::Method end it "should have method name equal to channel.flow" do Protocol::Channel::Flow.name.should eql("channel.flow") end it "has method id equal to 20" do Protocol::Channel::Flow.method_id.should == 20 end end describe Protocol::Channel::FlowOk do it "should be a subclass of Method" do Protocol::Channel::FlowOk.superclass.should == Protocol::Method end it "should have method name equal to channel.flow-ok" do Protocol::Channel::FlowOk.name.should eql("channel.flow-ok") end it "has method id equal to 21" do Protocol::Channel::FlowOk.method_id.should == 21 end end describe Protocol::Channel::Close do it "should be a subclass of Method" do Protocol::Channel::Close.superclass.should == Protocol::Method end it "should have method name equal to channel.close" do Protocol::Channel::Close.name.should eql("channel.close") end it "has method id equal to 40" do Protocol::Channel::Close.method_id.should == 40 end end describe Protocol::Channel::CloseOk do it "should be a subclass of Method" do Protocol::Channel::CloseOk.superclass.should == Protocol::Method end it "should have method name equal to channel.close-ok" do Protocol::Channel::CloseOk.name.should eql("channel.close-ok") end it "has method id equal to 41" do Protocol::Channel::CloseOk.method_id.should == 41 end end end describe Protocol::Exchange do it "should be a subclass of Class" do Protocol::Exchange.superclass.should == Protocol::Class end it "should have name equal to exchange" do Protocol::Exchange.name.should eql("exchange") end it "has method id equal to 40" do Protocol::Exchange.method_id.should == 40 end describe Protocol::Exchange::Declare do it "should be a subclass of Method" do Protocol::Exchange::Declare.superclass.should == Protocol::Method end it "should have method name equal to exchange.declare" do Protocol::Exchange::Declare.name.should eql("exchange.declare") end it "has method id equal to 10" do Protocol::Exchange::Declare.method_id.should == 10 end end describe Protocol::Exchange::DeclareOk do it "should be a subclass of Method" do Protocol::Exchange::DeclareOk.superclass.should == Protocol::Method end it "should have method name equal to exchange.declare-ok" do Protocol::Exchange::DeclareOk.name.should eql("exchange.declare-ok") end it "has method id equal to 11" do Protocol::Exchange::DeclareOk.method_id.should == 11 end end describe Protocol::Exchange::Delete do it "should be a subclass of Method" do Protocol::Exchange::Delete.superclass.should == Protocol::Method end it "should have method name equal to exchange.delete" do Protocol::Exchange::Delete.name.should eql("exchange.delete") end it "has method id equal to 20" do Protocol::Exchange::Delete.method_id.should == 20 end end describe Protocol::Exchange::DeleteOk do it "should be a subclass of Method" do Protocol::Exchange::DeleteOk.superclass.should == Protocol::Method end it "should have method name equal to exchange.delete-ok" do Protocol::Exchange::DeleteOk.name.should eql("exchange.delete-ok") end it "has method id equal to 21" do Protocol::Exchange::DeleteOk.method_id.should == 21 end end describe Protocol::Exchange::Bind do it "should be a subclass of Method" do Protocol::Exchange::Bind.superclass.should == Protocol::Method end it "should have method name equal to exchange.bind" do Protocol::Exchange::Bind.name.should eql("exchange.bind") end it "has method id equal to 30" do Protocol::Exchange::Bind.method_id.should == 30 end end describe Protocol::Exchange::BindOk do it "should be a subclass of Method" do Protocol::Exchange::BindOk.superclass.should == Protocol::Method end it "should have method name equal to exchange.bind-ok" do Protocol::Exchange::BindOk.name.should eql("exchange.bind-ok") end it "has method id equal to 31" do Protocol::Exchange::BindOk.method_id.should == 31 end end describe Protocol::Exchange::Unbind do it "should be a subclass of Method" do Protocol::Exchange::Unbind.superclass.should == Protocol::Method end it "should have method name equal to exchange.unbind" do Protocol::Exchange::Unbind.name.should eql("exchange.unbind") end it "has method id equal to 40" do Protocol::Exchange::Unbind.method_id.should == 40 end end describe Protocol::Exchange::UnbindOk do it "should be a subclass of Method" do Protocol::Exchange::UnbindOk.superclass.should == Protocol::Method end it "should have method name equal to exchange.unbind-ok" do Protocol::Exchange::UnbindOk.name.should eql("exchange.unbind-ok") end it "has method id equal to 51" do Protocol::Exchange::UnbindOk.method_id.should == 51 end end end describe Protocol::Queue do it "should be a subclass of Class" do Protocol::Queue.superclass.should == Protocol::Class end it "should have name equal to queue" do Protocol::Queue.name.should eql("queue") end it "has method id equal to 50" do Protocol::Queue.method_id.should == 50 end describe Protocol::Queue::Declare do it "should be a subclass of Method" do Protocol::Queue::Declare.superclass.should == Protocol::Method end it "should have method name equal to queue.declare" do Protocol::Queue::Declare.name.should eql("queue.declare") end it "has method id equal to 10" do Protocol::Queue::Declare.method_id.should == 10 end end describe Protocol::Queue::DeclareOk do it "should be a subclass of Method" do Protocol::Queue::DeclareOk.superclass.should == Protocol::Method end it "should have method name equal to queue.declare-ok" do Protocol::Queue::DeclareOk.name.should eql("queue.declare-ok") end it "has method id equal to 11" do Protocol::Queue::DeclareOk.method_id.should == 11 end end describe Protocol::Queue::Bind do it "should be a subclass of Method" do Protocol::Queue::Bind.superclass.should == Protocol::Method end it "should have method name equal to queue.bind" do Protocol::Queue::Bind.name.should eql("queue.bind") end it "has method id equal to 20" do Protocol::Queue::Bind.method_id.should == 20 end end describe Protocol::Queue::BindOk do it "should be a subclass of Method" do Protocol::Queue::BindOk.superclass.should == Protocol::Method end it "should have method name equal to queue.bind-ok" do Protocol::Queue::BindOk.name.should eql("queue.bind-ok") end it "has method id equal to 21" do Protocol::Queue::BindOk.method_id.should == 21 end end describe Protocol::Queue::Purge do it "should be a subclass of Method" do Protocol::Queue::Purge.superclass.should == Protocol::Method end it "should have method name equal to queue.purge" do Protocol::Queue::Purge.name.should eql("queue.purge") end it "has method id equal to 30" do Protocol::Queue::Purge.method_id.should == 30 end end describe Protocol::Queue::PurgeOk do it "should be a subclass of Method" do Protocol::Queue::PurgeOk.superclass.should == Protocol::Method end it "should have method name equal to queue.purge-ok" do Protocol::Queue::PurgeOk.name.should eql("queue.purge-ok") end it "has method id equal to 31" do Protocol::Queue::PurgeOk.method_id.should == 31 end end describe Protocol::Queue::Delete do it "should be a subclass of Method" do Protocol::Queue::Delete.superclass.should == Protocol::Method end it "should have method name equal to queue.delete" do Protocol::Queue::Delete.name.should eql("queue.delete") end it "has method id equal to 40" do Protocol::Queue::Delete.method_id.should == 40 end end describe Protocol::Queue::DeleteOk do it "should be a subclass of Method" do Protocol::Queue::DeleteOk.superclass.should == Protocol::Method end it "should have method name equal to queue.delete-ok" do Protocol::Queue::DeleteOk.name.should eql("queue.delete-ok") end it "has method id equal to 41" do Protocol::Queue::DeleteOk.method_id.should == 41 end end describe Protocol::Queue::Unbind do it "should be a subclass of Method" do Protocol::Queue::Unbind.superclass.should == Protocol::Method end it "should have method name equal to queue.unbind" do Protocol::Queue::Unbind.name.should eql("queue.unbind") end it "has method id equal to 50" do Protocol::Queue::Unbind.method_id.should == 50 end end describe Protocol::Queue::UnbindOk do it "should be a subclass of Method" do Protocol::Queue::UnbindOk.superclass.should == Protocol::Method end it "should have method name equal to queue.unbind-ok" do Protocol::Queue::UnbindOk.name.should eql("queue.unbind-ok") end it "has method id equal to 51" do Protocol::Queue::UnbindOk.method_id.should == 51 end end end describe Protocol::Basic do it "should be a subclass of Class" do Protocol::Basic.superclass.should == Protocol::Class end it "should have name equal to basic" do Protocol::Basic.name.should eql("basic") end it "has method id equal to 60" do Protocol::Basic.method_id.should == 60 end describe Protocol::Basic::Qos do it "should be a subclass of Method" do Protocol::Basic::Qos.superclass.should == Protocol::Method end it "should have method name equal to basic.qos" do Protocol::Basic::Qos.name.should eql("basic.qos") end it "has method id equal to 10" do Protocol::Basic::Qos.method_id.should == 10 end end describe Protocol::Basic::QosOk do it "should be a subclass of Method" do Protocol::Basic::QosOk.superclass.should == Protocol::Method end it "should have method name equal to basic.qos-ok" do Protocol::Basic::QosOk.name.should eql("basic.qos-ok") end it "has method id equal to 11" do Protocol::Basic::QosOk.method_id.should == 11 end end describe Protocol::Basic::Consume do it "should be a subclass of Method" do Protocol::Basic::Consume.superclass.should == Protocol::Method end it "should have method name equal to basic.consume" do Protocol::Basic::Consume.name.should eql("basic.consume") end it "has method id equal to 20" do Protocol::Basic::Consume.method_id.should == 20 end end describe Protocol::Basic::ConsumeOk do it "should be a subclass of Method" do Protocol::Basic::ConsumeOk.superclass.should == Protocol::Method end it "should have method name equal to basic.consume-ok" do Protocol::Basic::ConsumeOk.name.should eql("basic.consume-ok") end it "has method id equal to 21" do Protocol::Basic::ConsumeOk.method_id.should == 21 end end describe Protocol::Basic::Cancel do it "should be a subclass of Method" do Protocol::Basic::Cancel.superclass.should == Protocol::Method end it "should have method name equal to basic.cancel" do Protocol::Basic::Cancel.name.should eql("basic.cancel") end it "has method id equal to 30" do Protocol::Basic::Cancel.method_id.should == 30 end end describe Protocol::Basic::CancelOk do it "should be a subclass of Method" do Protocol::Basic::CancelOk.superclass.should == Protocol::Method end it "should have method name equal to basic.cancel-ok" do Protocol::Basic::CancelOk.name.should eql("basic.cancel-ok") end it "has method id equal to 31" do Protocol::Basic::CancelOk.method_id.should == 31 end end describe Protocol::Basic::Publish do it "should be a subclass of Method" do Protocol::Basic::Publish.superclass.should == Protocol::Method end it "should have method name equal to basic.publish" do Protocol::Basic::Publish.name.should eql("basic.publish") end it "has method id equal to 40" do Protocol::Basic::Publish.method_id.should == 40 end end describe Protocol::Basic::Return do it "should be a subclass of Method" do Protocol::Basic::Return.superclass.should == Protocol::Method end it "should have method name equal to basic.return" do Protocol::Basic::Return.name.should eql("basic.return") end it "has method id equal to 50" do Protocol::Basic::Return.method_id.should == 50 end end describe Protocol::Basic::Deliver do it "should be a subclass of Method" do Protocol::Basic::Deliver.superclass.should == Protocol::Method end it "should have method name equal to basic.deliver" do Protocol::Basic::Deliver.name.should eql("basic.deliver") end it "has method id equal to 60" do Protocol::Basic::Deliver.method_id.should == 60 end end describe Protocol::Basic::Get do it "should be a subclass of Method" do Protocol::Basic::Get.superclass.should == Protocol::Method end it "should have method name equal to basic.get" do Protocol::Basic::Get.name.should eql("basic.get") end it "has method id equal to 70" do Protocol::Basic::Get.method_id.should == 70 end end describe Protocol::Basic::GetOk do it "should be a subclass of Method" do Protocol::Basic::GetOk.superclass.should == Protocol::Method end it "should have method name equal to basic.get-ok" do Protocol::Basic::GetOk.name.should eql("basic.get-ok") end it "has method id equal to 71" do Protocol::Basic::GetOk.method_id.should == 71 end end describe Protocol::Basic::GetEmpty do it "should be a subclass of Method" do Protocol::Basic::GetEmpty.superclass.should == Protocol::Method end it "should have method name equal to basic.get-empty" do Protocol::Basic::GetEmpty.name.should eql("basic.get-empty") end it "has method id equal to 72" do Protocol::Basic::GetEmpty.method_id.should == 72 end end describe Protocol::Basic::Ack do it "should be a subclass of Method" do Protocol::Basic::Ack.superclass.should == Protocol::Method end it "should have method name equal to basic.ack" do Protocol::Basic::Ack.name.should eql("basic.ack") end it "has method id equal to 80" do Protocol::Basic::Ack.method_id.should == 80 end end describe Protocol::Basic::Reject do it "should be a subclass of Method" do Protocol::Basic::Reject.superclass.should == Protocol::Method end it "should have method name equal to basic.reject" do Protocol::Basic::Reject.name.should eql("basic.reject") end it "has method id equal to 90" do Protocol::Basic::Reject.method_id.should == 90 end end describe Protocol::Basic::RecoverAsync do it "should be a subclass of Method" do Protocol::Basic::RecoverAsync.superclass.should == Protocol::Method end it "should have method name equal to basic.recover-async" do Protocol::Basic::RecoverAsync.name.should eql("basic.recover-async") end it "has method id equal to 100" do Protocol::Basic::RecoverAsync.method_id.should == 100 end end describe Protocol::Basic::Recover do it "should be a subclass of Method" do Protocol::Basic::Recover.superclass.should == Protocol::Method end it "should have method name equal to basic.recover" do Protocol::Basic::Recover.name.should eql("basic.recover") end it "has method id equal to 110" do Protocol::Basic::Recover.method_id.should == 110 end end describe Protocol::Basic::RecoverOk do it "should be a subclass of Method" do Protocol::Basic::RecoverOk.superclass.should == Protocol::Method end it "should have method name equal to basic.recover-ok" do Protocol::Basic::RecoverOk.name.should eql("basic.recover-ok") end it "has method id equal to 111" do Protocol::Basic::RecoverOk.method_id.should == 111 end end end end endamq-protocol-0.9.2/spec/amq/protocol/0000755000175000017500000000000011772516231017021 5ustar tfheentfheenamq-protocol-0.9.2/spec/amq/protocol/queue_spec.rb0000644000175000017500000000742211772516231021511 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol class Queue describe Declare do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 queue = 'hello.world' passive = false durable = true exclusive = true auto_delete = true nowait = false arguments = nil method_frame = Declare.encode(channel, queue, passive, durable, exclusive, auto_delete, nowait, arguments) method_frame.payload.should == "\x002\x00\n\x00\x00\vhello.world\x0E\x00\x00\x00\x00" method_frame.channel.should == 1 end end end describe DeclareOk do describe '.decode' do subject do DeclareOk.decode(" amq.gen-KduGSqQrpeUo1otnU0TWSA==\x00\x00\x00\x00\x00\x00\x00\x00") end its(:queue) { should == 'amq.gen-KduGSqQrpeUo1otnU0TWSA==' } its(:message_count) { should == 0 } its(:consumer_count) { should == 0 } end end describe Bind do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 queue = 'hello.world' exchange = 'foo.bar' routing_key = 'xyz' nowait = false arguments = nil method_frame = Bind.encode(channel, queue, exchange, routing_key, nowait, arguments) method_frame.payload.should == "\x002\x00\x14\x00\x00\vhello.world\afoo.bar\x03xyz\x00\x00\x00\x00\x00" method_frame.channel.should == 1 end end end # describe BindOk do # describe '.decode' do # end # end describe Purge do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 queue = 'hello.world' nowait = false method_frame = Purge.encode(channel, queue, nowait) method_frame.payload.should == "\x002\x00\x1E\x00\x00\vhello.world\x00" method_frame.channel.should == 1 end end end describe PurgeOk do describe '.decode' do subject do PurgeOk.decode("\x00\x00\x00\x02") end its(:message_count) { should == 2 } end end describe Delete do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 queue = 'hello.world' if_unused = false if_empty = false nowait = false method_frame = Delete.encode(channel, queue, if_unused, if_empty, nowait) method_frame.payload.should == "\x002\x00(\x00\x00\vhello.world\x00" method_frame.channel.should == 1 end end end describe DeleteOk do describe '.decode' do subject do DeleteOk.decode("\x00\x00\x00\x02") end its(:message_count) { should == 2 } end end describe Unbind do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 queue = 'hello.world' exchange = 'foo.bar' routing_key = 'xyz' arguments = nil method_frame = Unbind.encode(channel, queue, exchange, routing_key, arguments) method_frame.payload.should == "\x002\x002\x00\x00\vhello.world\afoo.bar\x03xyz\x00\x00\x00\x00" method_frame.channel.should == 1 end end end # describe UnbindOk do # describe '.decode' do # end # end end end end amq-protocol-0.9.2/spec/amq/protocol/table_spec.rb0000644000175000017500000002002511772516231021446 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) require 'bigdecimal' require 'time' module AMQ module Protocol describe Table do timestamp = Time.utc(2010, 12, 31, 23, 58, 59) bigdecimal_1 = BigDecimal.new("1.0") bigdecimal_2 = BigDecimal.new("5E-3") bigdecimal_3 = BigDecimal.new("-0.01") DATA = if one_point_eight? { {} => "\000\000\000\000", {"test" => 1} => "\000\000\000\n\004testI\000\000\000\001", {"float" => 1.87} => "\000\000\000\017\005floatd\354Q\270\036\205\353\375?", {"test" => "string"} => "\000\000\000\020\004testS\000\000\000\006string", {"test" => {}} => "\000\000\000\n\004testF\000\000\000\000", {"test" => bigdecimal_1} => "\000\000\000\v\004testD\000\000\000\000\001", {"test" => bigdecimal_2} => "\000\000\000\v\004testD\003\000\000\000\005", {"test" => timestamp} => "\000\000\000\016\004testT\000\000\000\000M\036nC" } else { {} => "\x00\x00\x00\x00", {"test" => 1} => "\x00\x00\x00\n\x04testI\x00\x00\x00\x01", {"float" => 1.92} => "\x00\x00\x00\x0F\x05floatd\xB8\x1E\x85\xEBQ\xB8\xFE?", {"test" => "string"} => "\x00\x00\x00\x10\x04testS\x00\x00\x00\x06string", {"test" => {}} => "\x00\x00\x00\n\x04testF\x00\x00\x00\x00", {"test" => bigdecimal_1} => "\x00\x00\x00\v\x04testD\x00\x00\x00\x00\x01", {"test" => bigdecimal_2} => "\x00\x00\x00\v\x04testD\x03\x00\x00\x00\x05", {"test" => timestamp} => "\x00\x00\x00\x0e\x04testT\x00\x00\x00\x00M\x1enC" } end describe ".encode" do it "should return \"\x00\x00\x00\x00\" for nil" do encoded_value = if one_point_eight? "\000\000\000\000" else "\x00\x00\x00\x00" end Table.encode(nil).should eql(encoded_value) end it "should return \x00\x00\x00\a\x04testt\x01 for { :test => true }" do Table.encode(:test => true).should eql("\x00\x00\x00\a\x04testt\x01") end it "should return \x00\x00\x00\a\x04testt\x00 for { :test => false }" do Table.encode(:test => false).should eql("\x00\x00\x00\a\x04testt\x00") end it "should return \"\x00\x00\x00\n\x04testI\x00\x00\x00\x01\" for { :coordinates => { :latitude => 59.35 } }" do Table.encode(:coordinates => { :latitude => 59.35 }).should eql("\000\000\000#\vcoordinatesF\000\000\000\022\blatituded\315\314\314\314\314\254M@") end it "should return \"\x00\x00\x00\n\x04testI\x00\x00\x00\x01\" for { :coordinates => { :longitude => 18.066667 } }" do Table.encode(:coordinates => { :longitude => 18.066667 }).should eql("\000\000\000$\vcoordinatesF\000\000\000\023\tlongituded\361\270\250\026\021\0212@") end DATA.each do |data, encoded| it "should return #{encoded.inspect} for #{data.inspect}" do Table.encode(data).should eql(encoded) end end end describe ".decode" do DATA.each do |data, encoded| it "should return #{data.inspect} for #{encoded.inspect}" do Table.decode(encoded).should eql(data) end it "is capable of decoding what it encodes" do Table.decode(Table.encode(data)).should == data end end # DATA.each it "is capable of decoding boolean table values" do input1 = { "boolval" => true } Table.decode(Table.encode(input1)).should == input1 input2 = { "boolval" => false } Table.decode(Table.encode(input2)).should == input2 end it "is capable of decoding string table values" do input = { "stringvalue" => "string" } Table.decode(Table.encode(input)).should == input end it "is capable of decoding integer table values" do input = { "intvalue" => 10 } Table.decode(Table.encode(input)).should == input end it "is capable of decoding long table values" do input = { "longvalue" => 912598613 } Table.decode(Table.encode(input)).should == input end it "is capable of decoding float table values" do input = { "floatvalue" => 100.0 } Table.decode(Table.encode(input)).should == input end it "is capable of decoding time table values" do input = { "intvalue" => Time.parse("2011-07-14 01:17:46 +0400") } Table.decode(Table.encode(input)).should == input end it "is capable of decoding empty hash table values" do input = { "hashvalue" => Hash.new } Table.decode(Table.encode(input)).should == input end it "is capable of decoding empty array table values" do input = { "arrayvalue" => Array.new } Table.decode(Table.encode(input)).should == input end it "is capable of decoding single string value array table values" do input = { "arrayvalue" => ["amq-protocol"] } Table.decode(Table.encode(input)).should == input end it "is capable of decoding simple nested hash table values" do input = { "hashvalue" => { "a" => "b" } } Table.decode(Table.encode(input)).should == input end it "is capable of decoding nil table values" do input = { "nil" => nil } Table.decode(Table.encode(input)).should == input end it "is capable of decoding tables" do input = { "boolval" => true, "intval" => 1, "strval" => "Test", "timestampval" => Time.parse("2011-07-14 01:17:46 +0400"), "floatval" => 3.14, "longval" => 912598613, "hashval" => { "protocol" => "AMQP091", "true" => true, "false" => false, "nil" => nil } } Table.decode(Table.encode(input)).should == input end it "is capable of decoding deeply nested tables" do input = { "hashval" => { "protocol" => { "name" => "AMQP", "major" => 0, "minor" => "9", "rev" => 1.0, "spec" => { "url" => "http://bit.ly/hw2ELX", "utf8" => "à bientôt" } }, "true" => true, "false" => false, "nil" => nil } } Table.decode(Table.encode(input)).should == input end it "is capable of decoding array values in tables" do input1 = { "arrayval1" => [198, 3, 77, 8.0, ["inner", "array", { "oh" => "well", "it" => "should work", "3" => 6 }], "two", { "a" => "value", "is" => nil }], "arrayval2" => [198, 3, 77, "two", { "a" => "value", "is" => nil }, 8.0, ["inner", "array", { "oh" => "well", "it" => "should work", "3" => 6 }]] } Table.decode(Table.encode(input1)).should == input1 now = Time.now input2 = { "coordinates" => { "latitude" => 59.35, "longitude" => 18.066667 }, "participants" => 11, "venue" => "Stockholm", "true_field" => true, "false_field" => false, "nil_field" => nil, "ary_field" => ["one", 2.0, 3] } Table.decode(Table.encode(input2)).should == input2 input3 = { "timely" => { "now" => now } } Table.decode(Table.encode(input3))["timely"]["now"].to_i.should == now.to_i end end # describe end end end amq-protocol-0.9.2/spec/amq/protocol/tx_spec.rb0000644000175000017500000000257411772516231021023 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol class Tx describe Select do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 method_frame = Select.encode(channel) method_frame.payload.should == "\000Z\000\n" method_frame.channel.should == 1 end end end # describe SelectOk do # describe '.decode' do # end # end describe Commit do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 method_frame = Commit.encode(channel) method_frame.payload.should == "\000Z\000\024" method_frame.channel.should == 1 end end end # describe CommitOk do # describe '.decode' do # end # end describe Rollback do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 method_frame = Rollback.encode(channel) method_frame.payload.should == "\000Z\000\036" method_frame.channel.should == 1 end end end # describe RollbackOk do # describe '.decode' do # end # end end end end amq-protocol-0.9.2/spec/amq/protocol/confirm_spec.rb0000644000175000017500000000206511772516231022020 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol class Confirm describe Select do describe '.decode' do subject do Select.decode("\x01") end its(:nowait) { should be_true } end describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 nowait = true method_frame = Select.encode(channel, nowait) method_frame.payload.should == "\x00U\x00\n\x01" method_frame.channel.should == 1 end end end describe SelectOk do # describe '.decode' do # end describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 method_frame = SelectOk.encode(channel) method_frame.payload.should == "\000U\000\v" method_frame.channel.should == 1 end end end end end end amq-protocol-0.9.2/spec/amq/protocol/exchange_spec.rb0000644000175000017500000000552411772516231022150 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol class Exchange describe Declare do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 exchange = 'amqclient.adapters.em.exchange1' type = 'fanout' passive = false durable = false auto_delete = false internal = false nowait = false arguments = nil method_frame = Declare.encode(channel, exchange, type, passive, durable, auto_delete, internal, nowait, arguments) method_frame.payload.should == "\x00(\x00\n\x00\x00\x1Famqclient.adapters.em.exchange1\x06fanout\x00\x00\x00\x00\x00" method_frame.channel.should == 1 end end end # describe DeclareOk do # describe '.decode' do # end # end describe Delete do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 exchange = 'amqclient.adapters.em.exchange' if_unused = false nowait = false method_frame = Delete.encode(channel, exchange, if_unused, nowait) method_frame.payload.should == "\x00(\x00\x14\x00\x00\x1Eamqclient.adapters.em.exchange\x00" method_frame.channel.should == 1 end end end # describe DeleteOk do # describe '.decode' do # end # end describe Bind do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 destination = 'foo' source = 'bar' routing_key = 'xyz' nowait = false arguments = nil method_frame = Bind.encode(channel, destination, source, routing_key, nowait, arguments) method_frame.payload.should == "\x00(\x00\x1E\x00\x00\x03foo\x03bar\x03xyz\x00\x00\x00\x00\x00" method_frame.channel.should == 1 end end end # describe BindOk do # describe '.decode' do # end # end describe Unbind do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 destination = 'foo' source = 'bar' routing_key = 'xyz' nowait = false arguments = nil method_frame = Unbind.encode(channel, destination, source, routing_key, nowait, arguments) method_frame.payload.should == "\x00(\x00(\x00\x00\x03foo\x03bar\x03xyz\x00\x00\x00\x00\x00" method_frame.channel.should == 1 end end end # describe UnbindOk do # describe '.decode' do # end # end end end end amq-protocol-0.9.2/spec/amq/protocol/connection_spec.rb0000644000175000017500000001255311772516231022525 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol class Connection describe Start do describe '.decode' do subject do Start.decode("\x00\t\x00\x00\x00\xFB\tcopyrightS\x00\x00\x00gCopyright (C) 2007-2010 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.\vinformationS\x00\x00\x005Licensed under the MPL. See http://www.rabbitmq.com/\bplatformS\x00\x00\x00\nErlang/OTP\aproductS\x00\x00\x00\bRabbitMQ\aversionS\x00\x00\x00\x052.2.0\x00\x00\x00\x0EPLAIN AMQPLAIN\x00\x00\x00\x05en_US") end its(:version_major) { should == 0 } its(:version_minor) { should == 9 } its(:server_properties) { should == {'copyright' => 'Copyright (C) 2007-2010 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.', 'information' => 'Licensed under the MPL. See http://www.rabbitmq.com/', 'platform' => 'Erlang/OTP', 'product' => 'RabbitMQ', 'version' => '2.2.0'} } its(:mechanisms) { should == 'PLAIN AMQPLAIN' } its(:locales) { should == 'en_US' } end end describe StartOk do describe '.encode' do it 'encodes the parameters into a MethodFrame' do client_properties = {:platform => 'Ruby 1.9.2', :product => 'AMQ Client', :information => 'http://github.com/ruby-amqp/amq-client', :version => '0.2.0'} mechanism = 'PLAIN' response = "\x00guest\x00guest" locale = 'en_GB' method_frame = StartOk.encode(client_properties, mechanism, response, locale) # the order of the table parts isn't deterministic in Ruby 1.8 method_frame.payload[0, 8].should == "\x00\n\x00\v\x00\x00\x00x" method_frame.payload.should include("\bplatformS\x00\x00\x00\nRuby 1.9.2") method_frame.payload.should include("\aproductS\x00\x00\x00\nAMQ Client") method_frame.payload.should include("\vinformationS\x00\x00\x00&http://github.com/ruby-amqp/amq-client") method_frame.payload.should include("\aversionS\x00\x00\x00\x050.2.0") method_frame.payload[-28, 28].should == "\x05PLAIN\x00\x00\x00\f\x00guest\x00guest\x05en_GB" method_frame.payload.length.should == 156 end end end describe Secure do describe '.decode' do subject do Secure.decode("\x00\x00\x00\x03foo") end its(:challenge) { should == 'foo' } end end describe SecureOk do describe '.encode' do it 'encodes the parameters as a MethodFrame' do response = 'bar' method_frame = SecureOk.encode(response) method_frame.payload.should == "\x00\x0a\x00\x15\x00\x00\x00\x03bar" end end end describe Tune do describe '.decode' do subject do Tune.decode("\x00\x00\x00\x02\x00\x00\x00\x00") end its(:channel_max) { should == 0 } its(:frame_max) { should == 131072 } its(:heartbeat) { should == 0} end end describe TuneOk do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel_max = 0 frame_max = 65536 heartbeat = 1 method_frame = TuneOk.encode(channel_max, frame_max, heartbeat) method_frame.payload.should == "\x00\n\x00\x1F\x00\x00\x00\x01\x00\x00\x00\x01" end end end describe Open do describe '.encode' do it 'encodes the parameters into a MethodFrame' do vhost = '/test' method_frame = Open.encode(vhost) method_frame.payload.should == "\x00\n\x00(\x05/test\x00\x00" end end end describe OpenOk do describe '.decode' do subject do OpenOk.decode("\x00") end its(:known_hosts) { should == '' } end end describe Close do describe '.decode' do context 'with code 200' do subject do Close.decode("\x00\xc8\x07KTHXBAI\x00\x05\x00\x06") end its(:reply_code) { should == 200 } its(:reply_text) { should == 'KTHXBAI' } its(:class_id) { should == 5 } its(:method_id) { should == 6 } end context 'with an error code' do it 'returns method frame and lets calling code handle the issue' do Close.decode("\x01\x38\x08NO_ROUTE\x00\x00") end end end describe '.encode' do it 'encodes the parameters into a MethodFrame' do reply_code = 540 reply_text = 'NOT_IMPLEMENTED' class_id = 0 method_id = 0 method_frame = Close.encode(reply_code, reply_text, class_id, method_id) method_frame.payload.should == "\x00\x0a\x002\x02\x1c\x0fNOT_IMPLEMENTED\x00\x00\x00\x00" end end end describe CloseOk do describe '.encode' do it 'encodes a MethodFrame' do method_frame = CloseOk.encode method_frame.payload.should == "\x00\n\x003" end end end end end end amq-protocol-0.9.2/spec/amq/protocol/blank_body_encoding_spec.rb0000644000175000017500000000062711772516231024337 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) describe AMQ::Protocol::Method, ".encode_body" do it "encodes 1-byte long payload as exactly 1 body frame" do described_class.encode_body('1', 1, 65536).size.should == 1 end it "encodes 0-byte long (blank) payload as exactly 0 body frame" do described_class.encode_body('', 1, 65536).size.should == 0 end end amq-protocol-0.9.2/spec/amq/protocol/value_encoder_spec.rb0000644000175000017500000001067611772516231023205 0ustar tfheentfheen# -*- coding: utf-8 -*- require File.expand_path('../../../spec_helper', __FILE__) require 'time' require "amq/protocol/table_value_encoder" module AMQ module Protocol describe TableValueEncoder do it "calculates size of string field values" do described_class.field_value_size("amqp").should == 9 described_class.encode("amqp").bytesize.should == 9 described_class.field_value_size("amq-protocol").should == 17 described_class.encode("amq-protocol").bytesize.should == 17 described_class.field_value_size("à bientôt").should == 16 described_class.encode("à bientôt").bytesize.should == 16 end it "calculates size of integer field values" do described_class.field_value_size(10).should == 5 described_class.encode(10).bytesize.should == 5 end it "calculates size of float field values (considering them to be 64-bit)" do described_class.field_value_size(10.0).should == 9 described_class.encode(10.0).bytesize.should == 9 described_class.field_value_size(120000.0).should == 9 described_class.encode(120000.0).bytesize.should == 9 end it "calculates size of boolean field values" do described_class.field_value_size(true).should == 2 described_class.encode(true).bytesize.should == 2 described_class.field_value_size(false).should == 2 described_class.encode(false).bytesize.should == 2 end it "calculates size of void field values" do described_class.field_value_size(nil).should == 1 described_class.encode(nil).bytesize.should == 1 end it "calculates size of time field values" do t = Time.parse("2011-07-14 01:17:46 +0400") described_class.field_value_size(t).should == 9 described_class.encode(t).bytesize.should == 9 end it "calculates size of basic table field values" do input1 = { "key" => "value" } described_class.field_value_size(input1).should == 19 described_class.encode(input1).bytesize.should == 19 input2 = { "intval" => 1 } described_class.field_value_size(input2).should == 17 described_class.encode(input2).bytesize.should == 17 input3 = { "intval" => 1, "key" => "value" } described_class.field_value_size(input3).should == 31 described_class.encode(input3).bytesize.should == 31 end it "calculates size of table field values" do input1 = { "hashval" => { "protocol" => { "name" => "AMQP", "major" => 0, "minor" => "9", "rev" => 1.0, "spec" => { "url" => "http://bit.ly/hw2ELX", "utf8" => one_point_eight? ? "à bientôt" : "à bientôt".force_encoding(::Encoding::ASCII_8BIT) } }, "true" => true, "false" => false, "nil" => nil } } described_class.field_value_size(input1).should == 162 # puts(described_class.encode(input1).inspect) described_class.encode(input1).bytesize.should == 162 input2 = { "boolval" => true, "intval" => 1, "strval" => "Test", "timestampval" => Time.parse("2011-07-14 01:17:46 +0400"), "floatval" => 3.14, "longval" => 912598613, "hashval" => { "protocol" => "AMQP091", "true" => true, "false" => false, "nil" => nil } } described_class.field_value_size(input2).should == 150 described_class.encode(input2).bytesize.should == 150 end it "calculates size of basic array field values" do input1 = [1, 2, 3] described_class.field_value_size(input1).should == 20 described_class.encode(input1).bytesize.should == 20 input2 = ["one", "two", "three"] described_class.field_value_size(input2).should == 31 described_class.encode(input2).bytesize.should == 31 input3 = ["one", 2, "three"] described_class.field_value_size(input3).should == 28 described_class.encode(input3).bytesize.should == 28 input4 = ["one", 2, "three", ["four", 5, [6.0]]] described_class.field_value_size(input4).should == 61 described_class.encode(input4).bytesize.should == 61 end end # TableValueEncoder end # Protocol end # AMQ amq-protocol-0.9.2/spec/amq/protocol/channel_spec.rb0000644000175000017500000000745011772516231021776 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol class Channel describe Open do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 out_of_band = '' method_frame = Open.encode(channel, out_of_band) method_frame.payload.should == "\x00\x14\x00\n\x00" method_frame.channel.should == 1 end end end describe OpenOk do describe '.decode' do subject do OpenOk.decode("\x00\x00\x00\x03foo") end its(:channel_id) { should == 'foo' } end end describe Flow do describe '.decode' do subject do Flow.decode("\x01") end its(:active) { should be_true } end describe '.encode' do it 'encodes the parameters as a MethodFrame' do channel = 1 active = true method_frame = Flow.encode(channel, active) method_frame.payload.should == "\x00\x14\x00\x14\x01" method_frame.channel.should == 1 end end end describe FlowOk do describe '.decode' do subject do FlowOk.decode("\x00") end its(:active) { should be_false } end describe '.encode' do it 'encodes the parameters as a MethodFrame' do channel = 1 active = true method_frame = FlowOk.encode(channel, active) method_frame.payload.should == "\x00\x14\x00\x15\x01" method_frame.channel.should == 1 end end end describe Close do describe '.decode' do context 'with code 200' do subject do Close.decode("\x00\xc8\x07KTHXBAI\x00\x05\x00\x06") end its(:reply_code) { should == 200 } its(:reply_text) { should == 'KTHXBAI' } its(:class_id) { should == 5 } its(:method_id) { should == 6 } end context 'with code 404 and reply_text length > 127 characters' do subject do raw = "\x01\x94\x80NOT_FOUND - no binding 123456789012345678901234567890123 between exchange 'amq.topic' in vhost '/' and queue 'test' in vhost '/'\x002\x002" Close.decode(raw) end its(:reply_code) { should == 404 } its(:reply_text) { should == %q{NOT_FOUND - no binding 123456789012345678901234567890123 between exchange 'amq.topic' in vhost '/' and queue 'test' in vhost '/'} } its(:class_id) { should == 50 } its(:method_id) { should == 50 } end context 'with an error code' do it 'returns frame and lets calling code handle the issue' do Close.decode("\x01\x38\x08NO_ROUTE\x00\x00") end end end describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 reply_code = 540 reply_text = 'NOT_IMPLEMENTED' class_id = 0 method_id = 0 method_frame = Close.encode(channel, reply_code, reply_text, class_id, method_id) method_frame.payload.should == "\x00\x14\x00(\x02\x1c\x0fNOT_IMPLEMENTED\x00\x00\x00\x00" method_frame.channel.should == 1 end end end describe CloseOk do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 method_frame = CloseOk.encode(1) method_frame.payload.should == "\x00\x14\x00\x29" method_frame.channel.should == 1 end end end end end end amq-protocol-0.9.2/spec/amq/protocol/frame_spec.rb0000644000175000017500000000726111772516231021460 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol describe Frame do describe ".encode" do it "should raise FrameTypeError if type isn't one of: [:method, :header, :body, :heartbeat]" do lambda { Frame.encode(nil, "", 0) }.should raise_error(FrameTypeError) end it "should raise FrameTypeError if type isn't valid (when type is a symbol)" do expect { Frame.encode(:xyz, "test", 12) }.to raise_error(FrameTypeError) end it "should raise FrameTypeError if type isn't valid (when type is a number)" do expect { Frame.encode(16, "test", 12) }.to raise_error(FrameTypeError) end it "should raise RuntimeError if channel isn't 0 or an integer in range 1..65535" do lambda { Frame.encode(:method, "", -1) }.should raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/) lambda { Frame.encode(:method, "", 65536) }.should raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/) lambda { Frame.encode(:method, "", 65535) }.should_not raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/) lambda { Frame.encode(:method, "", 0) }.should_not raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/) lambda { Frame.encode(:method, "", 1) }.should_not raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/) end it "should raise RuntimeError if payload is nil" do lambda { Frame.encode(:method, nil, 0) }.should raise_error(RuntimeError, "Payload can't be nil") end it "should encode type" do Frame.encode(:body, "", 0).unpack("c").first.should eql(3) end it "should encode channel" do Frame.encode(:body, "", 12).unpack("cn").last.should eql(12) end it "should encode size" do Frame.encode(:body, "test", 12).unpack("cnN").last.should eql(4) end it "should include payload" do Frame.encode(:body, "test", 12)[7..-2].should eql("test") end it "should include final octet" do Frame.encode(:body, "test", 12).should =~ /\xCE$/ end it "should encode unicode strings" do expect { Frame.encode(:body, "à bientôt!", 12) }.to_not raise_error end end describe ".new" do it "should raise FrameTypeError if the type is not one of the accepted" do expect { Frame.new(10) }.to raise_error(FrameTypeError) end end describe '#decode_header' do it 'raises FrameTypeError if the decoded type is not one of the accepted' do expect { Frame.decode_header("\n\x00\x01\x00\x00\x00\x05") }.to raise_error(FrameTypeError) end it 'raises EmptyResponseError if the header is nil' do expect { Frame.decode_header(nil) }.to raise_error(EmptyResponseError) end end describe HeaderFrame do subject { HeaderFrame.new("\x00<\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\x98\x00\x18application/octet-stream\x02\x00", nil) } it "should decode body_size from payload" do subject.body_size.should == 10 end it "should decode klass_id from payload" do subject.klass_id.should == 60 end it "should decode weight from payload" do subject.weight.should == 0 end it "should decode properties from payload" do subject.properties[:delivery_mode].should == 2 subject.properties[:priority].should == 0 end end end end end amq-protocol-0.9.2/spec/amq/protocol/value_decoder_spec.rb0000644000175000017500000000331111772516231023157 0ustar tfheentfheen# -*- coding: utf-8 -*- require File.expand_path('../../../spec_helper', __FILE__) require 'time' require "amq/protocol/table_value_decoder" module AMQ module Protocol describe TableValueDecoder do it "is capable of decoding basic arrays TableValueEncoder encodes" do input1 = [1, 2, 3] value, offset = described_class.decode_array(TableValueEncoder.encode(input1), 1) value.size.should == 3 value.first.should == 1 value.should == input1 input2 = ["one", 2, "three"] value, offset = described_class.decode_array(TableValueEncoder.encode(input2), 1) value.size.should == 3 value.first.should == "one" value.should == input2 input3 = ["one", 2, "three", 4.0, 5000000.0] value, offset = described_class.decode_array(TableValueEncoder.encode(input3), 1) value.size.should == 5 value.last.should == 5000000.0 value.should == input3 end it "is capable of decoding arrays TableValueEncoder encodes" do input1 = [{ "one" => 2 }, 3] data1 = TableValueEncoder.encode(input1) # puts(TableValueEncoder.encode({ "one" => 2 }).inspect) # puts(TableValueEncoder.encode(input1).inspect) value, offset = described_class.decode_array(data1, 1) value.size.should == 2 value.first.should == Hash["one" => 2] value.should == input1 input2 = ["one", 2, { "three" => { "four" => 5.0 } }] value, offset = described_class.decode_array(TableValueEncoder.encode(input2), 1) value.size.should == 3 value.last["three"]["four"].should == 5.0 value.should == input2 end end end end amq-protocol-0.9.2/spec/amq/protocol/method_spec.rb0000644000175000017500000000356011772516231021644 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol describe Method do describe '.split_headers' do it 'splits user defined headers into properties and headers' do input = {:delivery_mode => 2, :content_type => 'application/octet-stream', :foo => 'bar'} properties, headers = Method.split_headers(input) properties.should == {:delivery_mode => 2, :content_type => 'application/octet-stream'} headers.should == {:foo => 'bar'} end end describe '.encode_body' do context 'when the body fits in a single frame' do it 'encodes a body into a BodyFrame' do body_frames = Method.encode_body('Hello world', 1, 131072) body_frames.first.payload.should == 'Hello world' body_frames.first.channel.should == 1 body_frames.should have(1).item end end context 'when the body is too big to fit in a single frame' do it 'encodes a body into a list of BodyFrames that each fit within the frame size' do lipsum = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.' frame_size = 100 expected_payload_size = 92 body_frames = Method.encode_body(lipsum, 1, frame_size) body_frames.map(&:payload).should == lipsum.split('').each_slice(expected_payload_size).map(&:join) end end end end end end amq-protocol-0.9.2/spec/amq/protocol/basic_spec.rb0000644000175000017500000002600411772516231021443 0ustar tfheentfheen# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) module AMQ module Protocol describe Basic do describe '.encode_timestamp' do it 'encodes the timestamp as a 64 byte big endian integer' do Basic.encode_timestamp(12345).last.should == "\x00\x00\x00\x00\x00\x0009" end end # describe '.decode_timestamp' do # it 'decodes the timestamp from a 64 byte big endian integer and returns a Time object' do # Basic.decode_timestamp("\x00\x00\x00\x00\x00\x0009").should == Time.at(12345) # end # end describe '.encode_headers' do it 'encodes the headers as a table' do Basic.encode_headers(:hello => 'world').last.should == "\x00\x00\x00\x10\x05helloS\x00\x00\x00\x05world" end end # describe '.decode_headers' do # it 'decodes the headers from a table' do # Basic.decode_headers("\x00\x00\x00\x10\x05helloS\x00\x00\x00\x05world").should == {'hello' => 'world'} # end # end describe '.encode_properties' do it 'packs the parameters into a byte array using the other encode_* methods' do result = Basic.encode_properties(10, {:priority => 0, :delivery_mode => 2, :content_type => 'application/octet-stream'}) result.should == "\x00<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x98\x00\x18application/octet-stream\x02\x00" end end describe '.decode_properties' do it 'unpacks the properties from a byte array using the decode_* methods' do result = Basic.decode_properties("\x98@\x18application/octet-stream\x02\x00\x00\x00\x00\x00\x00\x00\x00{") result.should == {:priority => 0, :delivery_mode => 2, :content_type => 'application/octet-stream', :timestamp => Time.at(123)} end it 'unpacks the properties from a byte array using the decode_* methods, including a table' do result = Basic.decode_properties("\xB8@\x18application/octet-stream\x00\x00\x00\x10\x05helloS\x00\x00\x00\x05world\x02\x00\x00\x00\x00\x00\x00\x00\x00{") result.should == {:priority => 0, :delivery_mode => 2, :content_type => 'application/octet-stream', :timestamp => Time.at(123), :headers => {'hello' => 'world'}} end end %w(content_type content_encoding correlation_id reply_to expiration message_id type user_id app_id cluster_id).each do |method| describe ".encode_#{method}" do it 'encodes the parameter as a Pascal string' do Basic.send("encode_#{method}", 'hello world').last.should == "\x0bhello world" end end # describe ".decode_#{method}" do # it 'returns the string' do # # the length has been stripped in .decode_properties # Basic.send("decode_#{method}", 'hello world').should == 'hello world' # end # end end %w(delivery_mode priority).each do |method| describe ".encode_#{method}" do it 'encodes the parameter as a char' do Basic.send("encode_#{method}", 10).last.should == "\x0a" end end # describe ".decode_#{method}" do # it 'decodes the value from a char' do # Basic.send("decode_#{method}", "\x10").should == 16 # end # end end end class Basic describe Qos do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 prefetch_size = 3 prefetch_count = 5 global = false method_frame = Qos.encode(channel, prefetch_size, prefetch_count, global) method_frame.payload.should == "\x00<\x00\n\x00\x00\x00\x03\x00\x05\x00" method_frame.channel.should == 1 end end end # describe QosOk do # describe '.decode' do # end # end describe Consume do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 queue = 'foo' consumer_tag = 'me' no_local = false no_ack = false exclusive = true nowait = false arguments = nil method_frame = Consume.encode(channel, queue, consumer_tag, no_local, no_ack, exclusive, nowait, arguments) method_frame.payload.should == "\x00<\x00\x14\x00\x00\x03foo\x02me\x04\x00\x00\x00\x00" method_frame.channel.should == 1 end end end describe ConsumeOk do describe '.decode' do subject do ConsumeOk.decode("\x03foo") end its(:consumer_tag) { should == 'foo' } end end describe Cancel do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 consumer_tag = 'foo' nowait = true method_frame = Cancel.encode(channel, consumer_tag, nowait) method_frame.payload.should == "\x00<\x00\x1E\x03foo\x01" method_frame.channel.should == 1 end end describe '.decode' do subject do CancelOk.decode("\x03foo\x01") end its(:consumer_tag) { should == 'foo' } end end describe CancelOk do describe '.decode' do subject do CancelOk.decode("\x03foo") end its(:consumer_tag) { should == 'foo' } end end describe Publish do describe '.encode' do it 'encodes the parameters into a list of MethodFrames' do channel = 1 payload = 'Hello World!' user_headers = {:priority => 0, :content_type => 'application/octet-stream'} exchange = 'foo' routing_key = 'xyz' mandatory = false immediate = true frame_size = 512 method_frames = Publish.encode(channel, payload, user_headers, exchange, routing_key, mandatory, immediate, frame_size) method_frames[0].payload.should == "\x00<\x00(\x00\x00\x03foo\x03xyz\x02" method_frames[1].payload.should == "\x00<\x00\x00\x00\x00\x00\x00\x00\x00\x00\f\x88\x00\x18application/octet-stream\x00" method_frames[2].payload.should == "Hello World!" method_frames[0].channel.should == 1 method_frames[1].channel.should == 1 method_frames[2].channel.should == 1 method_frames.should have(3).items end end end describe Return do describe '.decode' do subject do Return.decode("\x019\fNO_CONSUMERS\namq.fanout\x00") end its(:reply_code) { should == 313 } its(:reply_text) { should == 'NO_CONSUMERS' } its(:exchange) { should == 'amq.fanout' } its(:routing_key) { should == '' } end end describe Deliver do describe '.decode' do subject do Deliver.decode("\e-1300560114000-445586772970\x00\x00\x00\x00\x00\x00\x00c\x00\namq.fanout\x00") end its(:consumer_tag) { should == '-1300560114000-445586772970' } its(:delivery_tag) { should == 99 } its(:redelivered) { should == false } its(:exchange) { should == 'amq.fanout' } its(:routing_key) { should == '' } end end describe Get do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 queue = 'foo' no_ack = true method_frame = Get.encode(channel, queue, no_ack) method_frame.payload.should == "\x00\x3c\x00\x46\x00\x00\x03foo\x01" method_frame.channel.should == 1 end end end describe GetOk do describe '.decode' do subject do GetOk.decode("\x00\x00\x00\x00\x00\x00\x00\x06\x00\namq.fanout\x00\x00\x00\x00^") end its(:delivery_tag) { should == 6 } its(:redelivered) { should == false } its(:exchange) { should == 'amq.fanout' } its(:routing_key) { should == '' } its(:message_count) { should == 94 } end end describe GetEmpty do describe '.decode' do subject do GetEmpty.decode("\x03foo") end its(:cluster_id) { should == 'foo' } end end describe Ack do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 delivery_tag = 6 multiple = false method_frame = Ack.encode(channel, delivery_tag, multiple) method_frame.payload.should == "\x00<\x00P\x00\x00\x00\x00\x00\x00\x00\x06\x00" method_frame.channel.should == 1 end end end describe Reject do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 delivery_tag = 8 requeue = true method_frame = Reject.encode(channel, delivery_tag, requeue) method_frame.payload.should == "\x00<\x00Z\x00\x00\x00\x00\x00\x00\x00\x08\x01" method_frame.channel.should == 1 end end end describe RecoverAsync do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 requeue = true method_frame = RecoverAsync.encode(channel, requeue) method_frame.payload.should == "\x00<\x00d\x01" method_frame.channel.should == 1 end end end describe Recover do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 requeue = true method_frame = Recover.encode(channel, requeue) method_frame.payload.should == "\x00<\x00n\x01" method_frame.channel.should == 1 end end end # describe RecoverOk do # describe '.decode' do # end # end describe Nack do describe '.decode' do subject do Nack.decode("\x00\x00\x00\x00\x00\x00\x00\x09\x03") end its(:delivery_tag) { should == 9 } its(:multiple) { should == true } its(:requeue) { should == true } end describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 delivery_tag = 10 multiple = false requeue = true method_frame = Nack.encode(channel, delivery_tag, multiple, requeue) method_frame.payload.should == "\x00<\x00x\x00\x00\x00\x00\x00\x00\x00\x0a\x02" method_frame.channel.should == 1 end end end end end endamq-protocol-0.9.2/spec/spec_helper.rb0000644000175000017500000000101111772516231017211 0ustar tfheentfheen# encoding: binary require 'bundler/setup' require 'rspec' begin require 'simplecov' SimpleCov.start do add_filter '/spec/' end rescue LoadError end $: << File.expand_path('../../lib', __FILE__) require "amq/protocol" puts "Running on #{RUBY_VERSION}" module RubyVersionsSUpport def one_point_eight? RUBY_VERSION =~ /^1.8/ end end # RubyVersionsSUpport RSpec.configure do |config| config.include AMQ::Protocol config.include(RubyVersionsSUpport) config.extend(RubyVersionsSUpport) end amq-protocol-0.9.2/.gitmodules0000644000175000017500000000017411772516231015627 0ustar tfheentfheen[submodule "vendor/rabbitmq-codegen"] path = vendor/rabbitmq-codegen url = git://github.com/rabbitmq/rabbitmq-codegen.git amq-protocol-0.9.2/metadata.yml0000644000175000017500000000472311772516231015761 0ustar tfheentfheen--- !ruby/object:Gem::Specification name: amq-protocol version: !ruby/object:Gem::Version hash: 63 prerelease: segments: - 0 - 9 - 2 version: 0.9.2 platform: ruby authors: - Jakub Stastny - Michael S. Klishin - Theo Hultberg - Mark Abramov autorequire: bindir: bin cert_chain: [] date: 2012-06-26 00:00:00 Z dependencies: [] description: " amq-protocol is an AMQP 0.9.1 serialization library for Ruby. It is not an\n AMQP client: amq-protocol only handles serialization and deserialization.\n If you want to write your own AMQP client, this gem can help you with that.\n" email: - michael@novemberain.com - stastny@101ideas.cz executables: [] extensions: [] extra_rdoc_files: - README.md files: - .gitignore - .gitmodules - .rspec - .travis.yml - Gemfile - LICENSE - PROFILING.md - README.md - __init__.py - amq-protocol.gemspec - amqp_0.9.1_changes.json - codegen.py - codegen_helpers.py - generate.rb - irb.rb - lib/amq/hacks.rb - lib/amq/protocol.rb - lib/amq/protocol/client.rb - lib/amq/protocol/frame.rb - lib/amq/protocol/table.rb - lib/amq/protocol/table_value_decoder.rb - lib/amq/protocol/table_value_encoder.rb - lib/amq/protocol/type_constants.rb - lib/amq/protocol/version.rb - post-processing.rb - protocol.rb.pytemplate - spec/amq/hacks_spec.rb - spec/amq/protocol/basic_spec.rb - spec/amq/protocol/blank_body_encoding_spec.rb - spec/amq/protocol/channel_spec.rb - spec/amq/protocol/confirm_spec.rb - spec/amq/protocol/connection_spec.rb - spec/amq/protocol/exchange_spec.rb - spec/amq/protocol/frame_spec.rb - spec/amq/protocol/method_spec.rb - spec/amq/protocol/queue_spec.rb - spec/amq/protocol/table_spec.rb - spec/amq/protocol/tx_spec.rb - spec/amq/protocol/value_decoder_spec.rb - spec/amq/protocol/value_encoder_spec.rb - spec/amq/protocol_spec.rb - spec/spec_helper.rb homepage: http://github.com/ruby-amqp/amq-protocol licenses: - MIT post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: amq-protocol rubygems_version: 1.8.15 signing_key: specification_version: 3 summary: AMQP 0.9.1 encoder & decoder. test_files: [] has_rdoc: amq-protocol-0.9.2/LICENSE0000644000175000017500000000215011772516231014453 0ustar tfheentfheenCopyright (c) 2010 – 2011 Jakub Šťastný aka Botanicus Copyright (c) 2011 - 2012 Michael S. Klishin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. amq-protocol-0.9.2/codegen_helpers.py0000644000175000017500000001447111772516231017157 0ustar tfheentfheen# -*- coding: utf-8 -*- def genSingleEncode(spec, cValue, unresolved_domain): buffer = [] type = spec.resolveDomain(unresolved_domain) if type == 'shortstr': buffer.append("buffer << %s.bytesize.chr" % (cValue,)) buffer.append("buffer << %s" % (cValue,)) elif type == 'longstr': buffer.append("buffer << [%s.bytesize].pack(PACK_UINT32)" % (cValue,)) buffer.append("buffer << %s" % (cValue,)) elif type == 'octet': buffer.append("buffer << [%s].pack(PACK_CHAR)" % (cValue,)) elif type == 'short': buffer.append("buffer << [%s].pack(PACK_UINT16)" % (cValue,)) elif type == 'long': buffer.append("buffer << [%s].pack(PACK_UINT32)" % (cValue,)) elif type == 'longlong': buffer.append("buffer << AMQ::Hacks.pack_64_big_endian(%s)" % (cValue,)) elif type == 'timestamp': buffer.append("buffer << AMQ::Hacks.pack_64_big_endian(%s)" % (cValue,)) elif type == 'bit': raise "Can't encode bit in genSingleEncode" elif type == 'table': buffer.append("buffer << AMQ::Protocol::Table.encode(%s)" % (cValue,)) else: raise "Illegal domain in genSingleEncode", type return buffer def genSingleDecode(spec, field): cLvalue = field.ruby_name unresolved_domain = field.domain if cLvalue == "known_hosts": import sys print >> sys.stderr, field, field.ignored type = spec.resolveDomain(unresolved_domain) buffer = [] if type == 'shortstr': buffer.append("length = data[offset, 1].unpack(PACK_CHAR).first") buffer.append("offset += 1") buffer.append("%s = data[offset, length]" % (cLvalue,)) buffer.append("offset += length") elif type == 'longstr': buffer.append("length = data[offset, 4].unpack(PACK_UINT32).first") buffer.append("offset += 4") buffer.append("%s = data[offset, length]" % (cLvalue,)) buffer.append("offset += length") elif type == 'octet': buffer.append("%s = data[offset, 1].unpack(PACK_CHAR).first" % (cLvalue,)) buffer.append("offset += 1") elif type == 'short': buffer.append("%s = data[offset, 2].unpack(PACK_UINT16).first" % (cLvalue,)) buffer.append("offset += 2") elif type == 'long': buffer.append("%s = data[offset, 4].unpack(PACK_UINT32).first" % (cLvalue,)) buffer.append("offset += 4") elif type == 'longlong': buffer.append("%s = AMQ::Hacks.unpack_64_big_endian(data[offset, 8]).first" % (cLvalue,)) buffer.append("offset += 8") elif type == 'timestamp': buffer.append("%s = data[offset, 8].unpack(PACK_UINT32_X2).first" % (cLvalue,)) buffer.append("offset += 8") elif type == 'bit': raise "Can't decode bit in genSingleDecode" elif type == 'table': buffer.append("table_length = Table.length(data[offset, 4])") buffer.append("%s = Table.decode(data[offset, table_length + 4])" % (cLvalue,)) buffer.append("offset += table_length + 4") else: raise StandardError("Illegal domain '" + type + "' in genSingleDecode") return buffer def genSingleSimpleDecode(spec, field): cLvalue = field.ruby_name unresolved_domain = field.domain if cLvalue == "known_hosts": import sys print >> sys.stderr, field, field.ignored type = spec.resolveDomain(unresolved_domain) buffer = [] if type == 'shortstr': # buffer.append("length = data.unpack(PACK_CHAR)[0]") # buffer.append("result = data[offset..-1]") # buffer.append("raise 'Bad size: #{length} expected, got #{result.bytesize}' if result.bytesize != length") # buffer.append("result") buffer.append("data") elif type == 'longstr': # buffer.append("length = data.unpack(PACK_CHAR)[0]") # buffer.append("result = data[offset..-1]") # buffer.append("raise 'Bad size: #{length} expected, got #{result.bytesize}' if result.bytesize != length") # buffer.append("result") buffer.append("data") elif type == 'octet': buffer.append("data.unpack(PACK_CHAR).first") elif type == 'short': buffer.append("data.unpack(PACK_UINT16).first") elif type == 'long': buffer.append("data.unpack(PACK_UINT32).first") elif type == 'longlong': buffer.append("AMQ::Hacks.unpack_64_big_endian(data).first") elif type == 'timestamp': buffer.append("Time.at(data.unpack(PACK_UINT32_X2).last)") elif type == 'bit': raise "Can't decode bit in genSingleDecode" elif type == 'table': buffer.append("Table.decode(data)") else: raise StandardError("Illegal domain '" + type + "' in genSingleSimpleDecode") return buffer def genEncodeMethodDefinition(spec, m): def finishBits(): if bit_index is not None: buffer.append("buffer << [bit_buffer].pack(PACK_CHAR)") bit_index = None buffer = [] for f in m.arguments: if spec.resolveDomain(f.domain) == 'bit': if bit_index is None: bit_index = 0 buffer.append("bit_buffer = 0") if bit_index >= 8: finishBits() buffer.append("bit_buffer = 0") bit_index = 0 buffer.append("bit_buffer = bit_buffer | (1 << %d) if %s" % (bit_index, f.ruby_name)) bit_index = bit_index + 1 else: finishBits() bit_index = None buffer += genSingleEncode(spec, f.ruby_name, f.domain) finishBits() return buffer def genDecodeMethodDefinition(spec, m): buffer = [] bitindex = None for f in m.arguments: if spec.resolveDomain(f.domain) == 'bit': if bitindex is None: bitindex = 0 if bitindex >= 8: bitindex = 0 if bitindex == 0: buffer.append("bit_buffer = data[offset, 1].unpack(PACK_CHAR).first") buffer.append("offset += 1") buffer.append("%s = (bit_buffer & (1 << %d)) != 0" % (f.ruby_name, bitindex)) #### TODO: ADD bitindex TO THE buffer else: buffer.append("%s = (bit_buffer & (1 << %d)) != 0" % (f.ruby_name, bitindex)) bitindex = bitindex + 1 else: bitindex = None buffer += genSingleDecode(spec, f) return buffer amq-protocol-0.9.2/.rspec0000644000175000017500000000003311772516231014561 0ustar tfheentfheen--colour --format progress amq-protocol-0.9.2/README.md0000644000175000017500000000251611772516231014733 0ustar tfheentfheen# What is amq-protocol. amq-protocol is an AMQP 0.9.1 serialization library for Ruby. It is not an AMQP client: amq-protocol only handles serialization and deserialization. If you want to write your own AMQP client, this gem can help you with that. ## How does amq-protocol relate to amqp gem, amq-client and libraries like bunny? See [this page about AMQP gems family](https://github.com/ruby-amqp/amq-client/blob/master/README.textile) ## Installation gem install amq-protocol ## Development Make sure you have Python and the mako templating package installed. amq-protocol uses RabbitMQ protocol code generation library that is in Python, so there is some Python involved in the build. Don't fret. To regenerate `lib/amq/protocol/client.rb` from the source (`protocol.rb.pytemplate`), run ./generate.rb To make changes, **do not edit client.rb directly**. Instead, edit `protocol.rb.pytemplate` and regenerate. To run tests, use bundle install --binstubs ./bin/rspec -c spec spec ## Maintainer Information amq-protocol is maintained by [Michael Klishin](https://github.com/michaelklishin). ## Links * [Continous integration server](http://travis-ci.org/#!/ruby-amqp/amq-protocol) * [Ruby AMQP mailing list](http://groups.google.com/group/ruby-amqp) * [Issue tracker](http://github.com/ruby-amqp/amq-protocol/issues) amq-protocol-0.9.2/codegen.py0000755000175000017500000001103011772516231015424 0ustar tfheentfheen#!/usr/bin/env python # -*- coding: utf-8 -*- # Documentation for Mako templates: # http://www.makotemplates.org/docs/syntax.html import os, sys, re sys.path.append(os.path.join("vendor", "rabbitmq-codegen")) from amqp_codegen import * try: from mako.template import Template except ImportError: print "Mako isn't installed. Run easy_install mako." sys.exit(1) # main class class AmqpSpecObject(AmqpSpec): IGNORED_CLASSES = ["access"] IGNORED_FIELDS = { 'ticket': 0, 'capabilities': '', 'insist' : 0, 'out_of_band': '', 'known_hosts': '', } def __init__(self, path): AmqpSpec.__init__(self, path) def extend_field(field): field.ruby_name = re.sub("[- ]", "_", field.name) field.type = self.resolveDomain(field.domain) field.ignored = bool(field.name in self.__class__.IGNORED_FIELDS) # I. e. deprecated for klass in self.classes: klass.ignored = bool(klass.name in self.__class__.IGNORED_CLASSES) for field in klass.fields: extend_field(field) for method in klass.methods: for field in method.arguments: extend_field(field) self.classes = filter(lambda klass: not klass.ignored, self.classes) # I know, I'm a bad, bad boy, but come on guys, # monkey-patching is just handy for this case. # Oh hell, why Python doesn't have at least # anonymous functions? This looks so ugly. original_init = AmqpEntity.__init__ def new_init(self, arg): original_init(self, arg) constant_name = "" for chunk in self.name.split("-"): constant_name += chunk.capitalize() self.constant_name = constant_name AmqpEntity.__init__ = new_init # method.accepted_by("server") # method.accepted_by("client", "server") accepted_by_update = json.loads(file("amqp_0.9.1_changes.json").read()) def accepted_by(self, *receivers): def get_accepted_by(self): try: return accepted_by_update[self.klass.name][self.name] except KeyError: return ["server", "client"] actual_receivers = get_accepted_by(self) return all(map(lambda receiver: receiver in actual_receivers, receivers)) AmqpMethod.accepted_by = accepted_by def convert_value_to_ruby(value): values = {None: "nil", False: "false", True: "true", "": "EMPTY_STRING"} try: return values[value] except: return value.__repr__() def convert_to_ruby(field): name = re.sub("-", "_", field.name) # TODO: use ruby_name if name == "ticket": return "%s = %s" % (name, field.defaultvalue) # we want to keep it as an int, not as a boolean else: return "%s = %s" % (name, convert_value_to_ruby(field.defaultvalue)) def not_ignored_args(self): if self.hasContent: return ["payload", "user_headers"] + map(lambda argument: argument.ruby_name, filter(lambda argument: not argument.ignored, self.arguments)) + ["frame_size"] else: return map(lambda argument: argument.ruby_name, filter(lambda argument: not argument.ignored, self.arguments)) AmqpMethod.not_ignored_args = not_ignored_args def ignored_args(self): return filter(lambda argument: argument.ignored, self.arguments) AmqpMethod.ignored_args = ignored_args # helpers def to_ruby_name(name): return re.sub("[- ]", "_", name) def to_ruby_class_name(name): parts = re.split("[- ]", name) ruby_class_name = "" for part in parts: ruby_class_name = ruby_class_name + part[0].upper() + part[1:].lower() return ruby_class_name def params(self): buffer = [] for f in self.arguments: buffer.append(convert_to_ruby(f)) if self.hasContent: buffer.append("user_headers = nil") buffer.append("payload = \"\"") buffer.append("frame_size = nil") return buffer AmqpMethod.params = params def args(self): return map(lambda item: item.split(" ")[0], self.params()) AmqpMethod.args = args def binary(self): method_id = self.klass.index << 16 | self.index return "0x%08X # %i, %i, %i" % (method_id, self.klass.index, self.index, method_id) AmqpMethod.binary = binary # helpers def render(path, **context): file = open(path) template = Template(file.read()) return template.render(**context) def generateMain(type): def main(json_spec_path): spec = AmqpSpecObject(json_spec_path) spec.type = type print render("protocol.rb.pytemplate", spec = spec) return main if __name__ == "__main__": do_main_dict({"client": generateMain("client")}) amq-protocol-0.9.2/amqp_0.9.1_changes.json0000644000175000017500000000266411772516231017526 0ustar tfheentfheen{"tx": {"select-ok": ["client"], "rollback": ["server"], "commit": ["server"], "rollback-ok": ["client"], "select": ["server"], "commit-ok": ["client"]}, "exchange": {"delete-ok": ["client"], "declare-ok": ["client"], "declare": ["server"], "delete": ["server"], "bind": ["server"], "bind-ok": ["client"], "unbind": ["server"], "unbind-ok": ["client"]}, "queue": {"unbind": ["server"], "unbind-ok": ["client"], "purge-ok": ["client"], "bind": ["server"], "purge": ["server"], "declare-ok": ["client"], "delete-ok": ["client"], "delete": ["server"], "declare": ["server"], "bind-ok": ["client"]}, "connection": {"secure": ["client"], "secure-ok": ["server"], "open-ok": ["client"], "close-ok": ["client", "server"], "start": ["client"], "tune": ["client"], "start-ok": ["server"], "close": ["client", "server"], "open": ["server"], "tune-ok": ["server"]}, "basic": {"qos": ["server"], "consume": ["server"], "reject": ["server"], "get": ["server"], "ack": ["client", "server"], "get-ok": ["client"], "consume-ok": ["client"], "deliver": ["client"], "recover-ok": ["client"], "publish": ["server"], "cancel": ["server", "client"], "recover-async": ["server"], "get-empty": ["client"], "qos-ok": ["client"], "return": ["client"], "recover": ["server"], "cancel-ok": ["client"]}, "channel": {"flow-ok": ["server", "client"], "flow": ["server", "client"], "open-ok": ["client"], "close-ok": ["client", "server"], "close": ["client", "server"], "open": ["server"]}} amq-protocol-0.9.2/PROFILING.md0000644000175000017500000002064211772516231015327 0ustar tfheentfheen# Profiling To profile the encoding and decoding code use Aman Gupta's perftools.rb (https://github.com/tmm1/perftools.rb). It's really easy to use once you've set it up, and it generates graphs that make it pretty obvious where the hotspots are. ## Setup Start by installing perftools.rb: gem install perftools.rb I have it installed in my global gemset, which is handy since you can profile projects that uses any other gemset without having to add perftools.rb to its Gemfile: rvm gemset use global gem install perftools.rb If you look at the README for perftools.rb the way to use it seems really icky, having to set environment variables and all that. I have the following script saved as `~/bin/profile` to encapsulate all that: #!/bin/bash profile_id=$(date +'%Y%m%d%H%M%S') CPUPROFILE=/tmp/$profile_id RUBYOPT="-r`gem which perftools | tail -1`" $@ pprof.rb --pdf /tmp/$profile_id > /tmp/$profile_id.pdf open /tmp/$profile_id.pdf With this script you can prefix any command with "profile" and perftools.rb will be enabed, and a nice graph will be opened in Preview as soon as the program exits. This only works on OS X, obviously, but I'm sure it can be made to work on Linux too. ## How to profile the code Most of the time you want to profile a specific method or piece of code. The easiest thing to do is write a short script that runs that code over and over again. This will make sure that the profile graph isn't swamped by noise from other parts of the code, and running lots of iterations means that the numbers will be more stable. Perhaps most importantly it will also show the impact of the GC. 100000.times do strs.each do |str| AMQ::Client::Framing::String::Frame.decode(str) end end In the code above the `strs` variable holds a list of strings I've stolen from the amqp-benchmarks repository. I call the `decode` method of the `AMQ::Client::Framing::String::Frame` class over and over again and after 100K iterations (this takes around ten seconds to run) I get a graph that shows me which parts of the code take most time. This is how you run the script above (assuming you fill in the `strs` list and add the necessary require's -- and that you've followed the instructions at the top of this document -- and that you've named it "benchmark_script.rb"): profile ruby benchmark_script.rb It will run for a few seconds and then open a graph. Next I'll explain how to interpret that graph. ## Interpreting the profile graph The graph generated by perftools.rb shows all the methods that have run, which methods they call, how much time was spent in each method, and a lot of other very interesting things. At the top left of the picture it says mow many samples were taken. perftools.rb samples 100 times per second, so 1257 samples means that it ran for 12.57 seconds. The number of samples per second can be tweaked, but I've never had any reason to. The next three numbers just tell you that there are methods that were called not very often, and that these are not shown in the graph, to make it easier to read. There are usually two, and sometimes three, nodes which don't have any arrows pointing into them. The first is the entry point into your application, the second the GC, and sometimes there is a third which usually is RubyGems or Bundler. There is no reason there can't be more top level nodes, but those are the ones I've seen. Each node represents a method. The label is the class and method name, in classic Ruby style: ClassName#instance_method_name. Unfortunately it doesn't handle class methods very well, so all end up ass Class#method_name. This is bad for us, since most methods in amq-protocol are class methods. It also means that all class methods of the same name, regardless of which class then belong are represented as one node. That's really bad for us, since a lot of methods that we want to profile are called "decode" and "encode". The numbers below the label are the self time and cumulative time measurements, first as samples and then, in parentheses as percentages of the whole. Self time means the time spent in the method, excluding other methods, and cumulative time means the total time spent in the method, and all methods below it in the call stack. In other words, if method a calls b and c, the cumulative time for a is its self time, plus the cumulative time of b and c (which is the self time of each of those, plus the cumulative time of the methods they call, and so on). The number by the arrow from one node to another is the number of samples that saw the source node call the destination node. Looking at the numbers by the arrows into a node you can see roughly which method calls the method represented by that node the most. That's more or less it. I find the percentages most useful to work with, as the number of samples can vary a bit from time to time, its basically the same problem as using `time` to benchmark. Percentages are often much more stable. In the next section I'll explain how to act on the information that the graph gives. ## Optimizing The first thing to look at is the GC node. It will always be high (this is Ruby after all), but if it's above 20% this is what you should start with. The reason the GC takes so much time is because the code creates too many objects. It's not always obvious what is creating so many objects, but read the next section for how to remove the worst offenders. When you've picked the low hanging fruit and still have a high GC percentage, go over your code and try to see if there are places where you can memoize, cache, etc. If your objects are immutable you should never have to create two identical objects (on the other hand, it's easy to leak memory if you cache too much). The next thing to look at is the node with the highest self time percentage. This is your first hotspot. Apply all the tricks in the next section and see if it makes any difference. Sometimes hotspots are hotspots because of design rather than slow code. If a method is called many, many times you may not be able to optimize it further (but try, each tiny thing will make a huge difference). The third thing to look for are methods will high cumulative time. If the methods they call don't look too bad and can be optimized first, you may be able to rewrite the method to call them fewer times by caching values, for example. While optimizing run the profiler for each change to make sure you're going in the right direction. It's not uncommon for something that you think should be faster to be slower because of something you couldn't foresee or some unexpected side effect. When the method you're working on is no longer the worst offender, move on to the next, and iterate. ## Tips These are some general tips I've gathered while optimizing Ruby code: * Avoid string literals. In contrast to Java, strings in Ruby are mutable, so each literal string is a separate object (otherwise 'a'.upcase! would have very strange side effects). Move string literals to constants. * Avoid range literals. Just as with strings, ranges are objects and they are created every time they are encountered. Ranges are most often used to extract parts of a string, like `str[1..5]`. This can always be rewritten as a slice instead: `str[1, 4]` (the second argument is a length, not an index, so make sure you get the right value). Code like `data[offset..(offset + 4)]` is especially wasteful since it would be much clearer with the slice syntax: `data[offset, 5]`. * Avoid regular expressions. They are convenient, but for code that will be called thousands of times you need to rewrite them using String#index and String#slice/[]. Make sure that your rewrite doesn't create a lot of temporary string objects. * When reading files don't read line by line, and absolutely never byte by byte. It's much faster to read a big chunk (as in megabytes) and use String#split to split into lines. The same goes for writing. Buffer the lines and write them in one big chunk. Avoid IO#tell and #seek unless you're trying to read a few bytes out of a gigabyte file. * Never ever, ever, use Date or DateTime, or require 'date' (to get Time.parse, for example). Date is so slow that it's not even funny. If you use Date.parse you can be sure that whatever else you do that method will account for at least half of the running time. If you really, really need date parsing and date perform date calculations, use the home_run gem, but for almost everything you can use the basic methods on Time (but those aren't cheap either).amq-protocol-0.9.2/.travis.yml0000644000175000017500000000037611772516231015567 0ustar tfheentfheenlanguage: ruby bundler_args: --without development script: "bundle exec rspec spec" rvm: - 1.8.7 - rbx-18mode - rbx-19mode - 1.9.2 - 1.9.3 - ruby-head - jruby-19mode - jruby-head notifications: recipients: - michael@novemberain.com amq-protocol-0.9.2/.gitignore0000644000175000017500000000012411772516231015435 0ustar tfheentfheen/*.gem /.rvmrc tmp *.pyc /vendor/bundle /vendor/amq-* /coverage Gemfile.lock .rbx/* amq-protocol-0.9.2/protocol.rb.pytemplate0000644000175000017500000003024111772516231020021 0ustar tfheentfheen# encoding: utf-8 # encoding: binary # THIS IS AN AUTOGENERATED FILE, DO NOT MODIFY # IT DIRECTLY ! FOR CHANGES, PLEASE UPDATE CODEGEN.PY # IN THE ROOT DIRECTORY OF THE AMQ-PROTOCOL REPOSITORY.<% import codegen_helpers as helpers %><% import re, os, codegen %> require "amq/protocol/table" require "amq/protocol/frame" require "amq/hacks" module AMQ module Protocol PROTOCOL_VERSION = "${spec.major}.${spec.minor}.${spec.revision}".freeze PREAMBLE = "${'AMQP\\x00\\x%02x\\x%02x\\x%02x' % (spec.major, spec.minor, spec.revision)}".freeze DEFAULT_PORT = ${spec.port} # caching EMPTY_STRING = "".freeze PACK_CHAR = 'C'.freeze PACK_UINT16 = 'n'.freeze PACK_UINT16_X2 = 'n2'.freeze PACK_UINT32 = 'N'.freeze PACK_UINT32_X2 = 'N2'.freeze PACK_INT64 = 'q'.freeze PACK_UCHAR_UINT32 = 'CN'.freeze PACK_CHAR_UINT16_UINT32 = 'cnN'.freeze PACK_32BIT_FLOAT = 'f'.freeze PACK_64BIT_FLOAT = 'd'.freeze # @return [Array] Collection of subclasses of AMQ::Protocol::Class. def self.classes Protocol::Class.classes end # @return [Array] Collection of subclasses of AMQ::Protocol::Method. def self.methods Protocol::Method.methods end class Error < StandardError DEFAULT_MESSAGE = "AMQP error".freeze def self.inherited(subclass) @_subclasses ||= [] @_subclasses << subclass end # self.inherited(subclazz) def self.subclasses_with_values @_subclasses.select{ |k| defined?(k::VALUE) } end # self.subclasses_with_values def self.[](code) if result = subclasses_with_values.detect { |klass| klass::VALUE == code } result else raise "No such exception class for code #{code}" unless result end # if end # self.[] def initialize(message = self.class::DEFAULT_MESSAGE) super(message) end end class FrameTypeError < Protocol::Error def initialize(types) super("Must be one of #{types.inspect}") end end class EmptyResponseError < Protocol::Error DEFAULT_MESSAGE = "Empty response received from the server." def initialize(message = self.class::DEFAULT_MESSAGE) super(message) end end class BadResponseError < Protocol::Error def initialize(argument, expected, actual) super("Argument #{argument} has to be #{expected.inspect}, was #{data.inspect}") end end class SoftError < Protocol::Error def self.inherited(subclass) Error.inherited(subclass) end # self.inherited(subclass) end class HardError < Protocol::Error def self.inherited(subclass) Error.inherited(subclass) end # self.inherited(subclass) end % for tuple in spec.constants: % if tuple[2] == "soft-error" or tuple[2] == "hard-error": class ${codegen.to_ruby_class_name(tuple[0])} < ${codegen.to_ruby_class_name(tuple[2])} VALUE = ${tuple[1]} end % endif % endfor # We don't instantiate the following classes, # as we don't actually need any per-instance state. # Also, this is pretty low-level functionality, # hence it should have a reasonable performance. # As everyone knows, garbage collector in MRI performs # really badly, which is another good reason for # not creating any objects, but only use class as # a struct. Creating classes is quite expensive though, # but here the inheritance comes handy and mainly # as we can't simply make a reference to a function, # we can't use a hash or an object. I've been also # considering to have just a bunch of methods, but # here's the problem, that after we'd require this file, # all these methods would become global which would # be a bad, bad thing to do. class Class @classes = Array.new def self.method_id @method_id end def self.name @name end def self.inherited(base) if self == Protocol::Class @classes << base end end def self.classes @classes end end class Method @methods = Array.new def self.method_id @method_id end def self.name @name end def self.index @index end def self.inherited(base) if self == Protocol::Method @methods << base end end def self.methods @methods end def self.split_headers(user_headers) properties, headers = {}, {} user_headers.each do |key, value| # key MUST be a symbol since symbols are not garbage-collected if Basic::PROPERTIES.include?(key) properties[key] = value else headers[key] = value end end return [properties, headers] end def self.encode_body(body, channel, frame_size) return [] if body.empty? # See https://dev.rabbitmq.com/wiki/Amqp091Errata#section_11 limit = frame_size - 8 array = Array.new while body payload, body = body[0, limit], body[limit, body.length - limit] # array << [0x03, payload] array << BodyFrame.new(payload, channel) end array end # We can return different: # - instantiate given subclass of Method # - create an OpenStruct object # - create a hash # - yield params into the block rather than just return # @api plugin def self.instantiate(*args, &block) self.new(*args, &block) # or OpenStruct.new(args.first) # or args.first # or block.call(*args) end end % for klass in spec.classes : class ${klass.constant_name} < Protocol::Class @name = "${klass.name}" @method_id = ${klass.index} % if klass.fields: ## only the Basic class has fields (refered as properties in the JSON) PROPERTIES = [ % for field in klass.fields: :${field.ruby_name}, # ${spec.resolveDomain(field.domain)} % endfor ] % for f in klass.fields: # <% i = klass.fields.index(f) %>1 << ${15 - i} def self.encode_${f.ruby_name}(value) buffer = '' % for line in helpers.genSingleEncode(spec, "value", f.domain): ${line} % endfor [${i}, ${"0x%04x" % ( 1 << (15-i),)}, buffer] end % endfor % endif ## TODO: not only basic, resp. in fact it's only this class, but not necessarily in the future, rather check if properties are empty #} % if klass.name == "basic" : def self.encode_properties(body_size, properties) pieces, flags = [], 0 properties.each do |key, value| i, f, result = self.send(:"encode_#{key}", value) flags |= f pieces[i] = result end # result = [${klass.index}, 0, body_size, flags].pack('n2Qn') result = [${klass.index}, 0].pack(PACK_UINT16_X2) result += AMQ::Hacks.pack_64_big_endian(body_size) result += [flags].pack(PACK_UINT16) result + pieces.join(EMPTY_STRING) end # THIS DECODES ONLY FLAGS DECODE_PROPERTIES = { % for f in klass.fields: ${"0x%04x" % ( 1 << (15 - klass.fields.index(f)),)} => :${f.ruby_name}, % endfor } DECODE_PROPERTIES_TYPE = { % for f in klass.fields: ${"0x%04x" % ( 1 << (15 - klass.fields.index(f)),)} => :${spec.resolveDomain(f.domain)}, % endfor } # Hash doesn't give any guarantees on keys order, we will do it in a # straightforward way DECODE_PROPERTIES_KEYS = [ % for f in klass.fields: ${"0x%04x" % ( 1 << (15 - klass.fields.index(f)),)}, % endfor ] def self.decode_properties(data) offset, data_length, properties = 0, data.bytesize, {} compressed_index = data[offset, 2].unpack(PACK_UINT16)[0] offset += 2 while data_length > offset DECODE_PROPERTIES_KEYS.each do |key| next unless compressed_index >= key compressed_index -= key name = DECODE_PROPERTIES[key] || raise(RuntimeError.new("No property found for index #{index.inspect}!")) case DECODE_PROPERTIES_TYPE[key] when :shortstr size = data[offset, 1].unpack(PACK_CHAR)[0] offset += 1 result = data[offset, size] when :octet size = 1 result = data[offset, size].unpack(PACK_CHAR).first when :timestamp size = 8 result = Time.at(data[offset, size].unpack(PACK_UINT32_X2).last) when :table size = 4 + data[offset, 4].unpack(PACK_UINT32)[0] result = Table.decode(data[offset, size]) end properties[name] = result offset += size end end properties end % endif % for method in klass.methods: class ${method.constant_name} < Protocol::Method @name = "${klass.name}.${method.name}" @method_id = ${method.index} @index = ${method.binary()} @packed_indexes = [${klass.index}, ${method.index}].pack(PACK_UINT16_X2).freeze % if (spec.type == "client" and method.accepted_by("client")) or (spec.type == "server" and method.accepted_by("server") or spec.type == "all"): # @return def self.decode(data) offset = 0 % for line in helpers.genDecodeMethodDefinition(spec, method): ${line} % endfor % if (method.klass.name == "connection" or method.klass.name == "channel") and method.name == "close": self.new(${', '.join([f.ruby_name for f in method.arguments])}) % else: self.new(${', '.join([f.ruby_name for f in method.arguments])}) % endif end % if len(method.arguments) > 0: attr_reader ${', '.join([":" + f.ruby_name for f in method.arguments])} % endif def initialize(${', '.join([f.ruby_name for f in method.arguments])}) % for f in method.arguments: @${f.ruby_name} = ${f.ruby_name} % endfor end % endif def self.has_content? % if method.hasContent: true % else: false % endif end % if (spec.type == "client" and method.accepted_by("server")) or (spec.type == "server" and method.accepted_by("client")) or spec.type == "all": # @return # ${method.params()} % if klass.name == "connection": def self.encode(${(", ").join(method.not_ignored_args())}) % else: def self.encode(${(", ").join(["channel"] + method.not_ignored_args())}) % endif % for argument in method.ignored_args(): ${codegen.convert_to_ruby(argument)} % endfor % if klass.name == "connection": channel = 0 % endif buffer = '' buffer << @packed_indexes % for line in helpers.genEncodeMethodDefinition(spec, method): ${line} % endfor % if "payload" in method.args() or "user_headers" in method.args(): frames = [MethodFrame.new(buffer, channel)] % if "user_headers" in method.args(): properties, headers = self.split_headers(user_headers) # TODO: what shall I do with the headers? if properties.nil? or properties.empty? raise RuntimeError.new("Properties can not be empty!") # TODO: or can they? end properties_payload = Basic.encode_properties(payload.bytesize, properties) frames << HeaderFrame.new(properties_payload, channel) % endif % if "payload" in method.args(): frames + self.encode_body(payload, channel, frame_size) % endif % else: MethodFrame.new(buffer, channel) % endif end % endif end % endfor end % endfor METHODS = begin Method.methods.inject(Hash.new) do |hash, klass| hash.merge!(klass.index => klass) end end end end amq-protocol-0.9.2/amq-protocol.gemspec0000755000175000017500000000203411772516231017434 0ustar tfheentfheen#!/usr/bin/env gem build # encoding: utf-8 require "base64" require File.expand_path("../lib/amq/protocol/version", __FILE__) Gem::Specification.new do |s| s.name = "amq-protocol" s.version = AMQ::Protocol::VERSION s.authors = ["Jakub Stastny", "Michael S. Klishin", "Theo Hultberg", "Mark Abramov"] s.homepage = "http://github.com/ruby-amqp/amq-protocol" s.summary = "AMQP 0.9.1 encoder & decoder." s.description = <<-DESC amq-protocol is an AMQP 0.9.1 serialization library for Ruby. It is not an AMQP client: amq-protocol only handles serialization and deserialization. If you want to write your own AMQP client, this gem can help you with that. DESC s.email = ["bWljaGFlbEBub3ZlbWJlcmFpbi5jb20=\n", "c3Rhc3RueUAxMDFpZGVhcy5jeg==\n"].map { |i| Base64.decode64(i) } s.licenses = ["MIT"] # files s.files = `git ls-files`.split("\n").reject { |file| file =~ /^vendor\// } s.require_paths = ["lib"] s.extra_rdoc_files = ["README.md"] + Dir.glob("doc/*") # RubyForge s.rubyforge_project = "amq-protocol" end amq-protocol-0.9.2/irb.rb0000755000175000017500000000536611772516231014566 0ustar tfheentfheen#!/usr/bin/env bundle exec ruby # encoding: binary # This file is supposed to make inspecting AMQ protocol easier. # How does it work: # 1) This file is executed. # 2) We load irb, redefine where IRB looks for .irbrc and start IRB. # 3) IRB loads .irbrc, which we redefined, so it loads this file again. # However now the second branch of "if __FILE__ == $0" gets executed, # so it runs our custom code which loads the original .irbrc and then # it redefines some IRB settings. In this case it add IRB hook which # is executed after IRB is started. # Although it looks unnecessarily complicated, I can't see any easier # solution to this problem in case that you need to patch original settings. # Obviously in case you don't have the need, you'll be happy with simple: # require "irb" # # require_relative "lib/amq/protocol/client.rb" # include AMQ::Protocol # # IRB.start(__FILE__) require "irb" if __FILE__ == $0 puts "~ Using #{__FILE__} as an executable ..." def IRB.rc_file_generators yield Proc.new { |_| __FILE__ } end IRB.start(__FILE__) else begin irbrc = File.join(ENV["HOME"], ".irbrc") puts "~ Using #{__FILE__} as a custom .irbrc .." puts "~ Loading original #{irbrc} ..." load irbrc # TODO: Don't generate constants in all.rb multiple # times, then we can remove this craziness with $VERBOSE. old_verbose, $VERBOSE = $VERBOSE, nil begin require_relative "lib/amq/protocol/all.rb" rescue LoadError abort "File lib/amq/protocol/all.rb doesn't exist! You have to generate it using ./tasks.rb generate --targets=all, executed from the root of AMQ Protocol repository." end $VERBOSE = old_verbose include AMQ::Protocol begin require "amq/client/framing/string/frame" class AMQ::Protocol::Frame def self.decode(string) AMQ::Client::Framing::String::Frame.decode(string) end end rescue LoadError warn "~ AMQ Client isn't available." end # "0123456789".chunks(1, 1, 2, 3) # => ["0", "1", "23", "456"] class String def chunks(*parts) offset = 0 parts.map do |number_of_characters| self[offset..(offset + number_of_characters - 1)].tap do offset += number_of_characters end end << self[offset..-1] end end def fd(data) Frame.decode(data) end puts <<-EOF This is an AMQP #{AMQ::Protocol::PROTOCOL_VERSION} console. You can: - Decode data via: fd(frame_data). - Encode data using AMQP classes directly: frame = Connection::Open.encode("/") frame.encode EOF rescue Exception => exception # it just discards all the exceptions! abort exception.message + "\n - " + exception.backtrace.join("\n - ") end end amq-protocol-0.9.2/Gemfile0000644000175000017500000000032411772516231014742 0ustar tfheentfheen# encoding: utf-8 source :rubygems group :development do # excludes Windows, Rubinius and JRuby gem "perftools.rb", :platform => :mri_18 end group :test do gem "rspec", ">= 2.6.0" gem "effin_utf8" end amq-protocol-0.9.2/lib/0000755000175000017500000000000011772516231014216 5ustar tfheentfheenamq-protocol-0.9.2/lib/amq/0000755000175000017500000000000011772516231014774 5ustar tfheentfheenamq-protocol-0.9.2/lib/amq/protocol.rb0000644000175000017500000000012611772516231017161 0ustar tfheentfheen# -*- coding: utf-8 -*- require "amq/protocol/version" require "amq/protocol/client" amq-protocol-0.9.2/lib/amq/protocol/0000755000175000017500000000000011772516231016635 5ustar tfheentfheenamq-protocol-0.9.2/lib/amq/protocol/table_value_encoder.rb0000644000175000017500000000620011772516231023142 0ustar tfheentfheen# encoding: binary require "amq/protocol/client" require "amq/protocol/type_constants" require "amq/protocol/table" module AMQ module Protocol class TableValueEncoder # # Behaviors # include TypeConstants # # API # def self.encode(value) accumulator = String.new case value when String then accumulator << TYPE_STRING accumulator << [value.bytesize].pack(PACK_UINT32) accumulator << value when Symbol then v = value.to_s accumulator << TYPE_STRING accumulator << [v.bytesize].pack(PACK_UINT32) accumulator << v when Integer then accumulator << TYPE_INTEGER accumulator << [value].pack(PACK_UINT32) when Float then accumulator << TYPE_64BIT_FLOAT accumulator << [value].pack(PACK_64BIT_FLOAT) when true, false then accumulator << TYPE_BOOLEAN accumulator << (value ? BOOLEAN_TRUE : BOOLEAN_FALSE) when Time then accumulator << TYPE_TIME accumulator << [value.to_i].pack(PACK_INT64).reverse # FIXME: there has to be a more efficient way when nil then accumulator << TYPE_VOID when Array then accumulator << TYPE_ARRAY accumulator << [self.array_size(value)].pack(PACK_UINT32) value.each { |v| accumulator << self.encode(v) } when Hash then accumulator << TYPE_HASH accumulator << AMQ::Protocol::Table.encode(value) else # We don't want to require these libraries. if defined?(BigDecimal) && value.is_a?(BigDecimal) accumulator << TYPE_DECIMAL if value.exponent < 0 decimals = -value.exponent raw = (value * (decimals ** 10)).to_i accumulator << [decimals + 1, raw].pack(PACK_UCHAR_UINT32) # somewhat like floating point else # per spec, the "decimals" octet is unsigned (!) accumulator << [0, value.to_i].pack(PACK_UCHAR_UINT32) end else raise ArgumentError.new("Unsupported value #{value.inspect} of type #{value.class.name}") end # if end # case accumulator end # self.encode(value) def self.field_value_size(value) # the type tag takes 1 byte acc = 1 case value when String then acc += (value.bytesize + 4) when Integer then acc += 4 when Float then acc += 8 when Time, DateTime then acc += 8 when true, false then acc += 1 when nil then # nothing, type tag alone is enough when Hash then acc += (4 + Table.hash_size(value)) when Array then acc += (4 + self.array_size(value)) end acc end # self.field_value_size(value) def self.array_size(value) acc = 0 value.each { |v| acc += self.field_value_size(v) } acc end # self.array_size(value) end # TableValueEncoder end # Protocol end # AMQ amq-protocol-0.9.2/lib/amq/protocol/table_value_decoder.rb0000644000175000017500000001025411772516231023134 0ustar tfheentfheen# encoding: binary require "amq/protocol/client" require "amq/protocol/type_constants" require "amq/protocol/table" module AMQ module Protocol class TableValueDecoder # # Behaviors # include TypeConstants # # API # def self.decode_array(data, initial_offset) array_length = data.slice(initial_offset, 4).unpack(PACK_UINT32).first ary = Array.new offset = initial_offset + 4 while offset <= (initial_offset + array_length) type, offset = decode_value_type(data, offset) i = case type when TYPE_STRING v, offset = decode_string(data, offset) v when TYPE_INTEGER v, offset = decode_integer(data, offset) v when TYPE_DECIMAL v, offset = decode_big_decimal(data, offset) v when TYPE_TIME v, offset = decode_time(data, offset) v when TYPE_HASH v, offset = decode_hash(data, offset) v when TYPE_BOOLEAN v, offset = decode_boolean(data, offset) v when TYPE_SIGNED_8BIT then raise NotImplementedError.new when TYPE_SIGNED_16BIT then raise NotImplementedError.new when TYPE_SIGNED_64BIT then raise NotImplementedError.new when TYPE_32BIT_FLOAT then v, offset = decode_32bit_float(data, offset) v when TYPE_64BIT_FLOAT then v, offset = decode_64bit_float(data, offset) v when TYPE_VOID nil when TYPE_ARRAY v, offset = TableValueDecoder.decode_array(data, offset) v else raise ArgumentError.new("unsupported type: #{type.inspect}") end ary << i end [ary, initial_offset + array_length + 4] end # self.decode_array(data, initial_offset) def self.decode_string(data, offset) length = data.slice(offset, 4).unpack(PACK_UINT32).first offset += 4 v = data.slice(offset, length) offset += length [v, offset] end # self.decode_string(data, offset) def self.decode_integer(data, offset) v = data.slice(offset, 4).unpack(PACK_UINT32).first offset += 4 [v, offset] end # self.decode_integer(data, offset) def self.decode_big_decimal(data, offset) decimals, raw = data.slice(offset, 5).unpack(PACK_UCHAR_UINT32) offset += 5 v = BigDecimal.new(raw.to_s) * (BigDecimal.new(TEN) ** -decimals) [v, offset] end # self.decode_big_decimal(data, offset) def self.decode_time(data, offset) timestamp = data.slice(offset, 8).unpack(PACK_UINT32_X2).last v = Time.at(timestamp) offset += 8 [v, offset] end # self.decode_time(data, offset) def self.decode_boolean(data, offset) integer = data.slice(offset, 2).unpack(PACK_CHAR).first # 0 or 1 offset += 1 [(integer == 1), offset] end # self.decode_boolean(data, offset) def self.decode_32bit_float(data, offset) v = data.slice(offset, 4).unpack(PACK_32BIT_FLOAT).first offset += 4 [v, offset] end # self.decode_32bit_float(data, offset) def self.decode_64bit_float(data, offset) v = data.slice(offset, 8).unpack(PACK_64BIT_FLOAT).first offset += 8 [v, offset] end # self.decode_64bit_float(data, offset) def self.decode_value_type(data, offset) [data.slice(offset, 1), offset + 1] end # self.decode_value_type(data, offset) def self.decode_hash(data, offset) length = data.slice(offset, 4).unpack(PACK_UINT32).first v = Table.decode(data.slice(offset, length + 4)) offset += 4 + length [v, offset] end # self.decode_hash(data, offset) end # TableValueDecoder end # Protocol end # AMQ amq-protocol-0.9.2/lib/amq/protocol/frame.rb0000644000175000017500000001172611772516231020263 0ustar tfheentfheen# encoding: binary module AMQ module Protocol SIMPLE_BYTE_PACK = 'c*' class Frame TYPES = {:method => 1, :headers => 2, :body => 3, :heartbeat => 8}.freeze TYPES_REVERSE = TYPES.invert.freeze TYPES_OPTIONS = TYPES.keys.freeze CHANNEL_RANGE = (0..65535).freeze FINAL_OCTET = "\xCE".freeze # 206 # The channel number is 0 for all frames which are global to the connection and 1-65535 for frames that refer to specific channels. def self.encode(type, payload, channel) raise RuntimeError.new("Channel has to be 0 or an integer in range 1..65535 but was #{channel.inspect}") unless CHANNEL_RANGE.include?(channel) raise RuntimeError.new("Payload can't be nil") if payload.nil? [find_type(type), channel, payload.bytesize].pack(PACK_CHAR_UINT16_UINT32) + payload.bytes.to_a.pack(SIMPLE_BYTE_PACK) + FINAL_OCTET end class << self alias_method :__new__, :new unless method_defined?(:__new__) # because of reloading end def self.new(original_type, *args) type_id = find_type(original_type) klass = CLASSES[type_id] klass.new(*args) end def self.find_type(type) type_id = if Symbol === type then TYPES[type] else type end raise FrameTypeError.new(TYPES_OPTIONS) if type == nil || !TYPES_REVERSE.has_key?(type_id) type_id end def self.decode(*) raise NotImplementedError.new <<-EOF You are supposed to redefine this method, because it's dependent on used IO adapter. This functionality is part of the https://github.com/ruby-amqp/amq-client library. EOF end def self.decode_header(header) raise EmptyResponseError if header == nil type_id, channel, size = header.unpack(PACK_CHAR_UINT16_UINT32) type = TYPES_REVERSE[type_id] raise FrameTypeError.new(TYPES_OPTIONS) unless type [type, channel, size] end def final? true end end class FrameSubclass < Frame # Restore original new class << self alias_method :new, :__new__ undef_method :decode if method_defined?(:decode) end def self.id @id end def self.encode(payload, channel) super(@id, payload, channel) end attr_accessor :channel attr_reader :payload def initialize(payload, channel) @payload, @channel = payload, channel end def size @payload.bytesize end def encode [self.class.id, @channel, self.size].pack(PACK_CHAR_UINT16_UINT32) + @payload.bytes.to_a.pack(SIMPLE_BYTE_PACK) + FINAL_OCTET end end class MethodFrame < FrameSubclass @id = 1 def method_class @method_class ||= begin klass_id, method_id = self.payload.unpack(PACK_UINT16_X2) index = klass_id << 16 | method_id AMQ::Protocol::METHODS[index] end end def final? !self.method_class.has_content? end # final? def decode_payload self.method_class.decode(@payload[4..-1]) end end class HeaderFrame < FrameSubclass @id = 2 def final? false end def body_size decode_payload @body_size end def weight decode_payload @weight end def klass_id decode_payload @klass_id end def properties decode_payload @properties end def decode_payload @decoded_payload ||= begin @klass_id, @weight = @payload.unpack(PACK_UINT16_X2) # the total size of the content body, that is, the sum of the body sizes for the # following content body frames. Zero indicates that there are no content body frames. # So this is NOT related to this very header frame! @body_size = AMQ::Hacks.unpack_64_big_endian(@payload[4..11]).first @data = @payload[12..-1] @properties = Basic.decode_properties(@data) end end end class BodyFrame < FrameSubclass @id = 3 def decode_payload @payload end def final? # we cannot know whether it is final or not so framing code in amq-client # checks this over the entire frameset. MK. false end end class HeartbeatFrame < FrameSubclass @id = 8 def final? true end # final? def self.encode super(Protocol::EMPTY_STRING, 0) end end Frame::CLASSES = { Frame::TYPES[:method] => MethodFrame, Frame::TYPES[:headers] => HeaderFrame, Frame::TYPES[:body] => BodyFrame, Frame::TYPES[:heartbeat] => HeartbeatFrame } end end amq-protocol-0.9.2/lib/amq/protocol/version.rb0000644000175000017500000000011611772516231020645 0ustar tfheentfheenmodule AMQ module Protocol VERSION = "0.9.2" end # Protocol end # AMQ amq-protocol-0.9.2/lib/amq/protocol/client.rb0000644000175000017500000017373511772516231020460 0ustar tfheentfheen# encoding: binary # THIS IS AN AUTOGENERATED FILE, DO NOT MODIFY # IT DIRECTLY ! FOR CHANGES, PLEASE UPDATE CODEGEN.PY # IN THE ROOT DIRECTORY OF THE AMQ-PROTOCOL REPOSITORY. require "amq/protocol/table" require "amq/protocol/frame" require "amq/hacks" module AMQ module Protocol PROTOCOL_VERSION = "0.9.1".freeze PREAMBLE = "AMQP\x00\x00\x09\x01".freeze DEFAULT_PORT = 5672 # caching EMPTY_STRING = "".freeze PACK_CHAR = 'C'.freeze PACK_UINT16 = 'n'.freeze PACK_UINT16_X2 = 'n2'.freeze PACK_UINT32 = 'N'.freeze PACK_UINT32_X2 = 'N2'.freeze PACK_INT64 = 'q'.freeze PACK_UCHAR_UINT32 = 'CN'.freeze PACK_CHAR_UINT16_UINT32 = 'cnN'.freeze PACK_32BIT_FLOAT = 'f'.freeze PACK_64BIT_FLOAT = 'd'.freeze # @return [Array] Collection of subclasses of AMQ::Protocol::Class. def self.classes Protocol::Class.classes end # @return [Array] Collection of subclasses of AMQ::Protocol::Method. def self.methods Protocol::Method.methods end class Error < StandardError DEFAULT_MESSAGE = "AMQP error".freeze def self.inherited(subclass) @_subclasses ||= [] @_subclasses << subclass end # self.inherited(subclazz) def self.subclasses_with_values @_subclasses.select{ |k| defined?(k::VALUE) } end # self.subclasses_with_values def self.[](code) if result = subclasses_with_values.detect { |klass| klass::VALUE == code } result else raise "No such exception class for code #{code}" unless result end # if end # self.[] def initialize(message = self.class::DEFAULT_MESSAGE) super(message) end end class FrameTypeError < Protocol::Error def initialize(types) super("Must be one of #{types.inspect}") end end class EmptyResponseError < Protocol::Error DEFAULT_MESSAGE = "Empty response received from the server." def initialize(message = self.class::DEFAULT_MESSAGE) super(message) end end class BadResponseError < Protocol::Error def initialize(argument, expected, actual) super("Argument #{argument} has to be #{expected.inspect}, was #{data.inspect}") end end class SoftError < Protocol::Error def self.inherited(subclass) Error.inherited(subclass) end # self.inherited(subclass) end class HardError < Protocol::Error def self.inherited(subclass) Error.inherited(subclass) end # self.inherited(subclass) end class ContentTooLarge < SoftError VALUE = 311 end class NoRoute < SoftError VALUE = 312 end class NoConsumers < SoftError VALUE = 313 end class AccessRefused < SoftError VALUE = 403 end class NotFound < SoftError VALUE = 404 end class ResourceLocked < SoftError VALUE = 405 end class PreconditionFailed < SoftError VALUE = 406 end class ConnectionForced < HardError VALUE = 320 end class InvalidPath < HardError VALUE = 402 end class FrameError < HardError VALUE = 501 end class SyntaxError < HardError VALUE = 502 end class CommandInvalid < HardError VALUE = 503 end class ChannelError < HardError VALUE = 504 end class UnexpectedFrame < HardError VALUE = 505 end class ResourceError < HardError VALUE = 506 end class NotAllowed < HardError VALUE = 530 end class NotImplemented < HardError VALUE = 540 end class InternalError < HardError VALUE = 541 end # We don't instantiate the following classes, # as we don't actually need any per-instance state. # Also, this is pretty low-level functionality, # hence it should have a reasonable performance. # As everyone knows, garbage collector in MRI performs # really badly, which is another good reason for # not creating any objects, but only use class as # a struct. Creating classes is quite expensive though, # but here the inheritance comes handy and mainly # as we can't simply make a reference to a function, # we can't use a hash or an object. I've been also # considering to have just a bunch of methods, but # here's the problem, that after we'd require this file, # all these methods would become global which would # be a bad, bad thing to do. class Class @classes = Array.new def self.method_id @method_id end def self.name @name end def self.inherited(base) if self == Protocol::Class @classes << base end end def self.classes @classes end end class Method @methods = Array.new def self.method_id @method_id end def self.name @name end def self.index @index end def self.inherited(base) if self == Protocol::Method @methods << base end end def self.methods @methods end def self.split_headers(user_headers) properties, headers = {}, {} user_headers.each do |key, value| # key MUST be a symbol since symbols are not garbage-collected if Basic::PROPERTIES.include?(key) properties[key] = value else headers[key] = value end end return [properties, headers] end def self.encode_body(body, channel, frame_size) return [] if body.empty? # See https://dev.rabbitmq.com/wiki/Amqp091Errata#section_11 limit = frame_size - 8 array = Array.new while body payload, body = body[0, limit], body[limit, body.length - limit] # array << [0x03, payload] array << BodyFrame.new(payload, channel) end array end # We can return different: # - instantiate given subclass of Method # - create an OpenStruct object # - create a hash # - yield params into the block rather than just return # @api plugin def self.instantiate(*args, &block) self.new(*args, &block) # or OpenStruct.new(args.first) # or args.first # or block.call(*args) end end class Connection < Protocol::Class @name = "connection" @method_id = 10 class Start < Protocol::Method @name = "connection.start" @method_id = 10 @index = 0x000A000A # 10, 10, 655370 @packed_indexes = [10, 10].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 version_major = data[offset, 1].unpack(PACK_CHAR).first offset += 1 version_minor = data[offset, 1].unpack(PACK_CHAR).first offset += 1 table_length = Table.length(data[offset, 4]) server_properties = Table.decode(data[offset, table_length + 4]) offset += table_length + 4 length = data[offset, 4].unpack(PACK_UINT32).first offset += 4 mechanisms = data[offset, length] offset += length length = data[offset, 4].unpack(PACK_UINT32).first offset += 4 locales = data[offset, length] offset += length self.new(version_major, version_minor, server_properties, mechanisms, locales) end attr_reader :version_major, :version_minor, :server_properties, :mechanisms, :locales def initialize(version_major, version_minor, server_properties, mechanisms, locales) @version_major = version_major @version_minor = version_minor @server_properties = server_properties @mechanisms = mechanisms @locales = locales end def self.has_content? false end end class StartOk < Protocol::Method @name = "connection.start-ok" @method_id = 11 @index = 0x000A000B # 10, 11, 655371 @packed_indexes = [10, 11].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'client_properties = nil', u"mechanism = u'PLAIN'", u'response = nil', u"locale = u'en_US'"] def self.encode(client_properties, mechanism, response, locale) channel = 0 buffer = '' buffer << @packed_indexes buffer << AMQ::Protocol::Table.encode(client_properties) buffer << mechanism.bytesize.chr buffer << mechanism buffer << [response.bytesize].pack(PACK_UINT32) buffer << response buffer << locale.bytesize.chr buffer << locale MethodFrame.new(buffer, channel) end end class Secure < Protocol::Method @name = "connection.secure" @method_id = 20 @index = 0x000A0014 # 10, 20, 655380 @packed_indexes = [10, 20].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 4].unpack(PACK_UINT32).first offset += 4 challenge = data[offset, length] offset += length self.new(challenge) end attr_reader :challenge def initialize(challenge) @challenge = challenge end def self.has_content? false end end class SecureOk < Protocol::Method @name = "connection.secure-ok" @method_id = 21 @index = 0x000A0015 # 10, 21, 655381 @packed_indexes = [10, 21].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'response = nil'] def self.encode(response) channel = 0 buffer = '' buffer << @packed_indexes buffer << [response.bytesize].pack(PACK_UINT32) buffer << response MethodFrame.new(buffer, channel) end end class Tune < Protocol::Method @name = "connection.tune" @method_id = 30 @index = 0x000A001E # 10, 30, 655390 @packed_indexes = [10, 30].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 channel_max = data[offset, 2].unpack(PACK_UINT16).first offset += 2 frame_max = data[offset, 4].unpack(PACK_UINT32).first offset += 4 heartbeat = data[offset, 2].unpack(PACK_UINT16).first offset += 2 self.new(channel_max, frame_max, heartbeat) end attr_reader :channel_max, :frame_max, :heartbeat def initialize(channel_max, frame_max, heartbeat) @channel_max = channel_max @frame_max = frame_max @heartbeat = heartbeat end def self.has_content? false end end class TuneOk < Protocol::Method @name = "connection.tune-ok" @method_id = 31 @index = 0x000A001F # 10, 31, 655391 @packed_indexes = [10, 31].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'channel_max = false', u'frame_max = false', u'heartbeat = false'] def self.encode(channel_max, frame_max, heartbeat) channel = 0 buffer = '' buffer << @packed_indexes buffer << [channel_max].pack(PACK_UINT16) buffer << [frame_max].pack(PACK_UINT32) buffer << [heartbeat].pack(PACK_UINT16) MethodFrame.new(buffer, channel) end end class Open < Protocol::Method @name = "connection.open" @method_id = 40 @index = 0x000A0028 # 10, 40, 655400 @packed_indexes = [10, 40].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u"virtual_host = u'/'", u'capabilities = EMPTY_STRING', u'insist = false'] def self.encode(virtual_host) capabilities = EMPTY_STRING insist = false channel = 0 buffer = '' buffer << @packed_indexes buffer << virtual_host.bytesize.chr buffer << virtual_host buffer << capabilities.bytesize.chr buffer << capabilities bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if insist buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class OpenOk < Protocol::Method @name = "connection.open-ok" @method_id = 41 @index = 0x000A0029 # 10, 41, 655401 @packed_indexes = [10, 41].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 known_hosts = data[offset, length] offset += length self.new(known_hosts) end attr_reader :known_hosts def initialize(known_hosts) @known_hosts = known_hosts end def self.has_content? false end end class Close < Protocol::Method @name = "connection.close" @method_id = 50 @index = 0x000A0032 # 10, 50, 655410 @packed_indexes = [10, 50].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 reply_code = data[offset, 2].unpack(PACK_UINT16).first offset += 2 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 reply_text = data[offset, length] offset += length class_id = data[offset, 2].unpack(PACK_UINT16).first offset += 2 method_id = data[offset, 2].unpack(PACK_UINT16).first offset += 2 self.new(reply_code, reply_text, class_id, method_id) end attr_reader :reply_code, :reply_text, :class_id, :method_id def initialize(reply_code, reply_text, class_id, method_id) @reply_code = reply_code @reply_text = reply_text @class_id = class_id @method_id = method_id end def self.has_content? false end # @return # [u'reply_code = nil', u'reply_text = EMPTY_STRING', u'class_id = nil', u'method_id = nil'] def self.encode(reply_code, reply_text, class_id, method_id) channel = 0 buffer = '' buffer << @packed_indexes buffer << [reply_code].pack(PACK_UINT16) buffer << reply_text.bytesize.chr buffer << reply_text buffer << [class_id].pack(PACK_UINT16) buffer << [method_id].pack(PACK_UINT16) MethodFrame.new(buffer, channel) end end class CloseOk < Protocol::Method @name = "connection.close-ok" @method_id = 51 @index = 0x000A0033 # 10, 51, 655411 @packed_indexes = [10, 51].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end # @return # [] def self.encode() channel = 0 buffer = '' buffer << @packed_indexes MethodFrame.new(buffer, channel) end end end class Channel < Protocol::Class @name = "channel" @method_id = 20 class Open < Protocol::Method @name = "channel.open" @method_id = 10 @index = 0x0014000A # 20, 10, 1310730 @packed_indexes = [20, 10].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'out_of_band = EMPTY_STRING'] def self.encode(channel, out_of_band) buffer = '' buffer << @packed_indexes buffer << out_of_band.bytesize.chr buffer << out_of_band MethodFrame.new(buffer, channel) end end class OpenOk < Protocol::Method @name = "channel.open-ok" @method_id = 11 @index = 0x0014000B # 20, 11, 1310731 @packed_indexes = [20, 11].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 4].unpack(PACK_UINT32).first offset += 4 channel_id = data[offset, length] offset += length self.new(channel_id) end attr_reader :channel_id def initialize(channel_id) @channel_id = channel_id end def self.has_content? false end end class Flow < Protocol::Method @name = "channel.flow" @method_id = 20 @index = 0x00140014 # 20, 20, 1310740 @packed_indexes = [20, 20].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 bit_buffer = data[offset, 1].unpack(PACK_CHAR).first offset += 1 active = (bit_buffer & (1 << 0)) != 0 self.new(active) end attr_reader :active def initialize(active) @active = active end def self.has_content? false end # @return # [u'active = nil'] def self.encode(channel, active) buffer = '' buffer << @packed_indexes bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if active buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class FlowOk < Protocol::Method @name = "channel.flow-ok" @method_id = 21 @index = 0x00140015 # 20, 21, 1310741 @packed_indexes = [20, 21].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 bit_buffer = data[offset, 1].unpack(PACK_CHAR).first offset += 1 active = (bit_buffer & (1 << 0)) != 0 self.new(active) end attr_reader :active def initialize(active) @active = active end def self.has_content? false end # @return # [u'active = nil'] def self.encode(channel, active) buffer = '' buffer << @packed_indexes bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if active buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class Close < Protocol::Method @name = "channel.close" @method_id = 40 @index = 0x00140028 # 20, 40, 1310760 @packed_indexes = [20, 40].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 reply_code = data[offset, 2].unpack(PACK_UINT16).first offset += 2 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 reply_text = data[offset, length] offset += length class_id = data[offset, 2].unpack(PACK_UINT16).first offset += 2 method_id = data[offset, 2].unpack(PACK_UINT16).first offset += 2 self.new(reply_code, reply_text, class_id, method_id) end attr_reader :reply_code, :reply_text, :class_id, :method_id def initialize(reply_code, reply_text, class_id, method_id) @reply_code = reply_code @reply_text = reply_text @class_id = class_id @method_id = method_id end def self.has_content? false end # @return # [u'reply_code = nil', u'reply_text = EMPTY_STRING', u'class_id = nil', u'method_id = nil'] def self.encode(channel, reply_code, reply_text, class_id, method_id) buffer = '' buffer << @packed_indexes buffer << [reply_code].pack(PACK_UINT16) buffer << reply_text.bytesize.chr buffer << reply_text buffer << [class_id].pack(PACK_UINT16) buffer << [method_id].pack(PACK_UINT16) MethodFrame.new(buffer, channel) end end class CloseOk < Protocol::Method @name = "channel.close-ok" @method_id = 41 @index = 0x00140029 # 20, 41, 1310761 @packed_indexes = [20, 41].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end # @return # [] def self.encode(channel) buffer = '' buffer << @packed_indexes MethodFrame.new(buffer, channel) end end end class Exchange < Protocol::Class @name = "exchange" @method_id = 40 class Declare < Protocol::Method @name = "exchange.declare" @method_id = 10 @index = 0x0028000A # 40, 10, 2621450 @packed_indexes = [40, 10].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'exchange = nil', u"type = u'direct'", u'passive = false', u'durable = false', u'auto_delete = false', u'internal = false', u'nowait = false', u'arguments = {}'] def self.encode(channel, exchange, type, passive, durable, auto_delete, internal, nowait, arguments) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << exchange.bytesize.chr buffer << exchange buffer << type.bytesize.chr buffer << type bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if passive bit_buffer = bit_buffer | (1 << 1) if durable bit_buffer = bit_buffer | (1 << 2) if auto_delete bit_buffer = bit_buffer | (1 << 3) if internal bit_buffer = bit_buffer | (1 << 4) if nowait buffer << [bit_buffer].pack(PACK_CHAR) buffer << AMQ::Protocol::Table.encode(arguments) MethodFrame.new(buffer, channel) end end class DeclareOk < Protocol::Method @name = "exchange.declare-ok" @method_id = 11 @index = 0x0028000B # 40, 11, 2621451 @packed_indexes = [40, 11].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end class Delete < Protocol::Method @name = "exchange.delete" @method_id = 20 @index = 0x00280014 # 40, 20, 2621460 @packed_indexes = [40, 20].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'exchange = nil', u'if_unused = false', u'nowait = false'] def self.encode(channel, exchange, if_unused, nowait) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << exchange.bytesize.chr buffer << exchange bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if if_unused bit_buffer = bit_buffer | (1 << 1) if nowait buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class DeleteOk < Protocol::Method @name = "exchange.delete-ok" @method_id = 21 @index = 0x00280015 # 40, 21, 2621461 @packed_indexes = [40, 21].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end class Bind < Protocol::Method @name = "exchange.bind" @method_id = 30 @index = 0x0028001E # 40, 30, 2621470 @packed_indexes = [40, 30].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'destination = nil', u'source = nil', u'routing_key = EMPTY_STRING', u'nowait = false', u'arguments = {}'] def self.encode(channel, destination, source, routing_key, nowait, arguments) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << destination.bytesize.chr buffer << destination buffer << source.bytesize.chr buffer << source buffer << routing_key.bytesize.chr buffer << routing_key bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if nowait buffer << [bit_buffer].pack(PACK_CHAR) buffer << AMQ::Protocol::Table.encode(arguments) MethodFrame.new(buffer, channel) end end class BindOk < Protocol::Method @name = "exchange.bind-ok" @method_id = 31 @index = 0x0028001F # 40, 31, 2621471 @packed_indexes = [40, 31].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end class Unbind < Protocol::Method @name = "exchange.unbind" @method_id = 40 @index = 0x00280028 # 40, 40, 2621480 @packed_indexes = [40, 40].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'destination = nil', u'source = nil', u'routing_key = EMPTY_STRING', u'nowait = false', u'arguments = {}'] def self.encode(channel, destination, source, routing_key, nowait, arguments) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << destination.bytesize.chr buffer << destination buffer << source.bytesize.chr buffer << source buffer << routing_key.bytesize.chr buffer << routing_key bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if nowait buffer << [bit_buffer].pack(PACK_CHAR) buffer << AMQ::Protocol::Table.encode(arguments) MethodFrame.new(buffer, channel) end end class UnbindOk < Protocol::Method @name = "exchange.unbind-ok" @method_id = 51 @index = 0x00280033 # 40, 51, 2621491 @packed_indexes = [40, 51].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end end class Queue < Protocol::Class @name = "queue" @method_id = 50 class Declare < Protocol::Method @name = "queue.declare" @method_id = 10 @index = 0x0032000A # 50, 10, 3276810 @packed_indexes = [50, 10].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'queue = EMPTY_STRING', u'passive = false', u'durable = false', u'exclusive = false', u'auto_delete = false', u'nowait = false', u'arguments = {}'] def self.encode(channel, queue, passive, durable, exclusive, auto_delete, nowait, arguments) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << queue.bytesize.chr buffer << queue bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if passive bit_buffer = bit_buffer | (1 << 1) if durable bit_buffer = bit_buffer | (1 << 2) if exclusive bit_buffer = bit_buffer | (1 << 3) if auto_delete bit_buffer = bit_buffer | (1 << 4) if nowait buffer << [bit_buffer].pack(PACK_CHAR) buffer << AMQ::Protocol::Table.encode(arguments) MethodFrame.new(buffer, channel) end end class DeclareOk < Protocol::Method @name = "queue.declare-ok" @method_id = 11 @index = 0x0032000B # 50, 11, 3276811 @packed_indexes = [50, 11].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 queue = data[offset, length] offset += length message_count = data[offset, 4].unpack(PACK_UINT32).first offset += 4 consumer_count = data[offset, 4].unpack(PACK_UINT32).first offset += 4 self.new(queue, message_count, consumer_count) end attr_reader :queue, :message_count, :consumer_count def initialize(queue, message_count, consumer_count) @queue = queue @message_count = message_count @consumer_count = consumer_count end def self.has_content? false end end class Bind < Protocol::Method @name = "queue.bind" @method_id = 20 @index = 0x00320014 # 50, 20, 3276820 @packed_indexes = [50, 20].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'queue = EMPTY_STRING', u'exchange = nil', u'routing_key = EMPTY_STRING', u'nowait = false', u'arguments = {}'] def self.encode(channel, queue, exchange, routing_key, nowait, arguments) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << queue.bytesize.chr buffer << queue buffer << exchange.bytesize.chr buffer << exchange buffer << routing_key.bytesize.chr buffer << routing_key bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if nowait buffer << [bit_buffer].pack(PACK_CHAR) buffer << AMQ::Protocol::Table.encode(arguments) MethodFrame.new(buffer, channel) end end class BindOk < Protocol::Method @name = "queue.bind-ok" @method_id = 21 @index = 0x00320015 # 50, 21, 3276821 @packed_indexes = [50, 21].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end class Purge < Protocol::Method @name = "queue.purge" @method_id = 30 @index = 0x0032001E # 50, 30, 3276830 @packed_indexes = [50, 30].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'queue = EMPTY_STRING', u'nowait = false'] def self.encode(channel, queue, nowait) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << queue.bytesize.chr buffer << queue bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if nowait buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class PurgeOk < Protocol::Method @name = "queue.purge-ok" @method_id = 31 @index = 0x0032001F # 50, 31, 3276831 @packed_indexes = [50, 31].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 message_count = data[offset, 4].unpack(PACK_UINT32).first offset += 4 self.new(message_count) end attr_reader :message_count def initialize(message_count) @message_count = message_count end def self.has_content? false end end class Delete < Protocol::Method @name = "queue.delete" @method_id = 40 @index = 0x00320028 # 50, 40, 3276840 @packed_indexes = [50, 40].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'queue = EMPTY_STRING', u'if_unused = false', u'if_empty = false', u'nowait = false'] def self.encode(channel, queue, if_unused, if_empty, nowait) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << queue.bytesize.chr buffer << queue bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if if_unused bit_buffer = bit_buffer | (1 << 1) if if_empty bit_buffer = bit_buffer | (1 << 2) if nowait buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class DeleteOk < Protocol::Method @name = "queue.delete-ok" @method_id = 41 @index = 0x00320029 # 50, 41, 3276841 @packed_indexes = [50, 41].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 message_count = data[offset, 4].unpack(PACK_UINT32).first offset += 4 self.new(message_count) end attr_reader :message_count def initialize(message_count) @message_count = message_count end def self.has_content? false end end class Unbind < Protocol::Method @name = "queue.unbind" @method_id = 50 @index = 0x00320032 # 50, 50, 3276850 @packed_indexes = [50, 50].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'queue = EMPTY_STRING', u'exchange = nil', u'routing_key = EMPTY_STRING', u'arguments = {}'] def self.encode(channel, queue, exchange, routing_key, arguments) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << queue.bytesize.chr buffer << queue buffer << exchange.bytesize.chr buffer << exchange buffer << routing_key.bytesize.chr buffer << routing_key buffer << AMQ::Protocol::Table.encode(arguments) MethodFrame.new(buffer, channel) end end class UnbindOk < Protocol::Method @name = "queue.unbind-ok" @method_id = 51 @index = 0x00320033 # 50, 51, 3276851 @packed_indexes = [50, 51].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end end class Basic < Protocol::Class @name = "basic" @method_id = 60 PROPERTIES = [ :content_type, # shortstr :content_encoding, # shortstr :headers, # table :delivery_mode, # octet :priority, # octet :correlation_id, # shortstr :reply_to, # shortstr :expiration, # shortstr :message_id, # shortstr :timestamp, # timestamp :type, # shortstr :user_id, # shortstr :app_id, # shortstr :cluster_id, # shortstr ] # 1 << 15 def self.encode_content_type(value) buffer = '' buffer << value.bytesize.chr buffer << value [0, 0x8000, buffer] end # 1 << 14 def self.encode_content_encoding(value) buffer = '' buffer << value.bytesize.chr buffer << value [1, 0x4000, buffer] end # 1 << 13 def self.encode_headers(value) buffer = '' buffer << AMQ::Protocol::Table.encode(value) [2, 0x2000, buffer] end # 1 << 12 def self.encode_delivery_mode(value) buffer = '' buffer << [value].pack(PACK_CHAR) [3, 0x1000, buffer] end # 1 << 11 def self.encode_priority(value) buffer = '' buffer << [value].pack(PACK_CHAR) [4, 0x0800, buffer] end # 1 << 10 def self.encode_correlation_id(value) buffer = '' buffer << value.bytesize.chr buffer << value [5, 0x0400, buffer] end # 1 << 9 def self.encode_reply_to(value) buffer = '' buffer << value.bytesize.chr buffer << value [6, 0x0200, buffer] end # 1 << 8 def self.encode_expiration(value) buffer = '' buffer << value.bytesize.chr buffer << value [7, 0x0100, buffer] end # 1 << 7 def self.encode_message_id(value) buffer = '' buffer << value.bytesize.chr buffer << value [8, 0x0080, buffer] end # 1 << 6 def self.encode_timestamp(value) buffer = '' buffer << AMQ::Hacks.pack_64_big_endian(value) [9, 0x0040, buffer] end # 1 << 5 def self.encode_type(value) buffer = '' buffer << value.bytesize.chr buffer << value [10, 0x0020, buffer] end # 1 << 4 def self.encode_user_id(value) buffer = '' buffer << value.bytesize.chr buffer << value [11, 0x0010, buffer] end # 1 << 3 def self.encode_app_id(value) buffer = '' buffer << value.bytesize.chr buffer << value [12, 0x0008, buffer] end # 1 << 2 def self.encode_cluster_id(value) buffer = '' buffer << value.bytesize.chr buffer << value [13, 0x0004, buffer] end def self.encode_properties(body_size, properties) pieces, flags = [], 0 properties.each do |key, value| i, f, result = self.send(:"encode_#{key}", value) flags |= f pieces[i] = result end # result = [60, 0, body_size, flags].pack('n2Qn') result = [60, 0].pack(PACK_UINT16_X2) result += AMQ::Hacks.pack_64_big_endian(body_size) result += [flags].pack(PACK_UINT16) result + pieces.join(EMPTY_STRING) end # THIS DECODES ONLY FLAGS DECODE_PROPERTIES = { 0x8000 => :content_type, 0x4000 => :content_encoding, 0x2000 => :headers, 0x1000 => :delivery_mode, 0x0800 => :priority, 0x0400 => :correlation_id, 0x0200 => :reply_to, 0x0100 => :expiration, 0x0080 => :message_id, 0x0040 => :timestamp, 0x0020 => :type, 0x0010 => :user_id, 0x0008 => :app_id, 0x0004 => :cluster_id, } DECODE_PROPERTIES_TYPE = { 0x8000 => :shortstr, 0x4000 => :shortstr, 0x2000 => :table, 0x1000 => :octet, 0x0800 => :octet, 0x0400 => :shortstr, 0x0200 => :shortstr, 0x0100 => :shortstr, 0x0080 => :shortstr, 0x0040 => :timestamp, 0x0020 => :shortstr, 0x0010 => :shortstr, 0x0008 => :shortstr, 0x0004 => :shortstr, } # Hash doesn't give any guarantees on keys order, we will do it in a # straightforward way DECODE_PROPERTIES_KEYS = [ 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100, 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, ] def self.decode_properties(data) offset, data_length, properties = 0, data.bytesize, {} compressed_index = data[offset, 2].unpack(PACK_UINT16)[0] offset += 2 while data_length > offset DECODE_PROPERTIES_KEYS.each do |key| next unless compressed_index >= key compressed_index -= key name = DECODE_PROPERTIES[key] || raise(RuntimeError.new("No property found for index #{index.inspect}!")) case DECODE_PROPERTIES_TYPE[key] when :shortstr size = data[offset, 1].unpack(PACK_CHAR)[0] offset += 1 result = data[offset, size] when :octet size = 1 result = data[offset, size].unpack(PACK_CHAR).first when :timestamp size = 8 result = Time.at(data[offset, size].unpack(PACK_UINT32_X2).last) when :table size = 4 + data[offset, 4].unpack(PACK_UINT32)[0] result = Table.decode(data[offset, size]) end properties[name] = result offset += size end end properties end class Qos < Protocol::Method @name = "basic.qos" @method_id = 10 @index = 0x003C000A # 60, 10, 3932170 @packed_indexes = [60, 10].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'prefetch_size = false', u'prefetch_count = false', u'global = false'] def self.encode(channel, prefetch_size, prefetch_count, global) buffer = '' buffer << @packed_indexes buffer << [prefetch_size].pack(PACK_UINT32) buffer << [prefetch_count].pack(PACK_UINT16) bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if global buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class QosOk < Protocol::Method @name = "basic.qos-ok" @method_id = 11 @index = 0x003C000B # 60, 11, 3932171 @packed_indexes = [60, 11].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end class Consume < Protocol::Method @name = "basic.consume" @method_id = 20 @index = 0x003C0014 # 60, 20, 3932180 @packed_indexes = [60, 20].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'queue = EMPTY_STRING', u'consumer_tag = EMPTY_STRING', u'no_local = false', u'no_ack = false', u'exclusive = false', u'nowait = false', u'arguments = {}'] def self.encode(channel, queue, consumer_tag, no_local, no_ack, exclusive, nowait, arguments) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << queue.bytesize.chr buffer << queue buffer << consumer_tag.bytesize.chr buffer << consumer_tag bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if no_local bit_buffer = bit_buffer | (1 << 1) if no_ack bit_buffer = bit_buffer | (1 << 2) if exclusive bit_buffer = bit_buffer | (1 << 3) if nowait buffer << [bit_buffer].pack(PACK_CHAR) buffer << AMQ::Protocol::Table.encode(arguments) MethodFrame.new(buffer, channel) end end class ConsumeOk < Protocol::Method @name = "basic.consume-ok" @method_id = 21 @index = 0x003C0015 # 60, 21, 3932181 @packed_indexes = [60, 21].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 consumer_tag = data[offset, length] offset += length self.new(consumer_tag) end attr_reader :consumer_tag def initialize(consumer_tag) @consumer_tag = consumer_tag end def self.has_content? false end end class Cancel < Protocol::Method @name = "basic.cancel" @method_id = 30 @index = 0x003C001E # 60, 30, 3932190 @packed_indexes = [60, 30].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 consumer_tag = data[offset, length] offset += length bit_buffer = data[offset, 1].unpack(PACK_CHAR).first offset += 1 nowait = (bit_buffer & (1 << 0)) != 0 self.new(consumer_tag, nowait) end attr_reader :consumer_tag, :nowait def initialize(consumer_tag, nowait) @consumer_tag = consumer_tag @nowait = nowait end def self.has_content? false end # @return # [u'consumer_tag = nil', u'nowait = false'] def self.encode(channel, consumer_tag, nowait) buffer = '' buffer << @packed_indexes buffer << consumer_tag.bytesize.chr buffer << consumer_tag bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if nowait buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class CancelOk < Protocol::Method @name = "basic.cancel-ok" @method_id = 31 @index = 0x003C001F # 60, 31, 3932191 @packed_indexes = [60, 31].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 consumer_tag = data[offset, length] offset += length self.new(consumer_tag) end attr_reader :consumer_tag def initialize(consumer_tag) @consumer_tag = consumer_tag end def self.has_content? false end end class Publish < Protocol::Method @name = "basic.publish" @method_id = 40 @index = 0x003C0028 # 60, 40, 3932200 @packed_indexes = [60, 40].pack(PACK_UINT16_X2).freeze def self.has_content? true end # @return # [u'ticket = 0', u'exchange = EMPTY_STRING', u'routing_key = EMPTY_STRING', u'mandatory = false', u'immediate = false', 'user_headers = nil', 'payload = ""', 'frame_size = nil'] def self.encode(channel, payload, user_headers, exchange, routing_key, mandatory, immediate, frame_size) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << exchange.bytesize.chr buffer << exchange buffer << routing_key.bytesize.chr buffer << routing_key bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if mandatory bit_buffer = bit_buffer | (1 << 1) if immediate buffer << [bit_buffer].pack(PACK_CHAR) frames = [MethodFrame.new(buffer, channel)] properties, headers = self.split_headers(user_headers) # TODO: what shall I do with the headers? if properties.nil? or properties.empty? raise RuntimeError.new("Properties can not be empty!") # TODO: or can they? end properties_payload = Basic.encode_properties(payload.bytesize, properties) frames << HeaderFrame.new(properties_payload, channel) frames + self.encode_body(payload, channel, frame_size) end end class Return < Protocol::Method @name = "basic.return" @method_id = 50 @index = 0x003C0032 # 60, 50, 3932210 @packed_indexes = [60, 50].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 reply_code = data[offset, 2].unpack(PACK_UINT16).first offset += 2 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 reply_text = data[offset, length] offset += length length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 exchange = data[offset, length] offset += length length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 routing_key = data[offset, length] offset += length self.new(reply_code, reply_text, exchange, routing_key) end attr_reader :reply_code, :reply_text, :exchange, :routing_key def initialize(reply_code, reply_text, exchange, routing_key) @reply_code = reply_code @reply_text = reply_text @exchange = exchange @routing_key = routing_key end def self.has_content? true end end class Deliver < Protocol::Method @name = "basic.deliver" @method_id = 60 @index = 0x003C003C # 60, 60, 3932220 @packed_indexes = [60, 60].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 consumer_tag = data[offset, length] offset += length delivery_tag = AMQ::Hacks.unpack_64_big_endian(data[offset, 8]).first offset += 8 bit_buffer = data[offset, 1].unpack(PACK_CHAR).first offset += 1 redelivered = (bit_buffer & (1 << 0)) != 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 exchange = data[offset, length] offset += length length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 routing_key = data[offset, length] offset += length self.new(consumer_tag, delivery_tag, redelivered, exchange, routing_key) end attr_reader :consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key def initialize(consumer_tag, delivery_tag, redelivered, exchange, routing_key) @consumer_tag = consumer_tag @delivery_tag = delivery_tag @redelivered = redelivered @exchange = exchange @routing_key = routing_key end def self.has_content? true end end class Get < Protocol::Method @name = "basic.get" @method_id = 70 @index = 0x003C0046 # 60, 70, 3932230 @packed_indexes = [60, 70].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'ticket = 0', u'queue = EMPTY_STRING', u'no_ack = false'] def self.encode(channel, queue, no_ack) ticket = 0 buffer = '' buffer << @packed_indexes buffer << [ticket].pack(PACK_UINT16) buffer << queue.bytesize.chr buffer << queue bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if no_ack buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class GetOk < Protocol::Method @name = "basic.get-ok" @method_id = 71 @index = 0x003C0047 # 60, 71, 3932231 @packed_indexes = [60, 71].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 delivery_tag = AMQ::Hacks.unpack_64_big_endian(data[offset, 8]).first offset += 8 bit_buffer = data[offset, 1].unpack(PACK_CHAR).first offset += 1 redelivered = (bit_buffer & (1 << 0)) != 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 exchange = data[offset, length] offset += length length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 routing_key = data[offset, length] offset += length message_count = data[offset, 4].unpack(PACK_UINT32).first offset += 4 self.new(delivery_tag, redelivered, exchange, routing_key, message_count) end attr_reader :delivery_tag, :redelivered, :exchange, :routing_key, :message_count def initialize(delivery_tag, redelivered, exchange, routing_key, message_count) @delivery_tag = delivery_tag @redelivered = redelivered @exchange = exchange @routing_key = routing_key @message_count = message_count end def self.has_content? true end end class GetEmpty < Protocol::Method @name = "basic.get-empty" @method_id = 72 @index = 0x003C0048 # 60, 72, 3932232 @packed_indexes = [60, 72].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 cluster_id = data[offset, length] offset += length self.new(cluster_id) end attr_reader :cluster_id def initialize(cluster_id) @cluster_id = cluster_id end def self.has_content? false end end class Ack < Protocol::Method @name = "basic.ack" @method_id = 80 @index = 0x003C0050 # 60, 80, 3932240 @packed_indexes = [60, 80].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 delivery_tag = AMQ::Hacks.unpack_64_big_endian(data[offset, 8]).first offset += 8 bit_buffer = data[offset, 1].unpack(PACK_CHAR).first offset += 1 multiple = (bit_buffer & (1 << 0)) != 0 self.new(delivery_tag, multiple) end attr_reader :delivery_tag, :multiple def initialize(delivery_tag, multiple) @delivery_tag = delivery_tag @multiple = multiple end def self.has_content? false end # @return # [u'delivery_tag = false', u'multiple = false'] def self.encode(channel, delivery_tag, multiple) buffer = '' buffer << @packed_indexes buffer << AMQ::Hacks.pack_64_big_endian(delivery_tag) bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if multiple buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class Reject < Protocol::Method @name = "basic.reject" @method_id = 90 @index = 0x003C005A # 60, 90, 3932250 @packed_indexes = [60, 90].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'delivery_tag = nil', u'requeue = true'] def self.encode(channel, delivery_tag, requeue) buffer = '' buffer << @packed_indexes buffer << AMQ::Hacks.pack_64_big_endian(delivery_tag) bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if requeue buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class RecoverAsync < Protocol::Method @name = "basic.recover-async" @method_id = 100 @index = 0x003C0064 # 60, 100, 3932260 @packed_indexes = [60, 100].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'requeue = false'] def self.encode(channel, requeue) buffer = '' buffer << @packed_indexes bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if requeue buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class Recover < Protocol::Method @name = "basic.recover" @method_id = 110 @index = 0x003C006E # 60, 110, 3932270 @packed_indexes = [60, 110].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [u'requeue = false'] def self.encode(channel, requeue) buffer = '' buffer << @packed_indexes bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if requeue buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class RecoverOk < Protocol::Method @name = "basic.recover-ok" @method_id = 111 @index = 0x003C006F # 60, 111, 3932271 @packed_indexes = [60, 111].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end class Nack < Protocol::Method @name = "basic.nack" @method_id = 120 @index = 0x003C0078 # 60, 120, 3932280 @packed_indexes = [60, 120].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 delivery_tag = AMQ::Hacks.unpack_64_big_endian(data[offset, 8]).first offset += 8 bit_buffer = data[offset, 1].unpack(PACK_CHAR).first offset += 1 multiple = (bit_buffer & (1 << 0)) != 0 requeue = (bit_buffer & (1 << 1)) != 0 self.new(delivery_tag, multiple, requeue) end attr_reader :delivery_tag, :multiple, :requeue def initialize(delivery_tag, multiple, requeue) @delivery_tag = delivery_tag @multiple = multiple @requeue = requeue end def self.has_content? false end # @return # [u'delivery_tag = false', u'multiple = false', u'requeue = true'] def self.encode(channel, delivery_tag, multiple, requeue) buffer = '' buffer << @packed_indexes buffer << AMQ::Hacks.pack_64_big_endian(delivery_tag) bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if multiple bit_buffer = bit_buffer | (1 << 1) if requeue buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end end class Tx < Protocol::Class @name = "tx" @method_id = 90 class Select < Protocol::Method @name = "tx.select" @method_id = 10 @index = 0x005A000A # 90, 10, 5898250 @packed_indexes = [90, 10].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [] def self.encode(channel) buffer = '' buffer << @packed_indexes MethodFrame.new(buffer, channel) end end class SelectOk < Protocol::Method @name = "tx.select-ok" @method_id = 11 @index = 0x005A000B # 90, 11, 5898251 @packed_indexes = [90, 11].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end class Commit < Protocol::Method @name = "tx.commit" @method_id = 20 @index = 0x005A0014 # 90, 20, 5898260 @packed_indexes = [90, 20].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [] def self.encode(channel) buffer = '' buffer << @packed_indexes MethodFrame.new(buffer, channel) end end class CommitOk < Protocol::Method @name = "tx.commit-ok" @method_id = 21 @index = 0x005A0015 # 90, 21, 5898261 @packed_indexes = [90, 21].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end class Rollback < Protocol::Method @name = "tx.rollback" @method_id = 30 @index = 0x005A001E # 90, 30, 5898270 @packed_indexes = [90, 30].pack(PACK_UINT16_X2).freeze def self.has_content? false end # @return # [] def self.encode(channel) buffer = '' buffer << @packed_indexes MethodFrame.new(buffer, channel) end end class RollbackOk < Protocol::Method @name = "tx.rollback-ok" @method_id = 31 @index = 0x005A001F # 90, 31, 5898271 @packed_indexes = [90, 31].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end end end class Confirm < Protocol::Class @name = "confirm" @method_id = 85 class Select < Protocol::Method @name = "confirm.select" @method_id = 10 @index = 0x0055000A # 85, 10, 5570570 @packed_indexes = [85, 10].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 bit_buffer = data[offset, 1].unpack(PACK_CHAR).first offset += 1 nowait = (bit_buffer & (1 << 0)) != 0 self.new(nowait) end attr_reader :nowait def initialize(nowait) @nowait = nowait end def self.has_content? false end # @return # [u'nowait = false'] def self.encode(channel, nowait) buffer = '' buffer << @packed_indexes bit_buffer = 0 bit_buffer = bit_buffer | (1 << 0) if nowait buffer << [bit_buffer].pack(PACK_CHAR) MethodFrame.new(buffer, channel) end end class SelectOk < Protocol::Method @name = "confirm.select-ok" @method_id = 11 @index = 0x0055000B # 85, 11, 5570571 @packed_indexes = [85, 11].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 self.new() end def initialize() end def self.has_content? false end # @return # [] def self.encode(channel) buffer = '' buffer << @packed_indexes MethodFrame.new(buffer, channel) end end end METHODS = begin Method.methods.inject(Hash.new) do |hash, klass| hash.merge!(klass.index => klass) end end end end amq-protocol-0.9.2/lib/amq/protocol/table.rb0000644000175000017500000001021311772516231020246 0ustar tfheentfheen# encoding: binary require "amq/protocol/client" require "amq/protocol/type_constants" require "amq/protocol/table_value_encoder" require "amq/protocol/table_value_decoder" # We will need to introduce concept of mappings, because # AMQP 0.9, 0.9.1 and RabbitMQ uses different letters for entities # http://dev.rabbitmq.com/wiki/Amqp091Errata#section_3 module AMQ module Protocol class Table # # Behaviors # include TypeConstants # # API # class InvalidTableError < StandardError def initialize(key, value) super("Invalid table value on key #{key}: #{value.inspect} (#{value.class})") end end def self.encode(table) buffer = String.new table ||= {} table.each do |key, value| key = key.to_s # it can be a symbol as well buffer << key.bytesize.chr + key case value when Hash then buffer << TYPE_HASH buffer << self.encode(value) else buffer << TableValueEncoder.encode(value) end end [buffer.bytesize].pack(PACK_UINT32) + buffer end def self.decode(data) table = Hash.new table_length = data.unpack(PACK_UINT32).first return table if table_length.zero? offset = 4 while offset <= table_length key, offset = decode_table_key(data, offset) type, offset = TableValueDecoder.decode_value_type(data, offset) table[key] = case type when TYPE_STRING v, offset = TableValueDecoder.decode_string(data, offset) v when TYPE_INTEGER v, offset = TableValueDecoder.decode_integer(data, offset) v when TYPE_DECIMAL v, offset = TableValueDecoder.decode_big_decimal(data, offset) v when TYPE_TIME v, offset = TableValueDecoder.decode_time(data, offset) v when TYPE_HASH v, offset = TableValueDecoder.decode_hash(data, offset) v when TYPE_BOOLEAN v, offset = TableValueDecoder.decode_boolean(data, offset) v when TYPE_SIGNED_8BIT then raise NotImplementedError.new when TYPE_SIGNED_16BIT then raise NotImplementedError.new when TYPE_SIGNED_64BIT then raise NotImplementedError.new when TYPE_32BIT_FLOAT then v, offset = TableValueDecoder.decode_32bit_float(data, offset) v when TYPE_64BIT_FLOAT then v, offset = TableValueDecoder.decode_64bit_float(data, offset) v when TYPE_VOID nil when TYPE_ARRAY v, offset = TableValueDecoder.decode_array(data, offset) v else raise ArgumentError, "Not a valid type: #{type.inspect}\nData: #{data.inspect}\nUnprocessed data: #{data[offset..-1].inspect}\nOffset: #{offset}\nTotal size: #{table_length}\nProcessed data: #{table.inspect}" end end table end # self.decode def self.length(data) data.unpack(PACK_UINT32).first end def self.hash_size(value) acc = 0 value.each do |k, v| acc += (1 + k.to_s.bytesize) acc += TableValueEncoder.field_value_size(v) end acc end # self.hash_size(value) def self.decode_table_key(data, offset) key_length = data.slice(offset, 1).unpack(PACK_CHAR).first offset += 1 key = data.slice(offset, key_length) offset += key_length [key, offset] end # self.decode_table_key(data, offset) end # Table end # Protocol end # AMQ amq-protocol-0.9.2/lib/amq/protocol/type_constants.rb0000644000175000017500000000136211772516231022241 0ustar tfheentfheen# encoding: binary module AMQ module Protocol module TypeConstants TYPE_STRING = 'S'.freeze TYPE_INTEGER = 'I'.freeze TYPE_HASH = 'F'.freeze TYPE_TIME = 'T'.freeze TYPE_DECIMAL = 'D'.freeze TYPE_BOOLEAN = 't'.freeze TYPE_SIGNED_8BIT = 'b'.freeze TYPE_SIGNED_16BIT = 's'.freeze TYPE_SIGNED_64BIT = 'l'.freeze TYPE_32BIT_FLOAT = 'f'.freeze TYPE_64BIT_FLOAT = 'd'.freeze TYPE_VOID = 'V'.freeze TYPE_BYTE_ARRAY = 'x'.freeze TYPE_ARRAY = 'A'.freeze TEN = '10'.freeze BOOLEAN_TRUE = "\x01".freeze BOOLEAN_FALSE = "\x00".freeze end # TypeConstants end # Protocol end # AMQ amq-protocol-0.9.2/lib/amq/hacks.rb0000644000175000017500000000141211772516231016410 0ustar tfheentfheen# encoding: binary # Ruby doesn't support pack to/unpack from # 64bit string in network byte order. module AMQ module Hacks BIG_ENDIAN = ([1].pack("s") == "\x00\x01") Q = "Q".freeze if BIG_ENDIAN def self.pack_64_big_endian(long_long) [long_long].pack(Q) end def self.unpack_64_big_endian(data) data.unpack(Q) end else def self.pack_64_big_endian(long_long) result = [long_long].pack(Q) result.bytes.to_a.reverse.map(&:chr).join end def self.unpack_64_big_endian(data) data = data.bytes.to_a.reverse.map(&:chr).join data.unpack(Q) end end end end # AMQ::Hacks.pack_64_big_endian(17) # AMQ::Hacks.unpack_64_big_endian("\x00\x00\x00\x00\x00\x00\x00\x11")