amq-protocol-2.0.1/0000755000004100000410000000000012637243075014170 5ustar www-datawww-dataamq-protocol-2.0.1/Rakefile0000644000004100000410000000215212637243075015635 0ustar www-datawww-datarequire "bundler" Bundler.setup require "rake" require "rspec/core/rake_task" $LOAD_PATH.unshift File.expand_path("../lib", __FILE__) require "amq/protocol/version" task :gem => :build task :build do system "gem build amq-protocol.gemspec" end task :install => :build do system "gem install amq-protocol-#{AMQ::Protocol::VERSION}.gem" end def extension RUBY_PLATFORM =~ /darwin/ ? "bundle" : "so" end def compile! puts "Compiling native extensions..." Dir.chdir(Pathname(__FILE__).dirname + "ext/") do `bundle exec ruby extconf.rb` `make` `cp client.#{extension} ../lib/amq/protocol/native/` end end RSpec::Core::RakeTask.new("spec") do |spec| spec.pattern = "spec/**/*_spec.rb" end RSpec::Core::RakeTask.new("clean_spec") do |spec| spec.pattern = "spec/**/*_spec.rb" end task :compile do compile! end task :clean do puts "Cleaning out native extensions..." begin Dir.chdir(Pathname(__FILE__).dirname + "lib/amq-protocol/native") do `rm client.#{extension}` end rescue Exception => e puts e.message end end task :default => [:compile, :spec, :clean, :clean_spec] amq-protocol-2.0.1/Gemfile0000644000004100000410000000040712637243075015464 0ustar www-datawww-data# encoding: utf-8 source "https://rubygems.org" group :development do # excludes Windows, Rubinius and JRuby gem "ruby-prof", :platforms => [:mri_19, :mri_20, :mri_21] gem "rake" end group :test do gem "rspec" gem "rspec-its" gem "effin_utf8" end amq-protocol-2.0.1/ChangeLog.md0000644000004100000410000000442112637243075016342 0ustar www-datawww-data## Changes between 1.9.x and 2.0.0 2.0.0 has **breaking changes** in header encoding. ### Signed Integer Encoding in Headers Integer values in headers are now encoded as signed 64-bit (was unsigned 32-bit previously, unintentionally). This is a breaking change: consuming messages with integers in headers published with older versions of this library will break! ### Signed 16 Bit Integer Decoding Signed 16 bit integers are now decoded correctly. ### Signed 8 Bit Integer Decoding Signed 8 bit integers are now decoded correctly. Contributed by Benjamin Conlan. ## Changes between 1.8.0 and 1.9.0 ### Performance Improvements in AMQ::BitSet `AMQ::BitSet#next_clear_bit` is now drastically more efficient (down from 6 minutes for 10,000 iterations to 4 seconds for 65,536 iterations). Contributed by Doug Rohrer, Dave Anderson, and Jason Voegele from [Neo](http://www.neo.com). ## Changes between 1.7.0 and 1.8.0 ### Body Framing Fix Messages exactly 128 Kb in size are now framed correctly. Contributed by Nicolas Viennot. ## Changes between 1.6.0 and 1.7.0 ### connection.blocked Support `connection.blocked` AMQP 0.9.1 extension is now supported (should be available as of RabbitMQ 3.2). ## Changes between 1.0.0 and 1.1.0 ### Performance Enhancements Encoding of large payloads is now done more efficiently. Contributed by Greg Brockman. ## Changes between 1.0.0.pre6 and 1.0.0.pre7 ### AMQ::Settings `AMQ::Settings` extracts settings merging logic and AMQP/AMQPS URI parsing from `amq-client`. Parsing follows the same convention amqp gem and RabbitMQ Java client follow. Examples: ``` ruby AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com") # => vhost is nil, so default (/) will be used AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/") # => vhost is an empty string AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/%2Fvault") # => vhost is /vault AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/production") # => vhost is production AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/a.b.c") # => vhost is a.b.c AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/foo/bar") # => ArgumentError ``` ### AMQ::Protocol::TLS_PORT `AMQ::Protocol::TLS_PORT` is a new constant that contains default AMQPS 0.9.1 port, 5671. amq-protocol-2.0.1/.rspec0000644000004100000410000000003312637243075015301 0ustar www-datawww-data--colour --format progress amq-protocol-2.0.1/amq-protocol.gemspec0000755000004100000410000000166512637243075020165 0ustar www-datawww-data#!/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 encoding & decoding library." s.description = <<-DESC amq-protocol is an AMQP 0.9.1 serialization library for Ruby. It is not a client: the library only handles serialization and deserialization. DESC s.email = ["michael.s.klishin@gmail.com"] s.licenses = ["MIT"] s.required_ruby_version = Gem::Requirement.new(">= 2.0") # 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/*") s.rubyforge_project = "amq-protocol" end amq-protocol-2.0.1/spec/0000755000004100000410000000000012637243075015122 5ustar www-datawww-dataamq-protocol-2.0.1/spec/amq/0000755000004100000410000000000012637243075015700 5ustar www-datawww-dataamq-protocol-2.0.1/spec/amq/bit_set_spec.rb0000644000004100000410000001314012637243075020667 0ustar www-datawww-data# encoding: utf-8 require 'spec_helper' require "amq/bit_set" # extracted from amqp gem. MK. describe AMQ::BitSet do # # Environment # let(:nbits) { (1 << 16) - 1 } # # Examples # describe "#new" do it "has no bits set at the start" do bs = AMQ::BitSet.new(128) 0.upto(127) do |i| expect(bs[i]).to be_falsey end end # it end # describe describe "#word_index" do subject do described_class.new(nbits) end it "returns 0 when the word is between 0 and 63" do expect(subject.word_index(0)).to eq(0) expect(subject.word_index(63)).to eq(0) end # it it "returns 1 when the word is between 64 and 127" do expect(subject.word_index(64)).to be(1) expect(subject.word_index(127)).to be(1) end # it it "returns 2 when the word is between 128 and another number" do expect(subject.word_index(128)).to be(2) end # it end # describe describe "#get, #[]" do describe "when bit at given position is set" do subject do o = described_class.new(nbits) o.set(3) o end it "returns true" do expect(subject.get(3)).to be_truthy end # it end # describe describe "when bit at given position is off" do subject do described_class.new(nbits) end it "returns false" do expect(subject.get(5)).to be_falsey end # it end # describe describe "when index out of range" do subject do described_class.new(nbits) end it "should raise IndexError for negative index" do expect { subject.get(-1) }.to raise_error(IndexError) end # it it "should raise IndexError for index >= number of bits" do expect { subject.get(nbits) }.to raise_error(IndexError) end # it end # describe end # describe describe "#set" do describe "when bit at given position is set" do subject do described_class.new(nbits) end it "has no effect" do subject.set(3) expect(subject.get(3)).to be_truthy subject.set(3) expect(subject[3]).to be_truthy end # it end # describe describe "when bit at given position is off" do subject do described_class.new(nbits) end it "sets that bit" do subject.set(3) expect(subject.get(3)).to be_truthy subject.set(33) expect(subject.get(33)).to be_truthy subject.set(3387) expect(subject.get(3387)).to be_truthy end # it end # describe describe "when index out of range" do subject do described_class.new(nbits) end it "should raise IndexError for negative index" do expect { subject.set(-1) }.to raise_error(IndexError) end # it it "should raise IndexError for index >= number of bits" do expect { subject.set(nbits) }.to raise_error(IndexError) end # it end # describe end # describe describe "#unset" do describe "when bit at a given position is set" do subject do described_class.new(nbits) end it "unsets that bit" do subject.set(3) expect(subject.get(3)).to be_truthy subject.unset(3) expect(subject.get(3)).to be_falsey end # it end # describe describe "when bit at a given position is off" do subject do described_class.new(nbits) end it "has no effect" do expect(subject.get(3)).to be_falsey subject.unset(3) expect(subject.get(3)).to be_falsey end # it end # describe describe "when index out of range" do subject do described_class.new(nbits) end it "should raise IndexError for negative index" do expect { subject.unset(-1) }.to raise_error(IndexError) end # it it "should raise IndexError for index >= number of bits" do expect { subject.unset(nbits) }.to raise_error(IndexError) end # it end # describe end # describe describe "#clear" do subject do described_class.new(nbits) end it "clears all bits" do subject.set(3) expect(subject.get(3)).to be_truthy subject.set(7668) expect(subject.get(7668)).to be_truthy subject.clear expect(subject.get(3)).to be_falsey expect(subject.get(7668)).to be_falsey end # it end # describe describe "#number_of_trailing_ones" do it "calculates them" do expect(described_class.number_of_trailing_ones(0)).to eq(0) expect(described_class.number_of_trailing_ones(1)).to eq(1) expect(described_class.number_of_trailing_ones(2)).to eq(0) expect(described_class.number_of_trailing_ones(3)).to eq(2) expect(described_class.number_of_trailing_ones(4)).to eq(0) end # it end # describe describe '#next_clear_bit' do subject do described_class.new(255) end it "returns sequential values when none have been returned" do expect(subject.next_clear_bit).to eq(0) subject.set(0) expect(subject.next_clear_bit).to eq(1) subject.set(1) expect(subject.next_clear_bit).to eq(2) subject.unset(1) expect(subject.next_clear_bit).to eq(1) end # it it "returns the same number as long as nothing is set" do expect(subject.next_clear_bit).to eq(0) expect(subject.next_clear_bit).to eq(0) end # it it "handles more than 128 bits" do 0.upto(254) do |i| subject.set(i) expect(subject.next_clear_bit).to eq(i + 1) end subject.unset(254) expect(subject.get(254)).to be_falsey end # it end # describe end amq-protocol-2.0.1/spec/amq/protocol/0000755000004100000410000000000012637243075017541 5ustar www-datawww-dataamq-protocol-2.0.1/spec/amq/protocol/queue_spec.rb0000644000004100000410000000751112637243075022230 0ustar www-datawww-data# 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) expect(method_frame.payload).to eq("\x002\x00\n\x00\x00\vhello.world\x0E\x00\x00\x00\x00") expect(method_frame.channel).to eq(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 eq('amq.gen-KduGSqQrpeUo1otnU0TWSA==') } its(:message_count) { should eq(0) } its(:consumer_count) { should eq(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) expect(method_frame.payload).to eq("\x002\x00\x14\x00\x00\vhello.world\afoo.bar\x03xyz\x00\x00\x00\x00\x00") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\x002\x00\x1E\x00\x00\vhello.world\x00") expect(method_frame.channel).to eq(1) end end end describe PurgeOk do describe '.decode' do subject do PurgeOk.decode("\x00\x00\x00\x02") end its(:message_count) { should eq(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) expect(method_frame.payload).to eq("\x002\x00(\x00\x00\vhello.world\x00") expect(method_frame.channel).to eq(1) end end end describe DeleteOk do describe '.decode' do subject do DeleteOk.decode("\x00\x00\x00\x02") end its(:message_count) { should eq(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) expect(method_frame.payload).to eq("\x002\x002\x00\x00\vhello.world\afoo.bar\x03xyz\x00\x00\x00\x00") expect(method_frame.channel).to eq(1) end end end # describe UnbindOk do # describe '.decode' do # end # end end end end amq-protocol-2.0.1/spec/amq/protocol/blank_body_encoding_spec.rb0000644000004100000410000000064112637243075025053 0ustar www-datawww-data# 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 expect(described_class.encode_body('1', 1, 65536).size).to eq(1) end it "encodes 0-byte long (blank) payload as exactly 0 body frame" do expect(described_class.encode_body('', 1, 65536).size).to eq(0) end end amq-protocol-2.0.1/spec/amq/protocol/exchange_spec.rb0000644000004100000410000000677412637243075022700 0ustar www-datawww-data# 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) expect(method_frame.payload).to eq("\x00(\x00\n\x00\x00\x1Famqclient.adapters.em.exchange1\x06fanout\x00\x00\x00\x00\x00") expect(method_frame.channel).to eq(1) end end end describe Declare, "encoded with a symbol name" do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 exchange = :exchange2 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) expect(method_frame.payload).to eq("\x00(\x00\n\x00\x00\texchange2\x06fanout\x00\x00\x00\x00\x00") expect(method_frame.channel).to eq(1) end 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) expect(method_frame.payload).to eq("\x00(\x00\x14\x00\x00\x1Eamqclient.adapters.em.exchange\x00") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\x00(\x00\x1E\x00\x00\x03foo\x03bar\x03xyz\x00\x00\x00\x00\x00") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\x00(\x00(\x00\x00\x03foo\x03bar\x03xyz\x00\x00\x00\x00\x00") expect(method_frame.channel).to eq(1) end end end # describe UnbindOk do # describe '.decode' do # end # end end end end amq-protocol-2.0.1/spec/amq/protocol/basic_spec.rb0000644000004100000410000002631212637243075022165 0ustar www-datawww-data# 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 expect(Basic.encode_timestamp(12345).last).to eq("\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 # expect(Basic.decode_timestamp("\x00\x00\x00\x00\x00\x0009")).to eq(Time.at(12345)) # end # end describe '.encode_headers' do it 'encodes the headers as a table' do expect(Basic.encode_headers(:hello => 'world').last).to eq("\x00\x00\x00\x10\x05helloS\x00\x00\x00\x05world") end end # describe '.decode_headers' do # it 'decodes the headers from a table' do # expect(Basic.decode_headers("\x00\x00\x00\x10\x05helloS\x00\x00\x00\x05world")).to eq({'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'}) expect(result).to eq("\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{") expect(result).to eq({: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{") expect(result).to eq({: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 expect(Basic.send("encode_#{method}", 'hello world').last).to eq("\x0bhello world") end end # describe ".decode_#{method}" do # it 'returns the string' do # # the length has been stripped in .decode_properties # expect(Basic.send("decode_#{method}", 'hello world')).to eq('hello world') # end # end end %w(delivery_mode priority).each do |method| describe ".encode_#{method}" do it 'encodes the parameter as a char' do expect(Basic.send("encode_#{method}", 10).last).to eq("\x0a") end end # describe ".decode_#{method}" do # it 'decodes the value from a char' do # expect(Basic.send("decode_#{method}", "\x10")).to eq(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) expect(method_frame.payload).to eq("\x00<\x00\n\x00\x00\x00\x03\x00\x05\x00") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\x00<\x00\x14\x00\x00\x03foo\x02me\x04\x00\x00\x00\x00") expect(method_frame.channel).to eq(1) end end end describe ConsumeOk do describe '.decode' do subject do ConsumeOk.decode("\x03foo") end its(:consumer_tag) { should eq('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) expect(method_frame.payload).to eq("\x00<\x00\x1E\x03foo\x01") expect(method_frame.channel).to eq(1) end end describe '.decode' do subject do CancelOk.decode("\x03foo\x01") end its(:consumer_tag) { should eq('foo') } end end describe CancelOk do describe '.decode' do subject do CancelOk.decode("\x03foo") end its(:consumer_tag) { should eq('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) expect(method_frames[0].payload).to eq("\x00<\x00(\x00\x00\x03foo\x03xyz\x02") expect(method_frames[1].payload).to eq("\x00<\x00\x00\x00\x00\x00\x00\x00\x00\x00\f\x88\x00\x18application/octet-stream\x00") expect(method_frames[2].payload).to eq("Hello World!") expect(method_frames[0].channel).to eq(1) expect(method_frames[1].channel).to eq(1) expect(method_frames[2].channel).to eq(1) expect(method_frames.size).to eq(3) end end end describe Return do describe '.decode' do subject do Return.decode("\x019\fNO_CONSUMERS\namq.fanout\x00") end its(:reply_code) { should eq(313) } its(:reply_text) { should eq('NO_CONSUMERS') } its(:exchange) { should eq('amq.fanout') } its(:routing_key) { should eq('') } 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 eq('-1300560114000-445586772970') } its(:delivery_tag) { should eq(99) } its(:redelivered) { should eq(false) } its(:exchange) { should eq('amq.fanout') } its(:routing_key) { should eq('') } 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) expect(method_frame.payload).to eq("\x00\x3c\x00\x46\x00\x00\x03foo\x01") expect(method_frame.channel).to eq(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 eq(6) } its(:redelivered) { should eq(false) } its(:exchange) { should eq('amq.fanout') } its(:routing_key) { should eq('') } its(:message_count) { should eq(94) } end end describe GetEmpty do describe '.decode' do subject do GetEmpty.decode("\x03foo") end its(:cluster_id) { should eq('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) expect(method_frame.payload).to eq("\x00<\x00P\x00\x00\x00\x00\x00\x00\x00\x06\x00") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\x00<\x00Z\x00\x00\x00\x00\x00\x00\x00\x08\x01") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\x00<\x00d\x01") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\x00<\x00n\x01") expect(method_frame.channel).to eq(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 eq(9) } its(:multiple) { should eq(true) } its(:requeue) { should eq(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) expect(method_frame.payload).to eq("\x00<\x00x\x00\x00\x00\x00\x00\x00\x00\x0a\x02") expect(method_frame.channel).to eq(1) end end end end end end amq-protocol-2.0.1/spec/amq/protocol/connection_spec.rb0000644000004100000410000001265512637243075023250 0ustar www-datawww-data# 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 expect(method_frame.payload[0, 8]).to eq("\x00\n\x00\v\x00\x00\x00x") expect(method_frame.payload).to include("\bplatformS\x00\x00\x00\nRuby 1.9.2") expect(method_frame.payload).to include("\aproductS\x00\x00\x00\nAMQ Client") expect(method_frame.payload).to include("\vinformationS\x00\x00\x00&http://github.com/ruby-amqp/amq-client") expect(method_frame.payload).to include("\aversionS\x00\x00\x00\x050.2.0") expect(method_frame.payload[-28, 28]).to eq("\x05PLAIN\x00\x00\x00\f\x00guest\x00guest\x05en_GB") expect(method_frame.payload.length).to eq(156) end end end describe Secure do describe '.decode' do subject do Secure.decode("\x00\x00\x00\x03foo") end its(:challenge) { should eq('foo') } end end describe SecureOk do describe '.encode' do it 'encodes the parameters as a MethodFrame' do response = 'bar' method_frame = SecureOk.encode(response) expect(method_frame.payload).to eq("\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 eq(0) } its(:frame_max) { should eq(131072) } its(:heartbeat) { should eq(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) expect(method_frame.payload).to eq("\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) expect(method_frame.payload).to eq("\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 eq('') } 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 eq(200) } its(:reply_text) { should eq('KTHXBAI') } its(:class_id) { should eq(5) } its(:method_id) { should eq(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) expect(method_frame.payload).to eq("\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 expect(method_frame.payload).to eq("\x00\n\x003") end end end end end end amq-protocol-2.0.1/spec/amq/protocol/channel_spec.rb0000644000004100000410000000756212637243075022522 0ustar www-datawww-data# 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) expect(method_frame.payload).to eq("\x00\x14\x00\n\x00") expect(method_frame.channel).to eq(1) end end end describe OpenOk do describe '.decode' do subject do OpenOk.decode("\x00\x00\x00\x03foo") end its(:channel_id) { should eq('foo') } end end describe Flow do describe '.decode' do subject do Flow.decode("\x01") end its(:active) { should be_truthy } end describe '.encode' do it 'encodes the parameters as a MethodFrame' do channel = 1 active = true method_frame = Flow.encode(channel, active) expect(method_frame.payload).to eq("\x00\x14\x00\x14\x01") expect(method_frame.channel).to eq(1) end end end describe FlowOk do describe '.decode' do subject do FlowOk.decode("\x00") end its(:active) { should be_falsey } end describe '.encode' do it 'encodes the parameters as a MethodFrame' do channel = 1 active = true method_frame = FlowOk.encode(channel, active) expect(method_frame.payload).to eq("\x00\x14\x00\x15\x01") expect(method_frame.channel).to eq(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 eq(200) } its(:reply_text) { should eq('KTHXBAI') } its(:class_id) { should eq(5) } its(:method_id) { should eq(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 eq(404) } its(:reply_text) { should eq(%q{NOT_FOUND - no binding 123456789012345678901234567890123 between exchange 'amq.topic' in vhost '/' and queue 'test' in vhost '/'}) } its(:class_id) { should eq(50) } its(:method_id) { should eq(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) expect(method_frame.payload).to eq("\x00\x14\x00(\x02\x1c\x0fNOT_IMPLEMENTED\x00\x00\x00\x00") expect(method_frame.channel).to eq(1) end end end describe CloseOk do describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 method_frame = CloseOk.encode(channel) expect(method_frame.payload).to eq("\x00\x14\x00\x29") expect(method_frame.channel).to eq(channel) end end end end end end amq-protocol-2.0.1/spec/amq/protocol/constants_spec.rb0000644000004100000410000000054112637243075023114 0ustar www-datawww-data# encoding: binary require File.expand_path('../../../spec_helper', __FILE__) describe "(Some) AMQ::Protocol constants" do it "include regular port" do expect(AMQ::Protocol::DEFAULT_PORT).to eq(5672) end it "provides TLS/SSL port" do expect(AMQ::Protocol::TLS_PORT).to eq(5671) expect(AMQ::Protocol::SSL_PORT).to eq(5671) end end amq-protocol-2.0.1/spec/amq/protocol/value_encoder_spec.rb0000644000004100000410000001161512637243075023717 0ustar www-datawww-data# -*- coding: utf-8 -*- require File.expand_path('../../../spec_helper', __FILE__) require 'time' require "amq/protocol/table_value_encoder" require "amq/protocol/float_32bit" module AMQ module Protocol describe TableValueEncoder do it "calculates size of string field values" do expect(described_class.field_value_size("amqp")).to eq(9) expect(described_class.encode("amqp").bytesize).to eq(9) expect(described_class.field_value_size("amq-protocol")).to eq(17) expect(described_class.encode("amq-protocol").bytesize).to eq(17) expect(described_class.field_value_size("à bientôt")).to eq(16) expect(described_class.encode("à bientôt").bytesize).to eq(16) end it "calculates size of integer field values" do expect(described_class.field_value_size(10)).to eq(9) expect(described_class.encode(10).bytesize).to eq(9) end it "calculates size of float field values (considering them to be 64-bit)" do expect(described_class.field_value_size(10.0)).to eq(9) expect(described_class.encode(10.0).bytesize).to eq(9) expect(described_class.field_value_size(120000.0)).to eq(9) expect(described_class.encode(120000.0).bytesize).to eq(9) end it "calculates size of float field values (boxed as 32-bit)" do expect(described_class.encode(AMQ::Protocol::Float32Bit.new(10.0)).bytesize).to eq(5) expect(described_class.encode(AMQ::Protocol::Float32Bit.new(120000.0)).bytesize).to eq(5) end it "calculates size of boolean field values" do expect(described_class.field_value_size(true)).to eq(2) expect(described_class.encode(true).bytesize).to eq(2) expect(described_class.field_value_size(false)).to eq(2) expect(described_class.encode(false).bytesize).to eq(2) end it "calculates size of void field values" do expect(described_class.field_value_size(nil)).to eq(1) expect(described_class.encode(nil).bytesize).to eq(1) end it "calculates size of time field values" do t = Time.parse("2011-07-14 01:17:46 +0400") expect(described_class.field_value_size(t)).to eq(9) expect(described_class.encode(t).bytesize).to eq(9) end it "calculates size of basic table field values" do input1 = { "key" => "value" } expect(described_class.field_value_size(input1)).to eq(19) expect(described_class.encode(input1).bytesize).to eq(19) input2 = { "intval" => 1 } expect(described_class.field_value_size(input2)).to eq(21) expect(described_class.encode(input2).bytesize).to eq(21) input3 = { "intval" => 1, "key" => "value" } expect(described_class.field_value_size(input3)).to eq(35) expect(described_class.encode(input3).bytesize).to eq(35) 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" => "à bientôt".force_encoding(::Encoding::ASCII_8BIT) } }, "true" => true, "false" => false, "nil" => nil } } expect(described_class.field_value_size(input1)).to eq(166) # puts(described_class.encode(input1).inspect) expect(described_class.encode(input1).bytesize).to eq(166) 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 } } expect(described_class.field_value_size(input2)).to eq(158) expect(described_class.encode(input2).bytesize).to eq(158) end it "calculates size of basic array field values" do input1 = [1, 2, 3] expect(described_class.field_value_size(input1)).to eq(32) expect(described_class.encode(input1).bytesize).to eq(32) input2 = ["one", "two", "three"] expect(described_class.field_value_size(input2)).to eq(31) expect(described_class.encode(input2).bytesize).to eq(31) input3 = ["one", 2, "three"] expect(described_class.field_value_size(input3)).to eq(32) expect(described_class.encode(input3).bytesize).to eq(32) input4 = ["one", 2, "three", ["four", 5, [6.0]]] expect(described_class.field_value_size(input4)).to eq(69) expect(described_class.encode(input4).bytesize).to eq(69) end end # TableValueEncoder end # Protocol end # AMQ amq-protocol-2.0.1/spec/amq/protocol/table_spec.rb0000644000004100000410000002161312637243075022172 0ustar www-datawww-data# -*- coding: utf-8 -*- 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") DATA = { {} => "\x00\x00\x00\x00", {"test" => 1} => "\x00\x00\x00\x0E\x04testl\x00\x00\x00\x00\x00\x00\x00\x01", {"float" => 1.92} => "\x00\x00\x00\x0F\x05floatd?\xFE\xB8Q\xEB\x85\x1E\xB8", {"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" } describe ".encode" do it "should return \"\x00\x00\x00\x00\" for nil" do encoded_value = "\x00\x00\x00\x00" expect(Table.encode(nil)).to eql(encoded_value) end it "should serialize { :test => true }" do expect(Table.encode(:test => true)). to eql("\x00\x00\x00\a\x04testt\x01".force_encoding(Encoding::ASCII_8BIT)) end it "should serialize { :test => false }" do expect(Table.encode(:test => false)). to eql("\x00\x00\x00\a\x04testt\x00".force_encoding(Encoding::ASCII_8BIT)) end it "should serialize { :coordinates => { :latitude => 59.35 } }" do expect(Table.encode(:coordinates => { :latitude => 59.35 })). to eql("\x00\x00\x00#\vcoordinatesF\x00\x00\x00\x12\blatituded@M\xAC\xCC\xCC\xCC\xCC\xCD".force_encoding(Encoding::ASCII_8BIT)) end it "should serialize { :coordinates => { :longitude => 18.066667 } }" do expect(Table.encode(:coordinates => { :longitude => 18.066667 })). to eql("\x00\x00\x00$\vcoordinatesF\x00\x00\x00\x13\tlongituded@2\x11\x11\x16\xA8\xB8\xF1".force_encoding(Encoding::ASCII_8BIT)) end DATA.each do |data, encoded| it "should return #{encoded.inspect} for #{data.inspect}" do expect(Table.encode(data)).to eql(encoded.force_encoding(Encoding::ASCII_8BIT)) end end end describe ".decode" do DATA.each do |data, encoded| it "should return #{data.inspect} for #{encoded.inspect}" do expect(Table.decode(encoded)).to eql(data) end it "is capable of decoding what it encodes" do expect(Table.decode(Table.encode(data))).to eq(data) end end # DATA.each it "is capable of decoding boolean table values" do input1 = { "boolval" => true } expect(Table.decode(Table.encode(input1))).to eq(input1) input2 = { "boolval" => false } expect(Table.decode(Table.encode(input2))).to eq(input2) end it "is capable of decoding nil table values" do input = { "nilval" => nil } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding nil table in nested hash/map values" do input = { "hash" => {"nil" => nil} } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding string table values" do input = { "stringvalue" => "string" } expect(Table.decode(Table.encode(input))).to eq(input) expect(Table.decode("\x00\x00\x00\x17\vstringvalueS\x00\x00\x00\x06string")).to eq(input) end it "is capable of decoding byte array table values (as Ruby strings)" do expect(Table.decode("\x00\x00\x00\x17\vstringvaluex\x00\x00\x00\x06string")).to eq({"stringvalue" => "string"}) end it "is capable of decoding string table values with UTF-8 characters" do input = { "строка".force_encoding(::Encoding::ASCII_8BIT) => "значение".force_encoding(::Encoding::ASCII_8BIT) } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding integer table values" do input = { "intvalue" => 10 } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding signed integer table values" do input = { "intvalue" => -10 } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding long table values" do input = { "longvalue" => 912598613 } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding float table values" do input = { "floatvalue" => 100.0 } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding time table values" do input = { "intvalue" => Time.parse("2011-07-14 01:17:46 +0400") } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding empty hash table values" do input = { "hashvalue" => Hash.new } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding empty array table values" do input = { "arrayvalue" => Array.new } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding single string value array table values" do input = { "arrayvalue" => ["amq-protocol"] } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding simple nested hash table values" do input = { "hashvalue" => { "a" => "b" } } expect(Table.decode(Table.encode(input))).to eq(input) end it "is capable of decoding nil table values" do input = { "nil" => nil } expect(Table.decode(Table.encode(input))).to eq(input) end it 'is capable of decoding 8bit signed integers' do output = TableValueDecoder.decode_byte("\xC0",0).first expect(output).to eq(192) end it 'is capable of decoding 16bit signed integers' do output = TableValueDecoder.decode_short("\x06\x8D", 0).first expect(output).to eq(1677) 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 } } expect(Table.decode(Table.encode(input))).to eq(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".force_encoding(::Encoding::ASCII_8BIT) } }, "true" => true, "false" => false, "nil" => nil } } expect(Table.decode(Table.encode(input))).to eq(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 }]] } expect(Table.decode(Table.encode(input1))).to eq(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] } expect(Table.decode(Table.encode(input2))).to eq(input2) input3 = { "timely" => { "now" => now } } expect(Table.decode(Table.encode(input3))["timely"]["now"].to_i).to eq(now.to_i) end end # describe end end end amq-protocol-2.0.1/spec/amq/protocol/tx_spec.rb0000644000004100000410000000263212637243075021536 0ustar www-datawww-data# 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) expect(method_frame.payload).to eq("\000Z\000\n") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\000Z\000\024") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\000Z\000\036") expect(method_frame.channel).to eq(1) end end end # describe RollbackOk do # describe '.decode' do # end # end end end end amq-protocol-2.0.1/spec/amq/protocol/confirm_spec.rb0000644000004100000410000000211312637243075022532 0ustar www-datawww-data# 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_truthy } end describe '.encode' do it 'encodes the parameters into a MethodFrame' do channel = 1 nowait = true method_frame = Select.encode(channel, nowait) expect(method_frame.payload).to eq("\x00U\x00\n\x01") expect(method_frame.channel).to eq(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) expect(method_frame.payload).to eq("\000U\000\v") expect(method_frame.channel).to eq(1) end end end end end end amq-protocol-2.0.1/spec/amq/protocol/frame_spec.rb0000644000004100000410000000677712637243075022213 0ustar www-datawww-data# encoding: utf-8 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 expect { Frame.encode(nil, "", 0) }.to 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 expect { Frame.encode(:method, "", -1) }.to raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/) expect { Frame.encode(:method, "", 65536) }.to raise_error(RuntimeError, /^Channel has to be 0 or an integer in range 1\.\.65535/) expect { Frame.encode(:method, "", 65535) }.not_to raise_error expect { Frame.encode(:method, "", 0) }.not_to raise_error expect { Frame.encode(:method, "", 1) }.not_to raise_error end it "should raise RuntimeError if payload is nil" do expect { Frame.encode(:method, nil, 0) }.to raise_error(RuntimeError, "Payload can't be nil") end it "should encode type" do expect(Frame.encode(:body, "", 0).unpack("c").first).to eql(3) end it "should encode channel" do expect(Frame.encode(:body, "", 12).unpack("cn").last).to eql(12) end it "should encode size" do expect(Frame.encode(:body, "test", 12).unpack("cnN").last).to eql(4) end it "should include payload" do expect(Frame.encode(:body, "test", 12)[7..-2]).to eql("test") end it "should include final octet" do expect(Frame.encode(:body, "test", 12).each_byte.to_a.last).to eq("CE".hex) 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 expect(subject.body_size).to eq(10) end it "should decode klass_id from payload" do expect(subject.klass_id).to eq(60) end it "should decode weight from payload" do expect(subject.weight).to eq(0) end it "should decode properties from payload" do expect(subject.properties[:delivery_mode]).to eq(2) expect(subject.properties[:priority]).to eq(0) end end end end end amq-protocol-2.0.1/spec/amq/protocol/method_spec.rb0000644000004100000410000000433112637243075022361 0ustar www-datawww-data# 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) expect(properties).to eq({:delivery_mode => 2, :content_type => 'application/octet-stream'}) expect(headers).to eq({: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) expect(body_frames.first.payload).to eq('Hello world') expect(body_frames.first.channel).to eq(1) expect(body_frames.size).to eq(1) 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) expect(body_frames.map(&:payload)).to eq(lipsum.split('').each_slice(expected_payload_size).map(&:join)) end end context 'when the body fits perfectly in a single frame' do it 'encodes a body into a single BodyFrame' do body_frames = Method.encode_body('*' * 131064, 1, 131072) expect(body_frames.first.payload).to eq('*' * 131064) expect(body_frames.size).to eq(1) end end end end end end amq-protocol-2.0.1/spec/amq/protocol/value_decoder_spec.rb0000644000004100000410000000467312637243075023713 0ustar www-datawww-data# -*- 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) expect(value.size).to eq(3) expect(value.first).to eq(1) expect(value).to eq(input1) input2 = ["one", 2, "three"] value, offset = described_class.decode_array(TableValueEncoder.encode(input2), 1) expect(value.size).to eq(3) expect(value.first).to eq("one") expect(value).to eq(input2) input3 = ["one", 2, "three", 4.0, 5000000.0] value, offset = described_class.decode_array(TableValueEncoder.encode(input3), 1) expect(value.size).to eq(5) expect(value.last).to eq(5000000.0) expect(value).to eq(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) expect(value.size).to eq(2) expect(value.first).to eq(Hash["one" => 2]) expect(value).to eq(input1) input2 = ["one", 2, { "three" => { "four" => 5.0 } }] value, offset = described_class.decode_array(TableValueEncoder.encode(input2), 1) expect(value.size).to eq(3) expect(value.last["three"]["four"]).to eq(5.0) expect(value).to eq(input2) end it "is capable of decoding 32 bit float values" do input = Float32Bit.new(10.0) data = TableValueEncoder.encode(input) value = described_class.decode_32bit_float(data, 1)[0] expect(value).to eq(10.0) end context "8bit/byte decoding" do let(:examples) { { 0x00 => "\x00", 0x01 => "\x01", 0x10 => "\x10", 255 => "\xFF" # not -1 } } it "is capable of decoding byte values" do examples.each do |key, value| expect(described_class.decode_byte(value, 0).first).to eq(key) end end end end end end amq-protocol-2.0.1/spec/amq/pack_spec.rb0000644000004100000410000000421312637243075020155 0ustar www-datawww-data# encoding: binary require File.expand_path('../../spec_helper', __FILE__) module AMQ describe Pack do context "16-bit big-endian packing / unpacking" do let(:examples_16bit) { { 0x068D => "\x06\x8D" # 1677 } } it "unpacks signed integers from a string to a number" do examples_16bit.each do |key, value| expect(described_class.unpack_int16_big_endian(value)[0]).to eq(key) end end end 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| expect(described_class.pack_uint64_big_endian(key)).to eq(value) end end it "should unpack string representation into integer" do examples.each do |key, value| expect(described_class.unpack_uint64_big_endian(value)[0]).to eq(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| expect(described_class.pack_uint64_big_endian(key)).to eq(value) end end it "should unpack string representation into integer" do examples.each do |key, value| expect(described_class.unpack_uint64_big_endian(value)[0]).to eq(key) end end end end end end end amq-protocol-2.0.1/spec/amq/int_allocator_spec.rb0000644000004100000410000000502212637243075022070 0ustar www-datawww-data# encoding: utf-8 require 'spec_helper' require "amq/int_allocator" describe AMQ::IntAllocator do # # Environment # subject do described_class.new(1, 5) end # ... # # Examples # describe "#number_of_bits" do it "returns number of bits available for allocation" do expect(subject.number_of_bits).to eq(4) end end describe "#hi" do it "returns upper bound of the allocation range" do expect(subject.hi).to eq(5) end end describe "#lo" do it "returns lower bound of the allocation range" do expect(subject.lo).to eq(1) end end describe "#allocate" do context "when integer in the range is available" do it "returns allocated integer" do expect(subject.allocate).to eq(1) expect(subject.allocate).to eq(2) expect(subject.allocate).to eq(3) expect(subject.allocate).to eq(4) expect(subject.allocate).to eq(-1) end end context "when integer in the range IS NOT available" do it "returns -1" do 4.times { subject.allocate } expect(subject.allocate).to eq(-1) expect(subject.allocate).to eq(-1) expect(subject.allocate).to eq(-1) expect(subject.allocate).to eq(-1) end end end describe "#free" do context "when the integer WAS allocated" do it "returns frees that integer" do 4.times { subject.allocate } expect(subject.allocate).to eq(-1) subject.free(1) expect(subject.allocate).to eq(1) expect(subject.allocate).to eq(-1) subject.free(2) expect(subject.allocate).to eq(2) expect(subject.allocate).to eq(-1) subject.free(3) expect(subject.allocate).to eq(3) expect(subject.allocate).to eq(-1) end end context "when the integer WAS NOT allocated" do it "has no effect" do 32.times { subject.free(1) } expect(subject.allocate).to eq(1) end end end describe "#allocated?" do context "when given position WAS allocated" do it "returns true" do 3.times { subject.allocate } expect(subject.allocated?(1)).to be_truthy expect(subject.allocated?(2)).to be_truthy expect(subject.allocated?(3)).to be_truthy end end context "when given position WAS NOT allocated" do it "returns false" do 2.times { subject.allocate } expect(subject.allocated?(3)).to be_falsey expect(subject.allocated?(4)).to be_falsey end end end end amq-protocol-2.0.1/spec/amq/protocol_spec.rb0000644000004100000410000006354412637243075021114 0ustar www-datawww-data# encoding: binary require File.expand_path('../../spec_helper', __FILE__) module AMQ describe Protocol do it "should have PROTOCOL_VERSION constant" do expect(Protocol::PROTOCOL_VERSION).to match(/^\d+\.\d+\.\d$/) end it "should have DEFAULT_PORT constant" do expect(Protocol::DEFAULT_PORT).to be_kind_of(Integer) end it "should have PREAMBLE constant" do expect(Protocol::PREAMBLE).to be_kind_of(String) end describe Protocol::Error do it "should be an exception class" do expect(Protocol::Error.ancestors).to include(Exception) end end describe Protocol::Connection do it "should be a subclass of Class" do expect(Protocol::Connection.superclass).to eq(Protocol::Class) end it "should have name equal to connection" do expect(Protocol::Connection.name).to eql("connection") end it "should have method id equal to 10" do expect(Protocol::Connection.method_id).to eq(10) end describe Protocol::Connection::Start do it "should be a subclass of Method" do expect(Protocol::Connection::Start.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.start" do expect(Protocol::Connection::Start.name).to eql("connection.start") end it "should have method id equal to 10" do expect(Protocol::Connection::Start.method_id).to eq(10) end end describe Protocol::Connection::StartOk do it "should be a subclass of Method" do expect(Protocol::Connection::StartOk.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.start-ok" do expect(Protocol::Connection::StartOk.name).to eql("connection.start-ok") end it "has method id equal to 11" do expect(Protocol::Connection::StartOk.method_id).to eq(11) end end describe Protocol::Connection::Secure do it "should be a subclass of Method" do expect(Protocol::Connection::Secure.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.secure" do expect(Protocol::Connection::Secure.name).to eql("connection.secure") end it "has method id equal to 20" do expect(Protocol::Connection::Secure.method_id).to eq(20) end end describe Protocol::Connection::SecureOk do it "should be a subclass of Method" do expect(Protocol::Connection::SecureOk.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.secure-ok" do expect(Protocol::Connection::SecureOk.name).to eql("connection.secure-ok") end it "has method id equal to 21" do expect(Protocol::Connection::SecureOk.method_id).to eq(21) end end describe Protocol::Connection::Tune do it "should be a subclass of Method" do expect(Protocol::Connection::Tune.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.tune" do expect(Protocol::Connection::Tune.name).to eql("connection.tune") end it "has method id equal to 30" do expect(Protocol::Connection::Tune.method_id).to eq(30) end end describe Protocol::Connection::TuneOk do it "should be a subclass of Method" do expect(Protocol::Connection::TuneOk.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.tune-ok" do expect(Protocol::Connection::TuneOk.name).to eql("connection.tune-ok") end it "has method id equal to 31" do expect(Protocol::Connection::TuneOk.method_id).to eq(31) end describe ".encode" do it do frame = Protocol::Connection::TuneOk.encode(0, 131072, 0) expect(frame.payload).to 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 expect(Protocol::Connection::Open.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.open" do expect(Protocol::Connection::Open.name).to eql("connection.open") end it "has method id equal to 40" do expect(Protocol::Connection::Open.method_id).to eq(40) end end describe Protocol::Connection::OpenOk do it "should be a subclass of Method" do expect(Protocol::Connection::OpenOk.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.open-ok" do expect(Protocol::Connection::OpenOk.name).to eql("connection.open-ok") end it "has method id equal to 41" do expect(Protocol::Connection::OpenOk.method_id).to eq(41) end end describe Protocol::Connection::Close do it "should be a subclass of Method" do expect(Protocol::Connection::Close.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.close" do expect(Protocol::Connection::Close.name).to eql("connection.close") end it "has method id equal to 50" do expect(Protocol::Connection::Close.method_id).to eq(50) end end describe Protocol::Connection::CloseOk do it "should be a subclass of Method" do expect(Protocol::Connection::CloseOk.superclass).to eq(Protocol::Method) end it "should have method name equal to connection.close-ok" do expect(Protocol::Connection::CloseOk.name).to eql("connection.close-ok") end it "has method id equal to 51" do expect(Protocol::Connection::CloseOk.method_id).to eq(51) end end end describe Protocol::Channel do it "should be a subclass of Class" do expect(Protocol::Channel.superclass).to eq(Protocol::Class) end it "should have name equal to channel" do expect(Protocol::Channel.name).to eql("channel") end it "has method id equal to 20" do expect(Protocol::Channel.method_id).to eq(20) end describe Protocol::Channel::Open do it "should be a subclass of Method" do expect(Protocol::Channel::Open.superclass).to eq(Protocol::Method) end it "should have method name equal to channel.open" do expect(Protocol::Channel::Open.name).to eql("channel.open") end it "has method id equal to 10" do expect(Protocol::Channel::Open.method_id).to eq(10) end end describe Protocol::Channel::OpenOk do it "should be a subclass of Method" do expect(Protocol::Channel::OpenOk.superclass).to eq(Protocol::Method) end it "should have method name equal to channel.open-ok" do expect(Protocol::Channel::OpenOk.name).to eql("channel.open-ok") end it "has method id equal to 11" do expect(Protocol::Channel::OpenOk.method_id).to eq(11) end end describe Protocol::Channel::Flow do it "should be a subclass of Method" do expect(Protocol::Channel::Flow.superclass).to eq(Protocol::Method) end it "should have method name equal to channel.flow" do expect(Protocol::Channel::Flow.name).to eql("channel.flow") end it "has method id equal to 20" do expect(Protocol::Channel::Flow.method_id).to eq(20) end end describe Protocol::Channel::FlowOk do it "should be a subclass of Method" do expect(Protocol::Channel::FlowOk.superclass).to eq(Protocol::Method) end it "should have method name equal to channel.flow-ok" do expect(Protocol::Channel::FlowOk.name).to eql("channel.flow-ok") end it "has method id equal to 21" do expect(Protocol::Channel::FlowOk.method_id).to eq(21) end end describe Protocol::Channel::Close do it "should be a subclass of Method" do expect(Protocol::Channel::Close.superclass).to eq(Protocol::Method) end it "should have method name equal to channel.close" do expect(Protocol::Channel::Close.name).to eql("channel.close") end it "has method id equal to 40" do expect(Protocol::Channel::Close.method_id).to eq(40) end end describe Protocol::Channel::CloseOk do it "should be a subclass of Method" do expect(Protocol::Channel::CloseOk.superclass).to eq(Protocol::Method) end it "should have method name equal to channel.close-ok" do expect(Protocol::Channel::CloseOk.name).to eql("channel.close-ok") end it "has method id equal to 41" do expect(Protocol::Channel::CloseOk.method_id).to eq(41) end end end describe Protocol::Exchange do it "should be a subclass of Class" do expect(Protocol::Exchange.superclass).to eq(Protocol::Class) end it "should have name equal to exchange" do expect(Protocol::Exchange.name).to eql("exchange") end it "has method id equal to 40" do expect(Protocol::Exchange.method_id).to eq(40) end describe Protocol::Exchange::Declare do it "should be a subclass of Method" do expect(Protocol::Exchange::Declare.superclass).to eq(Protocol::Method) end it "should have method name equal to exchange.declare" do expect(Protocol::Exchange::Declare.name).to eql("exchange.declare") end it "has method id equal to 10" do expect(Protocol::Exchange::Declare.method_id).to eq(10) end end describe Protocol::Exchange::DeclareOk do it "should be a subclass of Method" do expect(Protocol::Exchange::DeclareOk.superclass).to eq(Protocol::Method) end it "should have method name equal to exchange.declare-ok" do expect(Protocol::Exchange::DeclareOk.name).to eql("exchange.declare-ok") end it "has method id equal to 11" do expect(Protocol::Exchange::DeclareOk.method_id).to eq(11) end end describe Protocol::Exchange::Delete do it "should be a subclass of Method" do expect(Protocol::Exchange::Delete.superclass).to eq(Protocol::Method) end it "should have method name equal to exchange.delete" do expect(Protocol::Exchange::Delete.name).to eql("exchange.delete") end it "has method id equal to 20" do expect(Protocol::Exchange::Delete.method_id).to eq(20) end end describe Protocol::Exchange::DeleteOk do it "should be a subclass of Method" do expect(Protocol::Exchange::DeleteOk.superclass).to eq(Protocol::Method) end it "should have method name equal to exchange.delete-ok" do expect(Protocol::Exchange::DeleteOk.name).to eql("exchange.delete-ok") end it "has method id equal to 21" do expect(Protocol::Exchange::DeleteOk.method_id).to eq(21) end end describe Protocol::Exchange::Bind do it "should be a subclass of Method" do expect(Protocol::Exchange::Bind.superclass).to eq(Protocol::Method) end it "should have method name equal to exchange.bind" do expect(Protocol::Exchange::Bind.name).to eql("exchange.bind") end it "has method id equal to 30" do expect(Protocol::Exchange::Bind.method_id).to eq(30) end end describe Protocol::Exchange::BindOk do it "should be a subclass of Method" do expect(Protocol::Exchange::BindOk.superclass).to eq(Protocol::Method) end it "should have method name equal to exchange.bind-ok" do expect(Protocol::Exchange::BindOk.name).to eql("exchange.bind-ok") end it "has method id equal to 31" do expect(Protocol::Exchange::BindOk.method_id).to eq(31) end end describe Protocol::Exchange::Unbind do it "should be a subclass of Method" do expect(Protocol::Exchange::Unbind.superclass).to eq(Protocol::Method) end it "should have method name equal to exchange.unbind" do expect(Protocol::Exchange::Unbind.name).to eql("exchange.unbind") end it "has method id equal to 40" do expect(Protocol::Exchange::Unbind.method_id).to eq(40) end end describe Protocol::Exchange::UnbindOk do it "should be a subclass of Method" do expect(Protocol::Exchange::UnbindOk.superclass).to eq(Protocol::Method) end it "should have method name equal to exchange.unbind-ok" do expect(Protocol::Exchange::UnbindOk.name).to eql("exchange.unbind-ok") end it "has method id equal to 51" do expect(Protocol::Exchange::UnbindOk.method_id).to eq(51) end end end describe Protocol::Queue do it "should be a subclass of Class" do expect(Protocol::Queue.superclass).to eq(Protocol::Class) end it "should have name equal to queue" do expect(Protocol::Queue.name).to eql("queue") end it "has method id equal to 50" do expect(Protocol::Queue.method_id).to eq(50) end describe Protocol::Queue::Declare do it "should be a subclass of Method" do expect(Protocol::Queue::Declare.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.declare" do expect(Protocol::Queue::Declare.name).to eql("queue.declare") end it "has method id equal to 10" do expect(Protocol::Queue::Declare.method_id).to eq(10) end end describe Protocol::Queue::DeclareOk do it "should be a subclass of Method" do expect(Protocol::Queue::DeclareOk.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.declare-ok" do expect(Protocol::Queue::DeclareOk.name).to eql("queue.declare-ok") end it "has method id equal to 11" do expect(Protocol::Queue::DeclareOk.method_id).to eq(11) end end describe Protocol::Queue::Bind do it "should be a subclass of Method" do expect(Protocol::Queue::Bind.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.bind" do expect(Protocol::Queue::Bind.name).to eql("queue.bind") end it "has method id equal to 20" do expect(Protocol::Queue::Bind.method_id).to eq(20) end end describe Protocol::Queue::BindOk do it "should be a subclass of Method" do expect(Protocol::Queue::BindOk.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.bind-ok" do expect(Protocol::Queue::BindOk.name).to eql("queue.bind-ok") end it "has method id equal to 21" do expect(Protocol::Queue::BindOk.method_id).to eq(21) end end describe Protocol::Queue::Purge do it "should be a subclass of Method" do expect(Protocol::Queue::Purge.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.purge" do expect(Protocol::Queue::Purge.name).to eql("queue.purge") end it "has method id equal to 30" do expect(Protocol::Queue::Purge.method_id).to eq(30) end end describe Protocol::Queue::PurgeOk do it "should be a subclass of Method" do expect(Protocol::Queue::PurgeOk.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.purge-ok" do expect(Protocol::Queue::PurgeOk.name).to eql("queue.purge-ok") end it "has method id equal to 31" do expect(Protocol::Queue::PurgeOk.method_id).to eq(31) end end describe Protocol::Queue::Delete do it "should be a subclass of Method" do expect(Protocol::Queue::Delete.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.delete" do expect(Protocol::Queue::Delete.name).to eql("queue.delete") end it "has method id equal to 40" do expect(Protocol::Queue::Delete.method_id).to eq(40) end end describe Protocol::Queue::DeleteOk do it "should be a subclass of Method" do expect(Protocol::Queue::DeleteOk.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.delete-ok" do expect(Protocol::Queue::DeleteOk.name).to eql("queue.delete-ok") end it "has method id equal to 41" do expect(Protocol::Queue::DeleteOk.method_id).to eq(41) end end describe Protocol::Queue::Unbind do it "should be a subclass of Method" do expect(Protocol::Queue::Unbind.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.unbind" do expect(Protocol::Queue::Unbind.name).to eql("queue.unbind") end it "has method id equal to 50" do expect(Protocol::Queue::Unbind.method_id).to eq(50) end end describe Protocol::Queue::UnbindOk do it "should be a subclass of Method" do expect(Protocol::Queue::UnbindOk.superclass).to eq(Protocol::Method) end it "should have method name equal to queue.unbind-ok" do expect(Protocol::Queue::UnbindOk.name).to eql("queue.unbind-ok") end it "has method id equal to 51" do expect(Protocol::Queue::UnbindOk.method_id).to eq(51) end end end describe Protocol::Basic do it "should be a subclass of Class" do expect(Protocol::Basic.superclass).to eq(Protocol::Class) end it "should have name equal to basic" do expect(Protocol::Basic.name).to eql("basic") end it "has method id equal to 60" do expect(Protocol::Basic.method_id).to eq(60) end describe Protocol::Basic::Qos do it "should be a subclass of Method" do expect(Protocol::Basic::Qos.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.qos" do expect(Protocol::Basic::Qos.name).to eql("basic.qos") end it "has method id equal to 10" do expect(Protocol::Basic::Qos.method_id).to eq(10) end end describe Protocol::Basic::QosOk do it "should be a subclass of Method" do expect(Protocol::Basic::QosOk.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.qos-ok" do expect(Protocol::Basic::QosOk.name).to eql("basic.qos-ok") end it "has method id equal to 11" do expect(Protocol::Basic::QosOk.method_id).to eq(11) end end describe Protocol::Basic::Consume do it "should be a subclass of Method" do expect(Protocol::Basic::Consume.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.consume" do expect(Protocol::Basic::Consume.name).to eql("basic.consume") end it "has method id equal to 20" do expect(Protocol::Basic::Consume.method_id).to eq(20) end end describe Protocol::Basic::ConsumeOk do it "should be a subclass of Method" do expect(Protocol::Basic::ConsumeOk.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.consume-ok" do expect(Protocol::Basic::ConsumeOk.name).to eql("basic.consume-ok") end it "has method id equal to 21" do expect(Protocol::Basic::ConsumeOk.method_id).to eq(21) end end describe Protocol::Basic::Cancel do it "should be a subclass of Method" do expect(Protocol::Basic::Cancel.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.cancel" do expect(Protocol::Basic::Cancel.name).to eql("basic.cancel") end it "has method id equal to 30" do expect(Protocol::Basic::Cancel.method_id).to eq(30) end end describe Protocol::Basic::CancelOk do it "should be a subclass of Method" do expect(Protocol::Basic::CancelOk.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.cancel-ok" do expect(Protocol::Basic::CancelOk.name).to eql("basic.cancel-ok") end it "has method id equal to 31" do expect(Protocol::Basic::CancelOk.method_id).to eq(31) end end describe Protocol::Basic::Publish do it "should be a subclass of Method" do expect(Protocol::Basic::Publish.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.publish" do expect(Protocol::Basic::Publish.name).to eql("basic.publish") end it "has method id equal to 40" do expect(Protocol::Basic::Publish.method_id).to eq(40) end end describe Protocol::Basic::Return do it "should be a subclass of Method" do expect(Protocol::Basic::Return.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.return" do expect(Protocol::Basic::Return.name).to eql("basic.return") end it "has method id equal to 50" do expect(Protocol::Basic::Return.method_id).to eq(50) end end describe Protocol::Basic::Deliver do it "should be a subclass of Method" do expect(Protocol::Basic::Deliver.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.deliver" do expect(Protocol::Basic::Deliver.name).to eql("basic.deliver") end it "has method id equal to 60" do expect(Protocol::Basic::Deliver.method_id).to eq(60) end end describe Protocol::Basic::Get do it "should be a subclass of Method" do expect(Protocol::Basic::Get.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.get" do expect(Protocol::Basic::Get.name).to eql("basic.get") end it "has method id equal to 70" do expect(Protocol::Basic::Get.method_id).to eq(70) end end describe Protocol::Basic::GetOk do it "should be a subclass of Method" do expect(Protocol::Basic::GetOk.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.get-ok" do expect(Protocol::Basic::GetOk.name).to eql("basic.get-ok") end it "has method id equal to 71" do expect(Protocol::Basic::GetOk.method_id).to eq(71) end end describe Protocol::Basic::GetEmpty do it "should be a subclass of Method" do expect(Protocol::Basic::GetEmpty.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.get-empty" do expect(Protocol::Basic::GetEmpty.name).to eql("basic.get-empty") end it "has method id equal to 72" do expect(Protocol::Basic::GetEmpty.method_id).to eq(72) end end describe Protocol::Basic::Ack do it "should be a subclass of Method" do expect(Protocol::Basic::Ack.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.ack" do expect(Protocol::Basic::Ack.name).to eql("basic.ack") end it "has method id equal to 80" do expect(Protocol::Basic::Ack.method_id).to eq(80) end end describe Protocol::Basic::Reject do it "should be a subclass of Method" do expect(Protocol::Basic::Reject.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.reject" do expect(Protocol::Basic::Reject.name).to eql("basic.reject") end it "has method id equal to 90" do expect(Protocol::Basic::Reject.method_id).to eq(90) end end describe Protocol::Basic::RecoverAsync do it "should be a subclass of Method" do expect(Protocol::Basic::RecoverAsync.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.recover-async" do expect(Protocol::Basic::RecoverAsync.name).to eql("basic.recover-async") end it "has method id equal to 100" do expect(Protocol::Basic::RecoverAsync.method_id).to eq(100) end end describe Protocol::Basic::Recover do it "should be a subclass of Method" do expect(Protocol::Basic::Recover.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.recover" do expect(Protocol::Basic::Recover.name).to eql("basic.recover") end it "has method id equal to 110" do expect(Protocol::Basic::Recover.method_id).to eq(110) end end describe Protocol::Basic::RecoverOk do it "should be a subclass of Method" do expect(Protocol::Basic::RecoverOk.superclass).to eq(Protocol::Method) end it "should have method name equal to basic.recover-ok" do expect(Protocol::Basic::RecoverOk.name).to eql("basic.recover-ok") end it "has method id equal to 111" do expect(Protocol::Basic::RecoverOk.method_id).to eq(111) end end end end end amq-protocol-2.0.1/spec/amq/uri_parsing_spec.rb0000644000004100000410000000575312637243075021573 0ustar www-datawww-data# encoding: utf-8 require "spec_helper" require "amq/uri" describe AMQ::URI, ".parse" do context "when schema is not one of [amqp, amqps]" do it "raises ArgumentError" do expect { described_class.parse_amqp_url("http://dev.rabbitmq.com") }.to raise_error(ArgumentError, /amqp or amqps schema/) end end it "handles amqp:// URIs w/o path part" do val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com") expect(val[:vhost]).to be_nil # in this case, default / will be used expect(val[:host]).to eq("dev.rabbitmq.com") expect(val[:port]).to eq(5672) expect(val[:scheme]).to eq("amqp") expect(val[:ssl]).to be_falsey end it "handles amqps:// URIs w/o path part" do val = described_class.parse_amqp_url("amqps://dev.rabbitmq.com") expect(val[:vhost]).to be_nil expect(val[:host]).to eq("dev.rabbitmq.com") expect(val[:port]).to eq(5671) expect(val[:scheme]).to eq("amqps") expect(val[:ssl]).to be_truthy end context "when URI ends in a slash" do it "parses vhost as an empty string" do val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/") expect(val[:host]).to eq("dev.rabbitmq.com") expect(val[:port]).to eq(5672) expect(val[:scheme]).to eq("amqp") expect(val[:ssl]).to be_falsey expect(val[:vhost]).to eq("") end end context "when URI ends in /%2Fvault" do it "parses vhost as /vault" do val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/%2Fvault") expect(val[:host]).to eq("dev.rabbitmq.com") expect(val[:port]).to eq(5672) expect(val[:scheme]).to eq("amqp") expect(val[:ssl]).to be_falsey expect(val[:vhost]).to eq("/vault") end end context "when URI is amqp://dev.rabbitmq.com/a.path.without.slashes" do it "parses vhost as a.path.without.slashes" do val = described_class.parse_amqp_url("amqp://dev.rabbitmq.com/a.path.without.slashes") expect(val[:host]).to eq("dev.rabbitmq.com") expect(val[:port]).to eq(5672) expect(val[:scheme]).to eq("amqp") expect(val[:ssl]).to be_falsey expect(val[:vhost]).to eq("a.path.without.slashes") end end context "when URI is amqp://dev.rabbitmq.com/a/path/with/slashes" do it "raises an ArgumentError" do expect { described_class.parse_amqp_url("amqp://dev.rabbitmq.com/a/path/with/slashes") }.to raise_error(ArgumentError) end end context "when URI has username:password, for instance, amqp://hedgehog:t0ps3kr3t@hub.megacorp.internal" do it "parses them out" do val = described_class.parse_amqp_url("amqp://hedgehog:t0ps3kr3t@hub.megacorp.internal") expect(val[:host]).to eq("hub.megacorp.internal") expect(val[:port]).to eq(5672) expect(val[:scheme]).to eq("amqp") expect(val[:ssl]).to be_falsey expect(val[:user]).to eq("hedgehog") expect(val[:pass]).to eq("t0ps3kr3t") expect(val[:vhost]).to be_nil # in this case, default / will be used end end end amq-protocol-2.0.1/spec/amq/settings_spec.rb0000644000004100000410000000127712637243075021106 0ustar www-datawww-data# encoding: utf-8 require "spec_helper" require "amq/settings" describe AMQ::Settings do describe ".default" do it "should provide some default values" do expect(AMQ::Settings.default).to_not be_nil expect(AMQ::Settings.default[:host]).to_not be_nil end end describe ".configure(&block)" do it "should merge custom settings with default settings" do settings = AMQ::Settings.configure(:host => "tagadab") expect(settings[:host]).to eql("tagadab") end it "should merge custom settings from AMQP URL with default settings" do settings = AMQ::Settings.configure("amqp://tagadab") expect(settings[:host]).to eql("tagadab") end end end amq-protocol-2.0.1/spec/spec_helper.rb0000644000004100000410000000062012637243075017736 0ustar www-datawww-data# encoding: binary require 'bundler/setup' require 'rspec' require 'rspec/its' require "effin_utf8" 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}" RSpec.configure do |config| config.include AMQ::Protocol config.warnings = true end amq-protocol-2.0.1/.travis.yml0000644000004100000410000000034612637243075016304 0ustar www-datawww-datalanguage: ruby bundler_args: --without development script: "bundle exec rspec spec" rvm: - 2.2 - 2.1 - 2.0 - ruby-head notifications: recipients: - michael@rabbitmq.com matrix: allow_failures: - rvm: ruby-head amq-protocol-2.0.1/lib/0000755000004100000410000000000012637243075014736 5ustar www-datawww-dataamq-protocol-2.0.1/lib/amq/0000755000004100000410000000000012637243075015514 5ustar www-datawww-dataamq-protocol-2.0.1/lib/amq/protocol.rb0000644000004100000410000000012612637243075017701 0ustar www-datawww-data# -*- coding: utf-8 -*- require "amq/protocol/version" require "amq/protocol/client" amq-protocol-2.0.1/lib/amq/bit_set.rb0000644000004100000410000000540312637243075017474 0ustar www-datawww-data# encoding: utf-8 module AMQ # Very minimalistic, pure Ruby implementation of bit set. Inspired by java.util.BitSet, # although significantly smaller in scope. # # Originally part of amqp gem. Extracted to make it possible for Bunny to use it. class BitSet attr_reader :words_in_use # # API # ADDRESS_BITS_PER_WORD = 6 BITS_PER_WORD = (1 << ADDRESS_BITS_PER_WORD) WORD_MASK = 0xffffffffffffffff # @param [Integer] Number of bits in the set # @api public def initialize(nbits) @nbits = nbits self.init_words(nbits) end # initialize(nbits) # Sets (flags) given bit. This method allows bits to be set more than once in a row, no exception will be raised. # # @param [Integer] A bit to set # @api public def set(i) check_range(i) w = self.word_index(i) result = @words[w] |= (1 << (i % BITS_PER_WORD)) result end # set(i) # Fetches flag value for given bit. # # @param [Integer] A bit to fetch # @return [Boolean] true if given bit is set, false otherwise # @api public def get(i) check_range(i) w = self.word_index(i) (@words[w] & (1 << i % BITS_PER_WORD)) != 0 end # get(i) alias [] get # Unsets (unflags) given bit. This method allows bits to be unset more than once in a row, no exception will be raised. # # @param [Integer] A bit to unset # @api public def unset(i) check_range(i) w = self.word_index(i) return if w.nil? result = @words[w] &= ~(1 << i % BITS_PER_WORD) result end # unset(i) # Clears all bits in the set # @api public def clear self.init_words(@nbits) end # clear def next_clear_bit() @words.each_with_index do |word, i| if word == WORD_MASK next end return i * BITS_PER_WORD + BitSet.number_of_trailing_ones(word) end -1 end # next_clear_bit def to_s result = "" @words.each do |w| result += w.to_s(2).rjust(BITS_PER_WORD,'0') + ":" end result end # to_s # # Implementation # # @private def self.number_of_trailing_ones(num) 0.upto(BITS_PER_WORD) do |bit| return bit if num[bit] == 0 end BITS_PER_WORD end # number_of_trailing_ones # @private def word_index(i) i >> ADDRESS_BITS_PER_WORD end # word_index protected # @private def init_words(nbits) n = word_index(nbits-1) + 1 @words = Array.new(n) { 0 } end # init_words def check_range(i) if i < 0 || i >= @nbits raise IndexError.new("Cannot access bit #{i} from a BitSet with #{@nbits} bits") end end # check_range end # BitSet end # AMQ amq-protocol-2.0.1/lib/amq/protocol/0000755000004100000410000000000012637243075017355 5ustar www-datawww-dataamq-protocol-2.0.1/lib/amq/protocol/table_value_decoder.rb0000644000004100000410000001311412637243075023652 0ustar www-datawww-data# encoding: binary require "amq/endianness" require "amq/protocol/client" require "amq/protocol/type_constants" require "amq/protocol/table" require "amq/protocol/float_32bit" 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_BYTE_ARRAY # Ruby doesn't have a direct counterpart to # ByteBuffer or byte[], so using a string feels # more appropriate than an array of fixnums 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_BYTE then v, offset = decode_byte(data, offset) v when TYPE_SIGNED_16BIT then v, offset = decode_short(data, offset) v when TYPE_SIGNED_64BIT then v, offset = decode_long(data, offset) v 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 in a table value: #{type.inspect}, do not know how to decode!") 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) if AMQ::Endianness.big_endian? def self.decode_long(data, offset) v = data.slice(offset, 8).unpack(PACK_INT64) offset += 8 [v, offset] end else def self.decode_long(data, offset) slice = data.slice(offset, 8).bytes.to_a.reverse.map(&:chr).join v = slice.unpack(PACK_INT64).first offset += 8 [v, offset] end end 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) # Decodes/Converts a byte value from the data at the provided offset. # # @param [Array] data - A big-endian ordered array of bytes. # @param [Fixnum] offset - The offset which bytes the byte is consumed. # @return [Array] - The Fixnum value and new offset pair. def self.decode_byte(data, offset) [data.slice(offset, 1).unpack(PACK_CHAR).first, offset += 1] end def self.decode_short(data, offset) v = AMQ::Hacks.unpack_int16_big_endian(data.slice(offset, 2)).first offset += 2 [v, offset] end end # TableValueDecoder end # Protocol end # AMQ amq-protocol-2.0.1/lib/amq/protocol/float_32bit.rb0000644000004100000410000000046412637243075022016 0ustar www-datawww-datamodule AMQ module Protocol # Allows distinguishing between 32-bit and 64-bit floats in Ruby. # Useful in cases when RabbitMQ plugins encode # values as 32 bit numbers. class Float32Bit attr_reader :value def initialize(value) @value = value end end end end amq-protocol-2.0.1/lib/amq/protocol/table.rb0000644000004100000410000001115012637243075020767 0ustar www-datawww-data# encoding: binary require "amq/protocol/client" require "amq/protocol/type_constants" require "amq/protocol/table_value_encoder" require "amq/protocol/table_value_decoder" 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).force_encoding(buffer.encoding) end end [buffer.bytesize].pack(PACK_UINT32).force_encoding(buffer.encoding) + 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_BYTE_ARRAY # Ruby doesn't have a direct counterpart to # ByteBuffer or byte[], so using a string feels # more appropriate than an array of fixnums 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_BYTE then v, offset = TableValueDecoder.decode_byte(data, offset) v when TYPE_SIGNED_16BIT then v, offset = TableValueDecoder.decode_short(data, offset) v when TYPE_SIGNED_64BIT then v, offset = TableValueDecoder.decode_long(data, offset) v 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-2.0.1/lib/amq/protocol/client.rb0000644000004100000410000017120212637243075021163 0ustar www-datawww-data# encoding: binary # THIS IS AN AUTOGENERATED FILE, DO NOT MODIFY # IT DIRECTLY ! FOR CHANGES, PLEASE UPDATE FILES # IN THE ./codegen DIRECTORY OF THE AMQ-PROTOCOL REPOSITORY. require "amq/pack" require "amq/protocol/table" require "amq/protocol/frame" require "amq/protocol/constants" require "amq/protocol/exceptions" module AMQ module Protocol PROTOCOL_VERSION = "0.9.1".freeze PREAMBLE = "AMQP\x00\x00\x09\x01".freeze DEFAULT_PORT = 5672 # @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 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 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? # 8 = 1 + 2 + 4 + 1 # 1 byte of frame type # 2 bytes of channel number # 4 bytes of frame payload length # 1 byte of payload trailer FRAME_END byte limit = frame_size - 8 return [BodyFrame.new(body, channel)] if body.bytesize < limit # Otherwise String#slice on 1.9 will operate with code points, # and we need bytes. MK. body.force_encoding("ASCII-8BIT") if RUBY_VERSION.to_f >= 1.9 array = Array.new while body && !body.empty? payload, body = body[0, limit], body[limit, body.length - limit] array << BodyFrame.new(payload, channel) end array end def self.instantiate(*args, &block) self.new(*args, &block) 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 = @packed_indexes.dup buffer << AMQ::Protocol::Table.encode(client_properties) buffer << mechanism.to_s.bytesize.chr buffer << mechanism.to_s buffer << [response.to_s.bytesize].pack(PACK_UINT32) buffer << response.to_s buffer << locale.to_s.bytesize.chr buffer << locale.to_s 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 = @packed_indexes.dup buffer << [response.to_s.bytesize].pack(PACK_UINT32) buffer << response.to_s 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 = @packed_indexes.dup 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 = @packed_indexes.dup buffer << virtual_host.to_s.bytesize.chr buffer << virtual_host.to_s buffer << capabilities.to_s.bytesize.chr buffer << capabilities.to_s 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 = @packed_indexes.dup buffer << [reply_code].pack(PACK_UINT16) buffer << reply_text.to_s.bytesize.chr buffer << reply_text.to_s 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 = @packed_indexes.dup MethodFrame.new(buffer, channel) end end class Blocked < Protocol::Method @name = "connection.blocked" @method_id = 60 @index = 0x000A003C # 10, 60, 655420 @packed_indexes = [10, 60].pack(PACK_UINT16_X2).freeze # @return def self.decode(data) offset = 0 length = data[offset, 1].unpack(PACK_CHAR).first offset += 1 reason = data[offset, length] offset += length self.new(reason) end attr_reader :reason def initialize(reason) @reason = reason end def self.has_content? false end # @return # [u'reason = EMPTY_STRING'] def self.encode(reason) channel = 0 buffer = @packed_indexes.dup buffer << reason.to_s.bytesize.chr buffer << reason.to_s MethodFrame.new(buffer, channel) end end class Unblocked < Protocol::Method @name = "connection.unblocked" @method_id = 61 @index = 0x000A003D # 10, 61, 655421 @packed_indexes = [10, 61].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 = @packed_indexes.dup 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 = @packed_indexes.dup buffer << out_of_band.to_s.bytesize.chr buffer << out_of_band.to_s 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 = @packed_indexes.dup 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 = @packed_indexes.dup 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 = @packed_indexes.dup buffer << [reply_code].pack(PACK_UINT16) buffer << reply_text.to_s.bytesize.chr buffer << reply_text.to_s 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 = @packed_indexes.dup 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << exchange.to_s.bytesize.chr buffer << exchange.to_s buffer << type.to_s.bytesize.chr buffer << type.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << exchange.to_s.bytesize.chr buffer << exchange.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << destination.to_s.bytesize.chr buffer << destination.to_s buffer << source.to_s.bytesize.chr buffer << source.to_s buffer << routing_key.to_s.bytesize.chr buffer << routing_key.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << destination.to_s.bytesize.chr buffer << destination.to_s buffer << source.to_s.bytesize.chr buffer << source.to_s buffer << routing_key.to_s.bytesize.chr buffer << routing_key.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << queue.to_s.bytesize.chr buffer << queue.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << queue.to_s.bytesize.chr buffer << queue.to_s buffer << exchange.to_s.bytesize.chr buffer << exchange.to_s buffer << routing_key.to_s.bytesize.chr buffer << routing_key.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << queue.to_s.bytesize.chr buffer << queue.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << queue.to_s.bytesize.chr buffer << queue.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << queue.to_s.bytesize.chr buffer << queue.to_s buffer << exchange.to_s.bytesize.chr buffer << exchange.to_s buffer << routing_key.to_s.bytesize.chr buffer << routing_key.to_s 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.to_s.bytesize.chr buffer << value.to_s [0, 0x8000, buffer] end # 1 << 14 def self.encode_content_encoding(value) buffer = '' buffer << value.to_s.bytesize.chr buffer << value.to_s [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.to_s.bytesize.chr buffer << value.to_s [5, 0x0400, buffer] end # 1 << 9 def self.encode_reply_to(value) buffer = '' buffer << value.to_s.bytesize.chr buffer << value.to_s [6, 0x0200, buffer] end # 1 << 8 def self.encode_expiration(value) buffer = '' buffer << value.to_s.bytesize.chr buffer << value.to_s [7, 0x0100, buffer] end # 1 << 7 def self.encode_message_id(value) buffer = '' buffer << value.to_s.bytesize.chr buffer << value.to_s [8, 0x0080, buffer] end # 1 << 6 def self.encode_timestamp(value) buffer = '' buffer << AMQ::Pack.pack_uint64_big_endian(value) [9, 0x0040, buffer] end # 1 << 5 def self.encode_type(value) buffer = '' buffer << value.to_s.bytesize.chr buffer << value.to_s [10, 0x0020, buffer] end # 1 << 4 def self.encode_user_id(value) buffer = '' buffer << value.to_s.bytesize.chr buffer << value.to_s [11, 0x0010, buffer] end # 1 << 3 def self.encode_app_id(value) buffer = '' buffer << value.to_s.bytesize.chr buffer << value.to_s [12, 0x0008, buffer] end # 1 << 2 def self.encode_cluster_id(value) buffer = '' buffer << value.to_s.bytesize.chr buffer << value.to_s [13, 0x0004, buffer] end def self.encode_properties(body_size, properties) pieces, flags = [], 0 properties.reject {|key, value| value.nil?}.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::Pack.pack_uint64_big_endian(body_size) result += [flags].pack(PACK_UINT16) pieces_joined = pieces.join(EMPTY_STRING) result.force_encoding(pieces_joined.encoding) + pieces_joined 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 = @packed_indexes.dup 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << queue.to_s.bytesize.chr buffer << queue.to_s buffer << consumer_tag.to_s.bytesize.chr buffer << consumer_tag.to_s 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 = @packed_indexes.dup buffer << consumer_tag.to_s.bytesize.chr buffer << consumer_tag.to_s 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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << exchange.to_s.bytesize.chr buffer << exchange.to_s buffer << routing_key.to_s.bytesize.chr buffer << routing_key.to_s 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) if properties.nil? or properties.empty? raise RuntimeError.new("Properties can not be empty!") end properties_payload = Basic.encode_properties(payload.bytesize, properties) frames << HeaderFrame.new(properties_payload, channel) frames += self.encode_body(payload, channel, frame_size) frames 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::Pack.unpack_uint64_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 = @packed_indexes.dup buffer << [ticket].pack(PACK_UINT16) buffer << queue.to_s.bytesize.chr buffer << queue.to_s 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::Pack.unpack_uint64_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::Pack.unpack_uint64_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 = @packed_indexes.dup buffer << AMQ::Pack.pack_uint64_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 = @packed_indexes.dup buffer << AMQ::Pack.pack_uint64_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 = @packed_indexes.dup 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 = @packed_indexes.dup 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::Pack.unpack_uint64_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 = @packed_indexes.dup buffer << AMQ::Pack.pack_uint64_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 = @packed_indexes.dup 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 = @packed_indexes.dup 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 = @packed_indexes.dup 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 = @packed_indexes.dup 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 = @packed_indexes.dup 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-2.0.1/lib/amq/protocol/version.rb0000644000004100000410000000011612637243075021365 0ustar www-datawww-datamodule AMQ module Protocol VERSION = "2.0.1" end # Protocol end # AMQ amq-protocol-2.0.1/lib/amq/protocol/type_constants.rb0000644000004100000410000000136212637243075022761 0ustar www-datawww-data# encoding: binary module AMQ module Protocol module TypeConstants TYPE_STRING = 'S'.freeze TYPE_INTEGER = 'I'.freeze TYPE_TIME = 'T'.freeze TYPE_DECIMAL = 'D'.freeze TYPE_HASH = 'F'.freeze TYPE_ARRAY = 'A'.freeze TYPE_BYTE = 'b'.freeze TYPE_64BIT_FLOAT = 'd'.freeze TYPE_32BIT_FLOAT = 'f'.freeze TYPE_SIGNED_64BIT = 'l'.freeze TYPE_SIGNED_16BIT = 's'.freeze TYPE_BOOLEAN = 't'.freeze TYPE_BYTE_ARRAY = 'x'.freeze TYPE_VOID = 'V'.freeze TEN = '10'.freeze BOOLEAN_TRUE = "\x01".freeze BOOLEAN_FALSE = "\x00".freeze end # TypeConstants end # Protocol end # AMQ amq-protocol-2.0.1/lib/amq/protocol/table_value_encoder.rb0000644000004100000410000000643312637243075023672 0ustar www-datawww-data# encoding: binary require "amq/protocol/client" require "amq/protocol/type_constants" require "amq/protocol/table" require "date" require "amq/protocol/float_32bit" 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_SIGNED_64BIT accumulator << [value].pack(PACK_INT64_BE) when AMQ::Protocol::Float32Bit then accumulator << TYPE_32BIT_FLOAT accumulator << [value.value].pack(PACK_32BIT_FLOAT) 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_BE) 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 += 8 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-2.0.1/lib/amq/protocol/constants.rb0000644000004100000410000000117712637243075021724 0ustar www-datawww-datamodule AMQ module Protocol TLS_PORT = 5671 SSL_PORT = 5671 # caching EMPTY_STRING = "".freeze PACK_INT8 = 'c'.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_INT64_BE = 'q>'.freeze PACK_UCHAR_UINT32 = 'CN'.freeze PACK_CHAR_UINT16_UINT32 = 'cnN'.freeze PACK_32BIT_FLOAT = 'f'.freeze PACK_64BIT_FLOAT = 'G'.freeze end end amq-protocol-2.0.1/lib/amq/protocol/frame.rb0000644000004100000410000001350412637243075020777 0ustar www-datawww-data# encoding: binary module AMQ module Protocol 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 def self.encoded_payload(payload) if payload.respond_to?(:force_encoding) && payload.encoding.name != 'BINARY' # Only copy if we have to. payload = payload.dup.force_encoding('BINARY') end payload end # 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_to_array(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? components = [] components << [find_type(type), channel, payload.bytesize].pack(PACK_CHAR_UINT16_UINT32) components << encoded_payload(payload) components << FINAL_OCTET components end def self.encode(type, payload, channel) encode_to_array(type, payload, channel).join 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 || header.empty? 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 # TODO: remove once we are sure none of the clients # uses this method directly # @api private def encode_to_array components = [] components << [self.class.id, @channel, @payload.bytesize].pack(PACK_CHAR_UINT16_UINT32) components << self.class.encoded_payload(@payload) components << FINAL_OCTET components end def encode s = [self.class.id, @channel, @payload.bytesize].pack(PACK_CHAR_UINT16_UINT32) s << self.class.encoded_payload(@payload) s << FINAL_OCTET s 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_uint64_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-2.0.1/lib/amq/protocol/exceptions.rb0000644000004100000410000000307412637243075022067 0ustar www-datawww-datamodule AMQ module Protocol 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 end end amq-protocol-2.0.1/lib/amq/uri.rb0000644000004100000410000000222012637243075016634 0ustar www-datawww-data# encoding: utf-8 require "cgi" require "uri" module AMQ class URI # @private AMQP_PORTS = {"amqp" => 5672, "amqps" => 5671}.freeze def self.parse(connection_string) uri = ::URI.parse(connection_string) raise ArgumentError.new("Connection URI must use amqp or amqps schema (example: amqp://bus.megacorp.internal:5766), learn more at http://bit.ly/ks8MXK") unless %w{amqp amqps}.include?(uri.scheme) opts = {} opts[:scheme] = uri.scheme opts[:user] = ::CGI::unescape(uri.user) if uri.user opts[:pass] = ::CGI::unescape(uri.password) if uri.password opts[:host] = uri.host if uri.host opts[:port] = uri.port || AMQP_PORTS[uri.scheme] opts[:ssl] = uri.scheme.to_s.downcase =~ /amqps/i if uri.path =~ %r{^/(.*)} raise ArgumentError.new("#{uri} has multiple-segment path; please percent-encode any slashes in the vhost name (e.g. /production => %2Fproduction). Learn more at http://bit.ly/amqp-gem-and-connection-uris") if $1.index('/') opts[:vhost] = ::CGI::unescape($1) end opts end def self.parse_amqp_url(s) parse(s) end end end amq-protocol-2.0.1/lib/amq/int_allocator.rb0000644000004100000410000000474012637243075020700 0ustar www-datawww-data# encoding: utf-8 require "amq/bit_set" module AMQ # Simple bitset-based integer allocator, heavily inspired by com.rabbitmq.utility.IntAllocator class # in the RabbitMQ Java client. # # Unlike monotonically incrementing identifier, this allocator is suitable for very long running programs # that aggressively allocate and release channels. class IntAllocator # # API # # @return [Integer] Number of integers in the allocation range attr_reader :number_of_bits # @return [Integer] Upper boundary of the integer range available for allocation attr_reader :hi # @return [Integer] Lower boundary of the integer range available for allocation attr_reader :lo # @param [Integer] lo Lower boundary of the integer range available for allocation # @param [Integer] hi Upper boundary of the integer range available for allocation # @raise [ArgumentError] if upper boundary is not greater than the lower one def initialize(lo, hi) raise ArgumentError.new "upper boundary must be greater than the lower one (given: hi = #{hi}, lo = #{lo})" unless hi > lo @hi = hi @lo = lo @number_of_bits = hi - lo @range = Range.new(1, @number_of_bits) @free_set = BitSet.new(@number_of_bits) end # initialize(hi, lo) # Attempts to allocate next available integer. If allocation succeeds, allocated value is returned. # Otherwise, nil is returned. # # Current implementation of this method is O(n), where n is number of bits in the range available for # allocation. # # @return [Integer] Allocated integer if allocation succeeded. nil otherwise. def allocate if n = @free_set.next_clear_bit if n < @hi - 1 then @free_set.set(n) n + 1 else -1 end else -1 end end # allocate # Releases previously allocated integer. If integer provided as argument was not previously allocated, # this method has no effect. # # @return [NilClass] nil def free(reservation) @free_set.unset(reservation-1) end # free(reservation) alias release free # @return [Boolean] true if provided argument was previously allocated, false otherwise def allocated?(reservation) @free_set.get(reservation-1) end # allocated?(reservation) # Releases the whole allocation range def reset @free_set.clear end # reset protected end # IntAllocator end # AMQ amq-protocol-2.0.1/lib/amq/pack.rb0000644000004100000410000000243712637243075016765 0ustar www-datawww-data# encoding: binary require 'amq/endianness' module AMQ # Implements pack to/unpack from 64bit string in network byte order # compatible with Ruby 1.8+. module Pack UINT64 = "Q".freeze UINT16_BE = "n".freeze INT16 = "c".freeze if Endianness.big_endian? def self.pack_uint64_big_endian(long_long) [long_long].pack(UINT64) end def self.unpack_uint64_big_endian(data) data.unpack(UINT64) end def self.pack_int16_big_endian(short) [long_long].pack(INT16) end def self.unpack_int16_big_endian(data) data.unpack(INT16) end else def self.pack_uint64_big_endian(long_long) result = [long_long].pack(UINT64) result.bytes.to_a.reverse.map(&:chr).join end def self.unpack_uint64_big_endian(data) data = data.bytes.to_a.reverse.map(&:chr).join data.unpack(UINT64) end def self.pack_int16_big_endian(short) result = [long_long].pack(INT16) result.bytes.to_a.reverse.map(&:chr).join end def self.unpack_int16_big_endian(data) value = data.bytes.to_a.map(&:chr).join.unpack(UINT16_BE)[0] [(value & ~(1 << 15)) - (value & (1 << 15))] end end end # Backwards compatibility Hacks = Pack end amq-protocol-2.0.1/lib/amq/settings.rb0000644000004100000410000001070412637243075017703 0ustar www-datawww-data# encoding: utf-8 require "amq/protocol/client" require "amq/uri" module AMQ module Settings # @private AMQPS = "amqps".freeze # Default connection settings used by AMQ clients # # @see AMQ::Client::Settings.configure def self.default @default ||= { # server :host => "127.0.0.1", :port => AMQ::Protocol::DEFAULT_PORT, # login :user => "guest", :pass => "guest", :vhost => "/", # ssl :ssl => false, :frame_max => (128 * 1024), :heartbeat => 0 } end # Merges given configuration parameters with defaults and returns # the result. # # @param [Hash] Configuration parameters to use. # # @option settings [String] :host ("127.0.0.1") Hostname AMQ broker runs on. # @option settings [String] :port (5672) Port AMQ broker listens on. # @option settings [String] :vhost ("/") Virtual host to use. # @option settings [String] :user ("guest") Username to use for authentication. # @option settings [String] :pass ("guest") Password to use for authentication. # @option settings [String] :ssl (false) Should be use TLS (SSL) for connection? # @option settings [String] :timeout (nil) Connection timeout. # @option settings [String] :broker (nil) Broker name (use if you intend to use broker-specific features). # @option settings [Fixnum] :frame_max (131072) Maximum frame size to use. If broker cannot support frames this large, broker's maximum value will be used instead. # # @return [Hash] Merged configuration parameters. def self.configure(settings = nil) case settings when Hash then if username = (settings.delete(:username) || settings.delete(:user)) settings[:user] ||= username end if password = (settings.delete(:password) || settings.delete(:pass)) settings[:pass] ||= password end self.default.merge(settings) when String then settings = self.parse_amqp_url(settings) self.default.merge(settings) when NilClass then self.default end end # Parses AMQP connection URI and returns its components as a hash. # # h2. vhost naming schemes # # It is convenient to be able to specify the AMQP connection # parameters as a URI string, and various "amqp" URI schemes # exist. Unfortunately, there is no standard for these URIs, so # while the schemes share the basic idea, they differ in some # details. This implementation aims to encourage URIs that work # as widely as possible. # # The URI scheme should be "amqp", or "amqps" if SSL is required. # # The host, port, username and password are represented in the # authority component of the URI in the same way as in http URIs. # # The vhost is obtained from the first segment of the path, with the # leading slash removed. The path should contain only a single # segment (i.e, the only slash in it should be the leading one). # If the vhost is to include slashes or other reserved URI # characters, these should be percent-escaped. # # @example How vhost is parsed # # AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com") # => vhost is nil, so default (/) will be used # AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/") # => vhost is an empty string # AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/%2Fvault") # => vhost is /vault # AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/production") # => vhost is production # AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/a.b.c") # => vhost is a.b.c # AMQ::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/foo/bar") # => ArgumentError # # # @param [String] connection_string AMQP connection URI, à la JDBC connection string. For example: amqp://bus.megacorp.internal:5877. # @return [Hash] Connection parameters (:username, :password, :vhost, :host, :port, :ssl) # # @raise [ArgumentError] When connection URI schema is not amqp or amqps, or the path contains multiple segments # # @api public def self.parse_amqp_url(connection_string) AMQ::URI.parse(connection_string) end end end amq-protocol-2.0.1/lib/amq/endianness.rb0000644000004100000410000000031112637243075020163 0ustar www-datawww-datamodule AMQ module Endianness BIG_ENDIAN = ([1].pack("s") == "\x00\x01") def big_endian? BIG_ENDIAN end def little_endian? !BIG_ENDIAN end extend self end end amq-protocol-2.0.1/metadata.yml0000644000004100000410000000545512637243075016504 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: amq-protocol version: !ruby/object:Gem::Version version: 2.0.1 platform: ruby authors: - Jakub Stastny - Michael S. Klishin - Theo Hultberg - Mark Abramov autorequire: bindir: bin cert_chain: [] date: 2015-12-17 00:00:00.000000000 Z dependencies: [] description: |2 amq-protocol is an AMQP 0.9.1 serialization library for Ruby. It is not a client: the library only handles serialization and deserialization. email: - michael.s.klishin@gmail.com executables: [] extensions: [] extra_rdoc_files: - README.md files: - ".gitignore" - ".gitmodules" - ".rspec" - ".travis.yml" - ChangeLog.md - Gemfile - LICENSE - README.md - Rakefile - amq-protocol.gemspec - benchmarks/int_allocator.rb - benchmarks/pure/body_framing_with_256k_payload.rb - benchmarks/pure/body_framing_with_2k_payload.rb - codegen/__init__.py - codegen/amqp_0.9.1_changes.json - codegen/codegen.py - codegen/codegen_helpers.py - codegen/protocol.rb.pytemplate - generate.rb - lib/amq/bit_set.rb - lib/amq/endianness.rb - lib/amq/int_allocator.rb - lib/amq/pack.rb - lib/amq/protocol.rb - lib/amq/protocol/client.rb - lib/amq/protocol/constants.rb - lib/amq/protocol/exceptions.rb - lib/amq/protocol/float_32bit.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 - lib/amq/settings.rb - lib/amq/uri.rb - profiling/README.md - profiling/stackprof/body_framing_with_2k_payload.rb - spec/amq/bit_set_spec.rb - spec/amq/int_allocator_spec.rb - spec/amq/pack_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/constants_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/amq/settings_spec.rb - spec/amq/uri_parsing_spec.rb - spec/spec_helper.rb homepage: http://github.com/ruby-amqp/amq-protocol licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '2.0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: amq-protocol rubygems_version: 2.4.8 signing_key: specification_version: 4 summary: AMQP 0.9.1 encoding & decoding library. test_files: [] has_rdoc: amq-protocol-2.0.1/generate.rb0000755000004100000410000000065612637243075016321 0ustar www-datawww-data#!/usr/bin/env ruby # encoding: utf-8 def sh(*args) system(*args) end extensions = [] spec = "codegen/rabbitmq-codegen/amqp-rabbitmq-0.9.1.json" unless File.exist?(spec) sh "git submodule update --init" end path = "lib/amq/protocol/client.rb" puts "Running ./codegen/codegen.py client #{spec} #{path}" sh "./codegen/codegen.py client #{spec} #{extensions.join(' ')} #{path}" if File.file?(path) sh "ruby -c #{path}" end amq-protocol-2.0.1/profiling/0000755000004100000410000000000012637243075016161 5ustar www-datawww-dataamq-protocol-2.0.1/profiling/stackprof/0000755000004100000410000000000012637243075020155 5ustar www-datawww-dataamq-protocol-2.0.1/profiling/stackprof/body_framing_with_2k_payload.rb0000644000004100000410000000131312637243075026300 0ustar www-datawww-data#!/usr/bin/env ruby # encoding: utf-8 $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib")) require "amq/protocol/client" FRAME_SIZE = 128 * 1024 puts puts "-" * 80 puts "Profiling on #{RUBY_DESCRIPTION}" n = 250_000 # warm up the JIT, etc puts "Doing a warmup run..." 15_000.times { AMQ::Protocol::Method.encode_body("ab" * 1024, 1, FRAME_SIZE) } require 'stackprof' # preallocate ary = Array.new(n) { "ab" * 1024 } puts "Doing main run..." result = StackProf.run(mode: :wall) do n.times { |i| AMQ::Protocol::Method.encode_body(ary[i], 1, FRAME_SIZE) } end File.open('./profiling/dumps/body_framing_with_2k_payload.dump', "w+") do |f| f.write Marshal.dump(result) end amq-protocol-2.0.1/profiling/README.md0000644000004100000410000000051612637243075017442 0ustar www-datawww-data# Profiling Scripts This directory contains profiling scripts. Currently they use [stackprof](https://github.com/tmm1/stackprof) which requires Ruby 2.1+ (preview2 or later). ## Running the Profiler ruby profiling/stackprof/body_framing_with_2k_payload.rb stackprof profiling/dumps/body_framing_with_2k_payload.dump --text amq-protocol-2.0.1/.gitignore0000644000004100000410000000025312637243075016160 0ustar www-datawww-data/*.gem /.rvmrc /.ruby-version tmp *.pyc *.iml .idea /vendor/bundle /vendor/amq-* /coverage Gemfile.lock .rbx/* .Apple* .bundle/* bin/* *.bundle Makefile profiling/dumps/* amq-protocol-2.0.1/LICENSE0000644000004100000410000000220412637243075015173 0ustar www-datawww-dataCopyright (c) 2010 – 2011 Jakub Šťastný aka Botanicus Copyright (c) 2011 – 2015 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-2.0.1/benchmarks/0000755000004100000410000000000012637243075016305 5ustar www-datawww-dataamq-protocol-2.0.1/benchmarks/pure/0000755000004100000410000000000012637243075017260 5ustar www-datawww-dataamq-protocol-2.0.1/benchmarks/pure/body_framing_with_256k_payload.rb0000644000004100000410000000120212637243075025553 0ustar www-datawww-data#!/usr/bin/env ruby # encoding: utf-8 $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib")) require "amq/protocol/client" require "benchmark" FRAME_SIZE = 128 * 1024 puts puts "-" * 80 puts "Benchmarking on #{RUBY_DESCRIPTION}" n = 250_000 # warm up the JIT, etc puts "Doing a warmup run..." 15_000.times { AMQ::Protocol::Method.encode_body("a" * 256 * 1024, 1, FRAME_SIZE) } t = Benchmark.realtime do n.times { AMQ::Protocol::Method.encode_body("a" * 256 * 1024, 1, FRAME_SIZE) } end r = (n.to_f/t.to_f) puts "AMQ::Protocol::Method.encode_body rate: #{(r / 1000).round(2)} KGHz" puts puts "-" * 80 amq-protocol-2.0.1/benchmarks/pure/body_framing_with_2k_payload.rb0000644000004100000410000000117012637243075025404 0ustar www-datawww-data#!/usr/bin/env ruby # encoding: utf-8 $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "lib")) require "amq/protocol/client" require "benchmark" FRAME_SIZE = 128 * 1024 puts puts "-" * 80 puts "Benchmarking on #{RUBY_DESCRIPTION}" n = 250_000 # warm up the JIT, etc puts "Doing a warmup run..." 15_000.times { AMQ::Protocol::Method.encode_body("ab" * 1024, 1, FRAME_SIZE) } t = Benchmark.realtime do n.times { AMQ::Protocol::Method.encode_body("ab" * 1024, 1, FRAME_SIZE) } end r = (n.to_f/t.to_f) puts "AMQ::Protocol::Method.encode_body rate: #{(r / 1000).round(2)} KGHz" puts puts "-" * 80 amq-protocol-2.0.1/benchmarks/int_allocator.rb0000644000004100000410000000127212637243075021466 0ustar www-datawww-data$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib")) require 'amq/int_allocator' require "benchmark" allocator = AMQ::IntAllocator.new(1,65535) mutex = Mutex.new Benchmark.bm do |x| x.report("allocate") do allocator = AMQ::IntAllocator.new(1,65535) 1.upto(65534) do |i| mutex.synchronize do n = allocator.allocate raise 'it be broke' unless n == i end end end x.report("allocate_with_release") do allocator = AMQ::IntAllocator.new(1,65535) 1.upto(65534) do |i| mutex.synchronize do n = allocator.allocate if i % 5 == 0 allocator.release(n) end end end end endamq-protocol-2.0.1/README.md0000644000004100000410000000315712637243075015455 0ustar www-datawww-data# 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 will handle all the serialization needs for you, including RabbitMQ extensions to AMQP 0.9.1. ## Supported Ruby Versions amq-protocol `1.9.2` was the last version to support Ruby 1.8 and 1.9. amq-protocol `2.0.0` and later only supports Ruby 2.0+. ## Installation gem install amq-protocol ## Development Make sure you have Python, pip and the mako templating package installed: pip install mako amq-protocol uses RabbitMQ protocol code generation library that is in Python, so there is some Python involved in the build. To regenerate `lib/amq/protocol/client.rb` from the source (`codegen/*` files), run ./generate.rb To make changes, **do not edit client.rb directly**. Instead, edit the `codegen/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). ## CI Status [![Build Status](https://secure.travis-ci.org/ruby-amqp/amq-protocol.png)](https://travis-ci.org/ruby-amqp/amq-protocol) ## Issues Please report any issues you may find to our [Issue tracker](http://github.com/ruby-amqp/amq-protocol/issues) on GitHub. ## Mailing List Any questions you may have should be sent to the [Ruby AMQP mailing list](http://groups.google.com/group/ruby-amqp). ## License MIT (see LICENSE in the repository root). amq-protocol-2.0.1/.gitmodules0000644000004100000410000000017612637243075016351 0ustar www-datawww-data[submodule "codegen/rabbitmq-codegen"] path = codegen/rabbitmq-codegen url = git://github.com/rabbitmq/rabbitmq-codegen.git amq-protocol-2.0.1/codegen/0000755000004100000410000000000012637243075015574 5ustar www-datawww-dataamq-protocol-2.0.1/codegen/protocol.rb.pytemplate0000644000004100000410000002246112637243075022152 0ustar www-datawww-data# encoding: utf-8 # encoding: binary # THIS IS AN AUTOGENERATED FILE, DO NOT MODIFY # IT DIRECTLY ! FOR CHANGES, PLEASE UPDATE FILES # IN THE ./codegen DIRECTORY OF THE AMQ-PROTOCOL REPOSITORY.<% import codegen_helpers as helpers %><% import re, os, codegen %> require "amq/pack" require "amq/protocol/table" require "amq/protocol/frame" require "amq/protocol/constants" require "amq/protocol/exceptions" 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} # @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 % 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 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? # 8 = 1 + 2 + 4 + 1 # 1 byte of frame type # 2 bytes of channel number # 4 bytes of frame payload length # 1 byte of payload trailer FRAME_END byte limit = frame_size - 8 return [BodyFrame.new(body, channel)] if body.bytesize < limit # Otherwise String#slice on 1.9 will operate with code points, # and we need bytes. MK. body.force_encoding("ASCII-8BIT") if RUBY_VERSION.to_f >= 1.9 array = Array.new while body payload, body = body[0, limit], body[limit, body.length - limit] array << BodyFrame.new(payload, channel) end array end def self.instantiate(*args, &block) self.new(*args, &block) 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 % if klass.name == "basic" : def self.encode_properties(body_size, properties) pieces, flags = [], 0 properties.reject {|key, value| value.nil?}.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::Pack.pack_uint64_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 = @packed_indexes.dup % 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) if properties.nil? or properties.empty? raise RuntimeError.new("Properties can not be empty!") 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) frames % 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-2.0.1/codegen/amqp_0.9.1_changes.json0000644000004100000410000000266412637243075021652 0ustar www-datawww-data{"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-2.0.1/codegen/codegen_helpers.py0000644000004100000410000001351712637243075021303 0ustar www-datawww-data# -*- coding: utf-8 -*- def genSingleEncode(spec, cValue, unresolved_domain): buffer = [] type = spec.resolveDomain(unresolved_domain) if type == 'shortstr': buffer.append("buffer << %s.to_s.bytesize.chr" % (cValue,)) buffer.append("buffer << %s.to_s" % (cValue,)) elif type == 'longstr': buffer.append("buffer << [%s.to_s.bytesize].pack(PACK_UINT32)" % (cValue,)) buffer.append("buffer << %s.to_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::Pack.pack_uint64_big_endian(%s)" % (cValue,)) elif type == 'timestamp': buffer.append("buffer << AMQ::Pack.pack_uint64_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::Pack.unpack_uint64_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("data.to_s") elif type == 'longstr': buffer.append("data.to_s") elif type == 'octet': buffer.append("data.unpack(PACK_INT8).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::Pack.unpack_uint64_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-2.0.1/codegen/codegen.py0000755000004100000410000001060412637243075017556 0ustar www-datawww-data#!/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("codegen", "rabbitmq-codegen")) from amqp_codegen import * try: from mako.template import Template except ImportError: print "Mako isn't installed. Please install mako via pip or similar." 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) 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("codegen/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("codegen/protocol.rb.pytemplate", spec = spec) return main if __name__ == "__main__": do_main_dict({"client": generateMain("client")}) amq-protocol-2.0.1/codegen/__init__.py0000644000004100000410000000000012637243075017673 0ustar www-datawww-data