celldee-bunny 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +43 -0
- data/Rakefile +12 -0
- data/examples/simple.rb +30 -0
- data/lib/amqp/buffer.rb +276 -0
- data/lib/amqp/client.rb +160 -0
- data/lib/amqp/frame.rb +62 -0
- data/lib/amqp/protocol.rb +158 -0
- data/lib/amqp/spec.rb +832 -0
- data/lib/amqp.rb +5 -0
- data/lib/bunny/exchange.rb +49 -0
- data/lib/bunny/header.rb +30 -0
- data/lib/bunny/logger.rb +89 -0
- data/lib/bunny/queue.rb +93 -0
- data/lib/bunny.rb +57 -0
- data/protocol/amqp-0.8.json +617 -0
- data/protocol/amqp-0.8.xml +3908 -0
- data/protocol/codegen.rb +173 -0
- data/spec/bunny_spec.rb +55 -0
- metadata +72 -0
data/lib/amqp.rb
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class Exchange
|
|
2
|
+
|
|
3
|
+
include AMQP
|
|
4
|
+
|
|
5
|
+
attr_reader :client, :type, :name, :opts, :key
|
|
6
|
+
|
|
7
|
+
def initialize(client, type, name, opts = {})
|
|
8
|
+
@client, @type, @name, @opts = client, type, name, opts
|
|
9
|
+
@key = opts[:key]
|
|
10
|
+
|
|
11
|
+
unless name == "amq.#{type}" or name == ''
|
|
12
|
+
client.send_frame(
|
|
13
|
+
Protocol::Exchange::Declare.new(
|
|
14
|
+
{ :exchange => name, :type => type, :nowait => true }.merge(opts)
|
|
15
|
+
)
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def publish(data, opts = {})
|
|
21
|
+
out = []
|
|
22
|
+
|
|
23
|
+
out << Protocol::Basic::Publish.new(
|
|
24
|
+
{ :exchange => name, :routing_key => opts.delete(:key) || key }.merge(opts)
|
|
25
|
+
)
|
|
26
|
+
data = data.to_s
|
|
27
|
+
out << Protocol::Header.new(
|
|
28
|
+
Protocol::Basic,
|
|
29
|
+
data.length, {
|
|
30
|
+
:content_type => 'application/octet-stream',
|
|
31
|
+
:delivery_mode => (opts.delete(:persistent) ? 2 : 1),
|
|
32
|
+
:priority => 0
|
|
33
|
+
}.merge(opts)
|
|
34
|
+
)
|
|
35
|
+
out << Frame::Body.new(data)
|
|
36
|
+
|
|
37
|
+
client.send_frame(*out)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def delete(opts = {})
|
|
41
|
+
client.send_frame(
|
|
42
|
+
Protocol::Exchange::Delete.new({ :exchange => name, :nowait => true }.merge(opts))
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def reset
|
|
47
|
+
initialize(client, type, name, opts)
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/bunny/header.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class Header
|
|
2
|
+
|
|
3
|
+
include AMQP
|
|
4
|
+
|
|
5
|
+
attr_reader :client
|
|
6
|
+
|
|
7
|
+
def initialize(client, header_obj)
|
|
8
|
+
@client = client
|
|
9
|
+
@header = header_obj
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Acknowledges the receipt of this message with the server.
|
|
13
|
+
def ack
|
|
14
|
+
client.send(Protocol::Basic::Ack.new(:delivery_tag => properties[:delivery_tag]))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Reject this message (XXX currently unimplemented in rabbitmq)
|
|
18
|
+
# * :requeue => true | false (default false)
|
|
19
|
+
def reject(opts = {})
|
|
20
|
+
client.send(Protocol::Basic::Reject.new(opts.merge(:delivery_tag => properties[:delivery_tag])))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def method_missing(meth, *args, &blk)
|
|
24
|
+
@header.send(meth, *args, &blk)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def inspect
|
|
28
|
+
@header.inspect
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/bunny/logger.rb
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
class MQ
|
|
2
|
+
class Logger
|
|
3
|
+
def initialize *args, &block
|
|
4
|
+
opts = args.pop if args.last.is_a? Hash
|
|
5
|
+
opts ||= {}
|
|
6
|
+
|
|
7
|
+
printer(block) if block
|
|
8
|
+
|
|
9
|
+
@prop = opts
|
|
10
|
+
@tags = ([:timestamp] + args).uniq
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :prop
|
|
14
|
+
alias :base :prop
|
|
15
|
+
|
|
16
|
+
def log severity, *args
|
|
17
|
+
opts = args.pop if args.last.is_a? Hash and args.size != 1
|
|
18
|
+
opts ||= {}
|
|
19
|
+
opts = @prop.clone.update(opts)
|
|
20
|
+
|
|
21
|
+
data = args.shift
|
|
22
|
+
|
|
23
|
+
data = {:type => :exception,
|
|
24
|
+
:name => data.class.to_s.intern,
|
|
25
|
+
:backtrace => data.backtrace,
|
|
26
|
+
:message => data.message} if data.is_a? Exception
|
|
27
|
+
|
|
28
|
+
(@tags + args).each do |tag|
|
|
29
|
+
tag = tag.to_sym
|
|
30
|
+
case tag
|
|
31
|
+
when :timestamp
|
|
32
|
+
opts.update :timestamp => Time.now
|
|
33
|
+
when :hostname
|
|
34
|
+
@hostname ||= { :hostname => `hostname`.strip }
|
|
35
|
+
opts.update @hostname
|
|
36
|
+
when :process
|
|
37
|
+
@process_id ||= { :process_id => Process.pid,
|
|
38
|
+
:process_name => $0,
|
|
39
|
+
:process_parent_id => Process.ppid,
|
|
40
|
+
:thread_id => Thread.current.object_id }
|
|
41
|
+
opts.update :process => @process_id
|
|
42
|
+
else
|
|
43
|
+
(opts[:tags] ||= []) << tag
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
opts.update(:severity => severity,
|
|
48
|
+
:msg => data)
|
|
49
|
+
|
|
50
|
+
print(opts)
|
|
51
|
+
unless Logger.disabled?
|
|
52
|
+
MQ.fanout('logging', :durable => true).publish Marshal.dump(opts)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
opts
|
|
56
|
+
end
|
|
57
|
+
alias :method_missing :log
|
|
58
|
+
|
|
59
|
+
def print data = nil, &block
|
|
60
|
+
if block
|
|
61
|
+
@printer = block
|
|
62
|
+
elsif data.is_a? Proc
|
|
63
|
+
@printer = data
|
|
64
|
+
elsif data
|
|
65
|
+
(pr = @printer || self.class.printer) and pr.call(data)
|
|
66
|
+
else
|
|
67
|
+
@printer
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
alias :printer :print
|
|
71
|
+
|
|
72
|
+
def self.printer &block
|
|
73
|
+
@printer = block if block
|
|
74
|
+
@printer
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.disabled?
|
|
78
|
+
!!@disabled
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.enable
|
|
82
|
+
@disabled = false
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.disable
|
|
86
|
+
@disabled = true
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/bunny/queue.rb
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
class Queue
|
|
2
|
+
|
|
3
|
+
include AMQP
|
|
4
|
+
|
|
5
|
+
attr_reader :name, :client
|
|
6
|
+
attr_accessor :delivery_tag
|
|
7
|
+
|
|
8
|
+
def initialize(client, name, opts = {})
|
|
9
|
+
@client = client
|
|
10
|
+
@opts = opts
|
|
11
|
+
@name = name
|
|
12
|
+
client.send_frame(
|
|
13
|
+
Protocol::Queue::Declare.new({ :queue => name, :nowait => true }.merge(opts))
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def pop(opts = {})
|
|
18
|
+
self.delivery_tag = nil
|
|
19
|
+
client.send_frame(
|
|
20
|
+
Protocol::Basic::Get.new({ :queue => name, :consumer_tag => name, :no_ack => !opts.delete(:ack), :nowait => true }.merge(opts))
|
|
21
|
+
)
|
|
22
|
+
method = client.next_method
|
|
23
|
+
return unless method.is_a?(Protocol::Basic::GetOk)
|
|
24
|
+
|
|
25
|
+
self.delivery_tag = method.delivery_tag
|
|
26
|
+
|
|
27
|
+
header = client.next_payload
|
|
28
|
+
msg = client.next_payload
|
|
29
|
+
raise 'unexpected length' if msg.length < header.size
|
|
30
|
+
|
|
31
|
+
msg
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def ack
|
|
35
|
+
client.send_frame(
|
|
36
|
+
Protocol::Basic::Ack.new(:delivery_tag => delivery_tag)
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def publish(data, opts = {})
|
|
41
|
+
exchange.publish(data, opts)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def message_count
|
|
45
|
+
status.first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def consumer_count
|
|
49
|
+
status.last
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def status(opts = {}, &blk)
|
|
53
|
+
client.send_frame(
|
|
54
|
+
Protocol::Queue::Declare.new({ :queue => name, :passive => true }.merge(opts))
|
|
55
|
+
)
|
|
56
|
+
method = client.next_method
|
|
57
|
+
[method.message_count, method.consumer_count]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def bind(exchange, opts = {})
|
|
61
|
+
exchange = exchange.respond_to?(:name) ? exchange.name : exchange
|
|
62
|
+
bindings[exchange] = opts
|
|
63
|
+
client.send_frame(
|
|
64
|
+
Protocol::Queue::Bind.new({ :queue => name, :exchange => exchange, :routing_key => opts.delete(:key), :nowait => true }.merge(opts))
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def unbind(exchange, opts = {})
|
|
69
|
+
exchange = exchange.respond_to?(:name) ? exchange.name : exchange
|
|
70
|
+
bindings.delete(exchange)
|
|
71
|
+
|
|
72
|
+
client.send_frame(
|
|
73
|
+
Protocol::Queue::Unbind.new({
|
|
74
|
+
:queue => name, :exchange => exchange, :routing_key => opts.delete(:key), :nowait => true }.merge(opts)
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def delete(opts = {})
|
|
80
|
+
client.send_frame(
|
|
81
|
+
Protocol::Queue::Delete.new({ :queue => name, :nowait => true }.merge(opts))
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
def exchange
|
|
87
|
+
@exchange ||= Exchange.new(client, :direct, '', :key => name)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def bindings
|
|
91
|
+
@bindings ||= {}
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/bunny.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
|
2
|
+
|
|
3
|
+
%w[socket thread timeout amqp].each do |file|
|
|
4
|
+
require file
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
%w[ exchange queue header ].each do |file|
|
|
8
|
+
require "bunny/#{file}"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class Bunny
|
|
12
|
+
|
|
13
|
+
attr_reader :client
|
|
14
|
+
|
|
15
|
+
class Error < StandardError; end
|
|
16
|
+
|
|
17
|
+
def initialize(opts = {})
|
|
18
|
+
@client = AMQP::Client.new(opts)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def start
|
|
22
|
+
client.start_session
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def status
|
|
26
|
+
client.status
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def queue(name, opts = {})
|
|
30
|
+
queues[name] ||= Queue.new(client, name, opts)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def stop
|
|
34
|
+
client.close
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def queues
|
|
38
|
+
@queues ||= {}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def direct(name = 'amq.direct', opts = {})
|
|
42
|
+
exchanges[name] ||= Exchange.new(client, :direct, name, opts)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def topic(name = 'amq.topic', opts = {})
|
|
46
|
+
exchanges[name] ||= Exchange.new(client, :topic, name, opts)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def headers(name = 'amq.match', opts = {})
|
|
50
|
+
exchanges[name] ||= Exchange.new(client, :headers, name, opts)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def exchanges
|
|
54
|
+
@exchanges ||= {}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|