hot_bunnies 1.1.2-java
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/.gitignore +5 -0
- data/.rvmrc +1 -0
- data/Gemfile +6 -0
- data/Rakefile +6 -0
- data/examples/blocking_subscription.rb +36 -0
- data/examples/non_blocking_subscription.rb +32 -0
- data/examples/non_blocking_subscription_with_executor.rb +38 -0
- data/hot_bunnies.gemspec +24 -0
- data/lib/ext/commons-io.jar +0 -0
- data/lib/ext/rabbitmq-client.jar +0 -0
- data/lib/hot_bunnies/channel.rb +24 -0
- data/lib/hot_bunnies/exchange.rb +34 -0
- data/lib/hot_bunnies/queue.rb +171 -0
- data/lib/hot_bunnies/version.rb +5 -0
- data/lib/hot_bunnies.rb +30 -0
- metadata +71 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create use jruby-1.6.2@hot_bunnies
|
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
$: << 'lib'
|
2
|
+
|
3
|
+
require 'hot_bunnies'
|
4
|
+
|
5
|
+
|
6
|
+
connection = HotBunnies.connect(:host => 'localhost')
|
7
|
+
channel = connection.create_channel
|
8
|
+
channel.prefetch = 10
|
9
|
+
|
10
|
+
exchange = channel.exchange('test', :type => :direct)
|
11
|
+
|
12
|
+
queue = channel.queue('hello.world')
|
13
|
+
queue.bind(exchange, :routing_key => 'xyz')
|
14
|
+
queue.purge
|
15
|
+
|
16
|
+
100.times do |i|
|
17
|
+
exchange.publish("hello world! #{i}", :routing_key => 'xyz')
|
18
|
+
end
|
19
|
+
|
20
|
+
exchange.publish("POISON!", :routing_key => 'xyz')
|
21
|
+
|
22
|
+
subscription = queue.subscribe(:ack => true)
|
23
|
+
subscription.each(:blocking => true) do |headers, msg|
|
24
|
+
puts msg
|
25
|
+
headers.ack
|
26
|
+
if msg == "POISON!"
|
27
|
+
:cancel
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
puts "ALL DONE!"
|
32
|
+
|
33
|
+
at_exit do
|
34
|
+
channel.close
|
35
|
+
connection.close
|
36
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
$: << 'lib'
|
2
|
+
|
3
|
+
require 'hot_bunnies'
|
4
|
+
|
5
|
+
|
6
|
+
connection = HotBunnies.connect(:host => 'localhost')
|
7
|
+
channel = connection.create_channel
|
8
|
+
channel.prefetch = 10
|
9
|
+
|
10
|
+
exchange = channel.exchange('test', :type => :direct)
|
11
|
+
|
12
|
+
queue = channel.queue('hello.world')
|
13
|
+
queue.bind(exchange, :routing_key => 'xyz')
|
14
|
+
queue.purge
|
15
|
+
|
16
|
+
subscription = queue.subscribe(:ack => true, :blocking => false) do |headers, msg|
|
17
|
+
puts msg
|
18
|
+
headers.ack
|
19
|
+
end
|
20
|
+
|
21
|
+
100.times do |i|
|
22
|
+
exchange.publish("hello world! #{i}", :routing_key => 'xyz')
|
23
|
+
end
|
24
|
+
|
25
|
+
subscription.cancel
|
26
|
+
|
27
|
+
puts "ALMOST ALL DONE!"
|
28
|
+
|
29
|
+
at_exit do
|
30
|
+
channel.close
|
31
|
+
connection.close
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
$: << 'lib'
|
2
|
+
|
3
|
+
require 'hot_bunnies'
|
4
|
+
|
5
|
+
import java.util.concurrent.Executors
|
6
|
+
|
7
|
+
|
8
|
+
connection = HotBunnies.connect(:host => 'localhost')
|
9
|
+
channel = connection.create_channel
|
10
|
+
channel.prefetch = 10
|
11
|
+
|
12
|
+
exchange = channel.exchange('test', :type => :direct)
|
13
|
+
|
14
|
+
queue = channel.queue('hello.world')
|
15
|
+
queue.bind(exchange, :routing_key => 'xyz')
|
16
|
+
queue.purge
|
17
|
+
|
18
|
+
thread_pool = Executors.new_fixed_thread_pool(3)
|
19
|
+
|
20
|
+
subscription = queue.subscribe(:ack => true)
|
21
|
+
subscription.each(:blocking => false, :executor => thread_pool) do |headers, msg|
|
22
|
+
puts msg
|
23
|
+
headers.ack
|
24
|
+
end
|
25
|
+
|
26
|
+
100.times do |i|
|
27
|
+
exchange.publish("hello world! #{i}", :routing_key => 'xyz')
|
28
|
+
end
|
29
|
+
|
30
|
+
thread_pool.shutdown_now
|
31
|
+
subscription.cancel
|
32
|
+
|
33
|
+
puts "ALMOST ALL DONE!"
|
34
|
+
|
35
|
+
at_exit do
|
36
|
+
channel.close
|
37
|
+
connection.close
|
38
|
+
end
|
data/hot_bunnies.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$: << File.expand_path('../lib', __FILE__)
|
4
|
+
|
5
|
+
require 'hot_bunnies/version'
|
6
|
+
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = 'hot_bunnies'
|
10
|
+
s.version = HotBunnies::VERSION
|
11
|
+
s.platform = 'java'
|
12
|
+
s.authors = ['Theo Hultberg']
|
13
|
+
s.email = ['theo@burtcorp.com']
|
14
|
+
s.homepage = 'http://github.com/iconara/hot_bunnies'
|
15
|
+
s.summary = %q{Ruby wrapper for the RabbitMQ Java driver}
|
16
|
+
s.description = %q{A object oriented interface to RabbitMQ that uses the Java driver under the hood}
|
17
|
+
|
18
|
+
s.rubyforge_project = 'hot_bunnies'
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
# s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
# s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = %w(lib)
|
24
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module HotBunnies
|
4
|
+
module Channel
|
5
|
+
def queue(name, options={})
|
6
|
+
Queue.new(self, name, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def exchange(name, options={})
|
10
|
+
Exchange.new(self, name, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def qos(options={})
|
14
|
+
if options.size == 1 && options[:prefetch_count]
|
15
|
+
then basic_qos(options[:prefetch_count])
|
16
|
+
else basic_qos(options.fetch(:prefetch_size, 0), options.fetch(:prefetch_count, 0), options.fetch(:global, false))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def prefetch=(n)
|
21
|
+
qos(:prefetch_count => n)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module HotBunnies
|
4
|
+
class Exchange
|
5
|
+
attr_reader :name, :channel
|
6
|
+
|
7
|
+
def initialize(channel, name, options={})
|
8
|
+
@channel = channel
|
9
|
+
@name = name
|
10
|
+
@options = {:type => :fanout, :durable => false, :auto_delete => false, :internal => false, :passive => false}.merge(options)
|
11
|
+
declare!
|
12
|
+
end
|
13
|
+
|
14
|
+
def publish(body, options={})
|
15
|
+
options = {:routing_key => '', :mandatory => false, :immediate => false}.merge(options)
|
16
|
+
@channel.basic_publish(@name, options[:routing_key], options[:mandatory], options[:immediate], nil, body.to_java_bytes)
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete(options={})
|
20
|
+
@channel.exchange_delete(@name, options.fetch(:if_unused, false))
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def declare!
|
26
|
+
unless @name == ''
|
27
|
+
if @options[:passive]
|
28
|
+
then @channel.exchange_declare_passive(@name)
|
29
|
+
else @channel.exchange_declare(@name, @options[:type].to_s, @options[:durable], @options[:auto_delete], @options[:internal], nil)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module HotBunnies
|
4
|
+
class Queue
|
5
|
+
attr_reader :name, :channel
|
6
|
+
|
7
|
+
def initialize(channel, name, options={})
|
8
|
+
@channel = channel
|
9
|
+
@name = name
|
10
|
+
@options = {:durable => false, :exclusive => false, :auto_delete => false, :passive => false}.merge(options)
|
11
|
+
declare!
|
12
|
+
end
|
13
|
+
|
14
|
+
def bind(exchange, options={})
|
15
|
+
exchange_name = if exchange.respond_to?(:name) then exchange.name else exchange.to_s end
|
16
|
+
@channel.queue_bind(@name, exchange_name, options.fetch(:routing_key, ''))
|
17
|
+
end
|
18
|
+
|
19
|
+
def unbind(exchange, options={})
|
20
|
+
exchange_name = if exchange.respond_to?(:name) then exchange.name else exchange.to_s end
|
21
|
+
@channel.queue_unbind(@name, exchange_name, options.fetch(:routing_key, ''))
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete
|
25
|
+
@channel.queue_delete(@name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def purge
|
29
|
+
@channel.queue_purge(@name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def get(options={})
|
33
|
+
response = @channel.basic_get(@name, !options.fetch(:ack, false))
|
34
|
+
if response
|
35
|
+
then [Headers.new(@channel, nil, response.envelope, response.props), String.from_java_bytes(response.body)]
|
36
|
+
else nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def subscribe(options={}, &block)
|
41
|
+
subscription = Subscription.new(@channel, @name, options)
|
42
|
+
subscription.each(options, &block) if block
|
43
|
+
subscription
|
44
|
+
end
|
45
|
+
|
46
|
+
def status
|
47
|
+
response = @channel.queue_declare_passive(@name)
|
48
|
+
[response.message_count, response.consumer_count]
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def declare!
|
54
|
+
response = if @options[:passive]
|
55
|
+
then @channel.queue_declare_passive(@name)
|
56
|
+
else @channel.queue_declare(@name, @options[:durable], @options[:exclusive], @options[:auto_delete], nil)
|
57
|
+
end
|
58
|
+
@name = response.queue
|
59
|
+
end
|
60
|
+
|
61
|
+
class Subscription
|
62
|
+
def initialize(channel, queue_name, options={})
|
63
|
+
@channel = channel
|
64
|
+
@queue_name = queue_name
|
65
|
+
@ack = options.fetch(:ack, false)
|
66
|
+
end
|
67
|
+
|
68
|
+
def each(options={}, &block)
|
69
|
+
raise 'The subscription already has a message listener' if @subscriber
|
70
|
+
if options.fetch(:blocking, true)
|
71
|
+
run(&block)
|
72
|
+
else
|
73
|
+
if options[:executor]
|
74
|
+
@shut_down_executor = false
|
75
|
+
@executor = options[:executor]
|
76
|
+
else
|
77
|
+
@shut_down_executor = true
|
78
|
+
@executor = java.util.concurrent.Executors.new_single_thread_executor
|
79
|
+
end
|
80
|
+
@executor.submit { run(&block) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def cancel
|
85
|
+
raise 'Can\'t cancel: the subscriber haven\'t received an OK yet' if !@subscriber || !@subscriber.consumer_tag
|
86
|
+
@channel.basic_cancel(@subscriber.consumer_tag)
|
87
|
+
@executor.shutdown_now if @executor && @shut_down_executor
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def run(&block)
|
93
|
+
@subscriber = BlockingSubscriber.new(@channel, self)
|
94
|
+
@channel.basic_consume(@queue_name, !@ack, @subscriber.consumer)
|
95
|
+
@subscriber.on_message(&block)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class Headers
|
100
|
+
def initialize(channel, consumer_tag, envelope, properties)
|
101
|
+
@channel = channel
|
102
|
+
@consumer_tag = consumer_tag
|
103
|
+
@envelope = envelope
|
104
|
+
@properties = properties
|
105
|
+
end
|
106
|
+
|
107
|
+
def ack(options={})
|
108
|
+
@channel.basic_ack(delivery_tag, options.fetch(:multiple, false))
|
109
|
+
end
|
110
|
+
|
111
|
+
def reject(options={})
|
112
|
+
@channel.basic_ack(delivery_tag, options.fetch(:requeue, false))
|
113
|
+
end
|
114
|
+
|
115
|
+
def delivery_tag
|
116
|
+
@envelope.delivery_tag
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
module Subscriber
|
121
|
+
def start
|
122
|
+
# to be implemented by the host class
|
123
|
+
end
|
124
|
+
|
125
|
+
def on_message(&block)
|
126
|
+
raise ArgumentError, 'Message listener already registered for this subscriber' if @subscriber
|
127
|
+
@subscriber = block
|
128
|
+
start
|
129
|
+
end
|
130
|
+
|
131
|
+
def handle_message(consumer_tag, envelope, properties, body_bytes)
|
132
|
+
body = String.from_java_bytes(body_bytes)
|
133
|
+
case @subscriber.arity
|
134
|
+
when 2 then @subscriber.call(Headers.new(@channel, consumer_tag, envelope, properties), body)
|
135
|
+
when 1 then @subscriber.call(body)
|
136
|
+
else raise ArgumentError, 'Consumer callback wants no arguments'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class BlockingSubscriber
|
142
|
+
include Subscriber
|
143
|
+
|
144
|
+
attr_reader :consumer
|
145
|
+
|
146
|
+
def initialize(channel, subscription)
|
147
|
+
@channel = channel
|
148
|
+
@subscription = subscription
|
149
|
+
@consumer = QueueingConsumer.new(@channel)
|
150
|
+
end
|
151
|
+
|
152
|
+
def consumer_tag
|
153
|
+
@consumer.consumer_tag
|
154
|
+
end
|
155
|
+
|
156
|
+
def start
|
157
|
+
super
|
158
|
+
while delivery = @consumer.next_delivery
|
159
|
+
result = handle_message(@consumer.consumer_tag, delivery.envelope, delivery.properties, delivery.body)
|
160
|
+
if result == :cancel
|
161
|
+
@subscription.cancel
|
162
|
+
while delivery = @consumer.next_delivery(0)
|
163
|
+
handle_message(@consumer.consumer_tag, delivery.envelope, delivery.properties, delivery.body)
|
164
|
+
end
|
165
|
+
break
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
data/lib/hot_bunnies.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'java'
|
4
|
+
require 'ext/commons-io'
|
5
|
+
require 'ext/rabbitmq-client'
|
6
|
+
|
7
|
+
|
8
|
+
module HotBunnies
|
9
|
+
import com.rabbitmq.client.ConnectionFactory
|
10
|
+
import com.rabbitmq.client.Connection
|
11
|
+
import com.rabbitmq.client.Channel
|
12
|
+
import com.rabbitmq.client.DefaultConsumer
|
13
|
+
import com.rabbitmq.client.QueueingConsumer
|
14
|
+
|
15
|
+
CONNECTION_PROPERTIES = [:host, :port, :virtual_host, :connection_timeout, :username, :password]
|
16
|
+
|
17
|
+
def self.connect(options={})
|
18
|
+
cf = ConnectionFactory.new
|
19
|
+
CONNECTION_PROPERTIES.each do |property|
|
20
|
+
if options[property]
|
21
|
+
cf.send("#{property}=".to_sym, options[property])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
cf.new_connection
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'hot_bunnies/channel'
|
29
|
+
require 'hot_bunnies/queue'
|
30
|
+
require 'hot_bunnies/exchange'
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hot_bunnies
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 1.1.2
|
6
|
+
platform: java
|
7
|
+
authors:
|
8
|
+
- Theo Hultberg
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-07-13 00:00:00 +02:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: A object oriented interface to RabbitMQ that uses the Java driver under the hood
|
18
|
+
email:
|
19
|
+
- theo@burtcorp.com
|
20
|
+
executables: []
|
21
|
+
|
22
|
+
extensions: []
|
23
|
+
|
24
|
+
extra_rdoc_files: []
|
25
|
+
|
26
|
+
files:
|
27
|
+
- .gitignore
|
28
|
+
- .rvmrc
|
29
|
+
- Gemfile
|
30
|
+
- Rakefile
|
31
|
+
- examples/blocking_subscription.rb
|
32
|
+
- examples/non_blocking_subscription.rb
|
33
|
+
- examples/non_blocking_subscription_with_executor.rb
|
34
|
+
- hot_bunnies.gemspec
|
35
|
+
- lib/ext/commons-io.jar
|
36
|
+
- lib/ext/rabbitmq-client.jar
|
37
|
+
- lib/hot_bunnies.rb
|
38
|
+
- lib/hot_bunnies/channel.rb
|
39
|
+
- lib/hot_bunnies/exchange.rb
|
40
|
+
- lib/hot_bunnies/queue.rb
|
41
|
+
- lib/hot_bunnies/version.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/iconara/hot_bunnies
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project: hot_bunnies
|
66
|
+
rubygems_version: 1.5.2
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Ruby wrapper for the RabbitMQ Java driver
|
70
|
+
test_files: []
|
71
|
+
|