amq-client 0.7.0.alpha23 → 0.7.0.alpha24
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +3 -9
- data/lib/amq/client.rb +6 -5
- data/lib/amq/client/adapter.rb +2 -64
- data/lib/amq/client/adapters/coolio.rb +1 -2
- data/lib/amq/client/adapters/event_machine.rb +2 -7
- data/lib/amq/client/callbacks.rb +60 -0
- data/lib/amq/client/channel.rb +5 -1
- data/lib/amq/client/connection.rb +13 -21
- data/lib/amq/client/entity.rb +19 -81
- data/lib/amq/client/exchange.rb +9 -10
- data/lib/amq/client/handlers_registry.rb +30 -0
- data/lib/amq/client/{mixins/status.rb → openable.rb} +2 -2
- data/lib/amq/client/queue.rb +6 -8
- data/lib/amq/client/{mixins/anonymous_entity.rb → server_named_entity.rb} +6 -4
- data/lib/amq/client/version.rb +1 -1
- data/lib/amq/{client/protocol → protocol}/get_response.rb +0 -0
- data/spec/client/protocol/get_response_spec.rb +1 -1
- data/spec/integration/eventmachine/exchange_declare_spec.rb +32 -1
- data/spec/unit/client/entity_spec.rb +8 -1
- data/spec/unit/client/mixins/status_spec.rb +4 -4
- data/spec/unit/client_spec.rb +3 -5
- metadata +9 -11
- data/examples/socket_adapter/basics.rb +0 -19
- data/examples/socket_adapter/connection.rb +0 -53
- data/examples/socket_adapter/multiple_connections.rb +0 -17
- data/lib/amq/client/adapters/socket.rb +0 -90
data/README.textile
CHANGED
@@ -27,11 +27,10 @@ conciseness.
|
|
27
27
|
|
28
28
|
h2. Adapters
|
29
29
|
|
30
|
-
|
30
|
+
Currently implemented adapters:
|
31
31
|
|
32
|
-
* EventMachine
|
33
|
-
* cool.io
|
34
|
-
* TCP sockets (synchronous)
|
32
|
+
* "EventMachine":http://github.com/eventmachine/eventmachine
|
33
|
+
* "cool.io":http://coolio.github.com/
|
35
34
|
|
36
35
|
h3. EventMachine adapter
|
37
36
|
|
@@ -46,11 +45,6 @@ cool.io adapter is on par with EventMachine but is not used by any popular libra
|
|
46
45
|
Note that cool.io doesn't work on JRuby and Microsoft Windows(tm).
|
47
46
|
|
48
47
|
|
49
|
-
h3. TCP socket adapter
|
50
|
-
|
51
|
-
TCP socket adapter is largely incomplete.
|
52
|
-
|
53
|
-
|
54
48
|
h2. Installation
|
55
49
|
|
56
50
|
amq-client is available from rubygems.org:
|
data/lib/amq/client.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "amq/client/version"
|
4
4
|
require "amq/client/exceptions"
|
5
|
+
require "amq/client/handlers_registry"
|
5
6
|
require "amq/client/adapter"
|
6
7
|
require "amq/client/channel"
|
7
8
|
require "amq/client/exchange"
|
@@ -23,8 +24,8 @@ module AMQ
|
|
23
24
|
# where metadata are hash with :path and :const_name keys.
|
24
25
|
#
|
25
26
|
# @example
|
26
|
-
# AMQ::Client.adapters[:
|
27
|
-
#
|
27
|
+
# AMQ::Client.adapters[:event_machine] # => {path: "...", const_name: "EventMachineClient"}}
|
28
|
+
#
|
28
29
|
# @return [Hash]
|
29
30
|
# @api public
|
30
31
|
def self.adapters
|
@@ -50,7 +51,7 @@ module AMQ
|
|
50
51
|
# @param [Hash] Connection parameters, including :adapter to use.
|
51
52
|
# @api public
|
52
53
|
def self.connect(settings = nil, &block)
|
53
|
-
adapter = (settings && settings.delete(:adapter))
|
54
|
+
adapter = (settings && settings.delete(:adapter))
|
54
55
|
adapter = load_adapter(adapter)
|
55
56
|
adapter.connect(settings, &block)
|
56
57
|
end
|
@@ -66,5 +67,5 @@ module AMQ
|
|
66
67
|
rescue LoadError
|
67
68
|
raise InvalidAdapterNameError.new(adapter)
|
68
69
|
end
|
69
|
-
end
|
70
|
-
end
|
70
|
+
end # Client
|
71
|
+
end # AMQ
|
data/lib/amq/client/adapter.rb
CHANGED
@@ -16,29 +16,6 @@ module AMQ
|
|
16
16
|
# * #estabilish_connection(settings)
|
17
17
|
# * #close_connection
|
18
18
|
#
|
19
|
-
# Adapters also must indicate whether they operate in asynchronous or synchronous mode
|
20
|
-
# using AMQ::Client::Adapter.sync accessor:
|
21
|
-
#
|
22
|
-
# @example EventMachine adapter indicates that it is asynchronous
|
23
|
-
# module AMQ
|
24
|
-
# module Client
|
25
|
-
# class EventMachineClient
|
26
|
-
#
|
27
|
-
# #
|
28
|
-
# # Behaviors
|
29
|
-
# #
|
30
|
-
#
|
31
|
-
# include AMQ::Client::Adapter
|
32
|
-
# include EventMachine::Deferrable
|
33
|
-
#
|
34
|
-
# self.sync = false
|
35
|
-
#
|
36
|
-
# # the rest of implementation code ...
|
37
|
-
#
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
# end
|
41
|
-
#
|
42
19
|
# @abstract
|
43
20
|
module Adapter
|
44
21
|
|
@@ -126,27 +103,6 @@ module AMQ
|
|
126
103
|
instance
|
127
104
|
end
|
128
105
|
|
129
|
-
# @see AMQ::Client::Adapter
|
130
|
-
def sync=(boolean)
|
131
|
-
@sync = boolean
|
132
|
-
end
|
133
|
-
|
134
|
-
# Use this method to detect whether adapter is synchronous or asynchronous.
|
135
|
-
#
|
136
|
-
# @return [Boolean] true if this adapter is synchronous
|
137
|
-
# @api plugin
|
138
|
-
# @see AMQ::Client::Adapter
|
139
|
-
def sync?
|
140
|
-
@sync == true
|
141
|
-
end
|
142
|
-
|
143
|
-
# @see #sync?
|
144
|
-
# @api plugin
|
145
|
-
# @see AMQ::Client::Adapter
|
146
|
-
def async?
|
147
|
-
!sync?
|
148
|
-
end
|
149
|
-
|
150
106
|
|
151
107
|
# Can be overriden by higher-level libraries like amqp gem or bunny.
|
152
108
|
# Defaults to AMQ::Client::TCPConnectionFailed.
|
@@ -170,7 +126,7 @@ module AMQ
|
|
170
126
|
# Behaviors
|
171
127
|
#
|
172
128
|
|
173
|
-
include AMQ::Client::
|
129
|
+
include AMQ::Client::Openable
|
174
130
|
|
175
131
|
extend RegisterEntityMixin
|
176
132
|
|
@@ -201,10 +157,6 @@ module AMQ
|
|
201
157
|
def handshake(mechanism = "PLAIN", response = "\0guest\0guest", locale = "en_GB")
|
202
158
|
self.send_preamble
|
203
159
|
self.connection = AMQ::Client::Connection.new(self, mechanism, response, locale)
|
204
|
-
if self.sync?
|
205
|
-
self.receive # Start/Start-Ok
|
206
|
-
self.receive # Tune/Tune-Ok
|
207
|
-
end
|
208
160
|
end
|
209
161
|
|
210
162
|
# Properly close connection with AMQ broker, as described in
|
@@ -279,7 +231,7 @@ module AMQ
|
|
279
231
|
if Protocol::HeartbeatFrame === frame
|
280
232
|
@last_server_heartbeat = Time.now
|
281
233
|
else
|
282
|
-
callable = AMQ::Client::
|
234
|
+
callable = AMQ::Client::HandlersRegistry.find(frame.method_class)
|
283
235
|
if callable
|
284
236
|
callable.call(self, frames.first, frames[1..-1])
|
285
237
|
else
|
@@ -299,20 +251,6 @@ module AMQ
|
|
299
251
|
end # send_heartbeat
|
300
252
|
|
301
253
|
|
302
|
-
# @see .sync?
|
303
|
-
# @api plugin
|
304
|
-
# @see AMQ::Client::Adapter
|
305
|
-
def sync?
|
306
|
-
self.class.sync?
|
307
|
-
end
|
308
|
-
|
309
|
-
# @see .async?
|
310
|
-
# @api plugin
|
311
|
-
# @see AMQ::Client::Adapter
|
312
|
-
def async?
|
313
|
-
self.class.async?
|
314
|
-
end
|
315
|
-
|
316
254
|
# Returns heartbeat interval this client uses, in seconds.
|
317
255
|
# This value may or may not be used depending on broker capabilities.
|
318
256
|
#
|
@@ -18,7 +18,6 @@ module AMQ
|
|
18
18
|
|
19
19
|
include AMQ::Client::Adapter
|
20
20
|
|
21
|
-
self.sync = false
|
22
21
|
|
23
22
|
#
|
24
23
|
# API
|
@@ -119,7 +118,7 @@ module AMQ
|
|
119
118
|
|
120
119
|
def initialize(*args)
|
121
120
|
super(*args)
|
122
|
-
|
121
|
+
opening!
|
123
122
|
@connections = Array.new
|
124
123
|
# track TCP connection state, used to detect initial TCP connection failures.
|
125
124
|
@tcp_connection_established = false
|
@@ -250,11 +249,7 @@ module AMQ
|
|
250
249
|
# in the authentication stage. If so, it is likely to signal an authentication
|
251
250
|
# issue. Java client behaves the same way. MK.
|
252
251
|
if authenticating? && !@intentionally_closing_connection
|
253
|
-
if
|
254
|
-
raise PossibleAuthenticationFailureError.new(@settings)
|
255
|
-
else
|
256
|
-
@on_possible_authentication_failure.call(@settings) if @on_possible_authentication_failure
|
257
|
-
end
|
252
|
+
@on_possible_authentication_failure.call(@settings) if @on_possible_authentication_failure
|
258
253
|
end
|
259
254
|
end # unbind
|
260
255
|
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module AMQ
|
2
|
+
module Client
|
3
|
+
module Callbacks
|
4
|
+
|
5
|
+
def redefine_callback(event, callable = nil, &block)
|
6
|
+
f = (callable || block)
|
7
|
+
# yes, re-assign!
|
8
|
+
@callbacks[event] = [f]
|
9
|
+
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def define_callback(event, callable = nil, &block)
|
14
|
+
f = (callable || block)
|
15
|
+
|
16
|
+
@callbacks[event] ||= []
|
17
|
+
@callbacks[event] << f if f
|
18
|
+
|
19
|
+
self
|
20
|
+
end # define_callback(event, &block)
|
21
|
+
alias append_callback define_callback
|
22
|
+
|
23
|
+
def prepend_callback(event, &block)
|
24
|
+
@callbacks[event] ||= []
|
25
|
+
@callbacks[event].unshift(block)
|
26
|
+
|
27
|
+
self
|
28
|
+
end # prepend_callback(event, &block)
|
29
|
+
|
30
|
+
def clear_callbacks(event)
|
31
|
+
@callbacks[event].clear if @callbacks[event]
|
32
|
+
end # clear_callbacks(event)
|
33
|
+
|
34
|
+
|
35
|
+
def exec_callback(name, *args, &block)
|
36
|
+
callbacks = Array(self.callbacks[name])
|
37
|
+
callbacks.map { |c| c.call(*args, &block) } if callbacks.any?
|
38
|
+
end
|
39
|
+
|
40
|
+
def exec_callback_once(name, *args, &block)
|
41
|
+
callbacks = Array(self.callbacks.delete(name))
|
42
|
+
callbacks.map { |c| c.call(*args, &block) } if callbacks.any?
|
43
|
+
end
|
44
|
+
|
45
|
+
def exec_callback_yielding_self(name, *args, &block)
|
46
|
+
callbacks = Array(self.callbacks[name])
|
47
|
+
callbacks.map { |c| c.call(self, *args, &block) } if callbacks.any?
|
48
|
+
end
|
49
|
+
|
50
|
+
def exec_callback_once_yielding_self(name, *args, &block)
|
51
|
+
callbacks = Array(self.callbacks.delete(name))
|
52
|
+
callbacks.map { |c| c.call(self, *args, &block) } if callbacks.any?
|
53
|
+
end
|
54
|
+
|
55
|
+
def has_callback?(name)
|
56
|
+
self.callbacks[name] && !self.callbacks[name].empty?
|
57
|
+
end # has_callback?
|
58
|
+
end # Callbacks
|
59
|
+
end # Client
|
60
|
+
end # AMQ
|
data/lib/amq/client/channel.rb
CHANGED
@@ -6,12 +6,16 @@ require "amq/client/exchange"
|
|
6
6
|
|
7
7
|
module AMQ
|
8
8
|
module Client
|
9
|
-
class Channel
|
9
|
+
class Channel
|
10
10
|
|
11
11
|
#
|
12
12
|
# Behaviors
|
13
13
|
#
|
14
14
|
|
15
|
+
extend RegisterEntityMixin
|
16
|
+
include Entity
|
17
|
+
extend ProtocolMethodHandlers
|
18
|
+
|
15
19
|
register_entity :queue, AMQ::Client::Queue
|
16
20
|
register_entity :exchange, AMQ::Client::Exchange
|
17
21
|
|
@@ -10,26 +10,26 @@ module AMQ
|
|
10
10
|
# methods)
|
11
11
|
#
|
12
12
|
# AMQP connection has multiple channels accessible via {Connection#channels} reader.
|
13
|
-
class Connection
|
13
|
+
class Connection
|
14
14
|
|
15
15
|
#
|
16
16
|
# Behaviors
|
17
17
|
#
|
18
18
|
|
19
|
-
include
|
20
|
-
|
19
|
+
include Entity
|
20
|
+
extend ProtocolMethodHandlers
|
21
21
|
|
22
22
|
#
|
23
23
|
# API
|
24
24
|
#
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:version
|
31
|
-
|
32
|
-
|
26
|
+
DEFAULT_CLIENT_PROPERTIES = {
|
27
|
+
:platform => ::RUBY_DESCRIPTION,
|
28
|
+
:product => "AMQ Client",
|
29
|
+
:information => "http://github.com/ruby-amqp/amq-client",
|
30
|
+
:version => AMQ::Client::VERSION
|
31
|
+
}
|
32
|
+
|
33
33
|
|
34
34
|
# Client capabilities
|
35
35
|
#
|
@@ -84,18 +84,13 @@ module AMQ
|
|
84
84
|
|
85
85
|
|
86
86
|
# @api public
|
87
|
-
def initialize(client, mechanism, response, locale, client_properties =
|
87
|
+
def initialize(client, mechanism, response, locale, client_properties = {})
|
88
88
|
@mechanism = mechanism
|
89
89
|
@response = response
|
90
90
|
@locale = locale
|
91
91
|
|
92
92
|
@channels = Hash.new
|
93
|
-
@client_properties = client_properties
|
94
|
-
:platform => "Ruby #{RUBY_VERSION}",
|
95
|
-
:product => "AMQ Client",
|
96
|
-
:information => "http://github.com/ruby-amqp/amq-client",
|
97
|
-
:version => AMQ::Client::VERSION
|
98
|
-
}
|
93
|
+
@client_properties = DEFAULT_CLIENT_PROPERTIES.merge(client_properties)
|
99
94
|
|
100
95
|
reset_state!
|
101
96
|
|
@@ -106,8 +101,6 @@ module AMQ
|
|
106
101
|
# Default errback.
|
107
102
|
# You might want to override it, otherwise it'll
|
108
103
|
# crash your program. It's the expected behaviour
|
109
|
-
# if it's a synchronous one, but not if you use
|
110
|
-
# some kind of event loop like EventMachine etc.
|
111
104
|
self.define_callback(:close) { |exception| raise(exception) }
|
112
105
|
end
|
113
106
|
|
@@ -117,6 +110,7 @@ module AMQ
|
|
117
110
|
end # settings
|
118
111
|
|
119
112
|
|
113
|
+
|
120
114
|
#
|
121
115
|
# Connection class methods
|
122
116
|
#
|
@@ -175,8 +169,6 @@ module AMQ
|
|
175
169
|
@known_hosts = method.known_hosts
|
176
170
|
|
177
171
|
opened!
|
178
|
-
# async adapters need this callback to proceed with
|
179
|
-
# Adapter.connect block evaluation
|
180
172
|
@client.connection_successful if @client.respond_to?(:connection_successful)
|
181
173
|
end
|
182
174
|
|
data/lib/amq/client/entity.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require "amq/client/
|
3
|
+
require "amq/client/callbacks"
|
4
|
+
require "amq/client/openable"
|
4
5
|
|
5
6
|
module AMQ
|
6
7
|
module Client
|
@@ -14,65 +15,20 @@ module AMQ
|
|
14
15
|
def register_entity(name, klass)
|
15
16
|
define_method(name) do |*args, &block|
|
16
17
|
klass.new(self, *args, &block)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
module CallbacksMixin
|
22
|
-
def redefine_callback(event, callable = nil, &block)
|
23
|
-
f = (callable || block)
|
24
|
-
# yes, re-assign!
|
25
|
-
@callbacks[event] = [f]
|
18
|
+
end # define_method
|
19
|
+
end # register_entity
|
20
|
+
end # RegisterEntityMixin
|
26
21
|
|
27
|
-
|
22
|
+
module ProtocolMethodHandlers
|
23
|
+
def handle(klass, &block)
|
24
|
+
AMQ::Client::HandlersRegistry.register(klass, &block)
|
28
25
|
end
|
29
26
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
@callbacks[event] ||= []
|
34
|
-
@callbacks[event] << f if f
|
35
|
-
|
36
|
-
self
|
37
|
-
end # define_callback(event, &block)
|
38
|
-
alias append_callback define_callback
|
39
|
-
|
40
|
-
def prepend_callback(event, &block)
|
41
|
-
@callbacks[event] ||= []
|
42
|
-
@callbacks[event].unshift(block)
|
43
|
-
|
44
|
-
self
|
45
|
-
end # prepend_callback(event, &block)
|
46
|
-
|
47
|
-
def clear_callbacks(event)
|
48
|
-
@callbacks[event].clear if @callbacks[event]
|
49
|
-
end # clear_callbacks(event)
|
50
|
-
|
51
|
-
|
52
|
-
def exec_callback(name, *args, &block)
|
53
|
-
callbacks = Array(self.callbacks[name])
|
54
|
-
callbacks.map { |c| c.call(*args, &block) } if callbacks.any?
|
27
|
+
def handlers
|
28
|
+
AMQ::Client::HandlersRegistry.handlers
|
55
29
|
end
|
30
|
+
end # ProtocolMethodHandlers
|
56
31
|
|
57
|
-
def exec_callback_once(name, *args, &block)
|
58
|
-
callbacks = Array(self.callbacks.delete(name))
|
59
|
-
callbacks.map { |c| c.call(*args, &block) } if callbacks.any?
|
60
|
-
end
|
61
|
-
|
62
|
-
def exec_callback_yielding_self(name, *args, &block)
|
63
|
-
callbacks = Array(self.callbacks[name])
|
64
|
-
callbacks.map { |c| c.call(self, *args, &block) } if callbacks.any?
|
65
|
-
end
|
66
|
-
|
67
|
-
def exec_callback_once_yielding_self(name, *args, &block)
|
68
|
-
callbacks = Array(self.callbacks.delete(name))
|
69
|
-
callbacks.map { |c| c.call(self, *args, &block) } if callbacks.any?
|
70
|
-
end
|
71
|
-
|
72
|
-
def has_callback?(name)
|
73
|
-
self.callbacks[name] && !self.callbacks[name].empty?
|
74
|
-
end # has_callback?
|
75
|
-
end
|
76
32
|
|
77
33
|
# AMQ entities, as implemented by AMQ::Client, have callbacks and can run them
|
78
34
|
# when necessary.
|
@@ -80,16 +36,14 @@ module AMQ
|
|
80
36
|
# @note Exchanges and queues implementation is based on this class.
|
81
37
|
#
|
82
38
|
# @abstract
|
83
|
-
|
39
|
+
module Entity
|
84
40
|
|
85
41
|
#
|
86
42
|
# Behaviors
|
87
43
|
#
|
88
44
|
|
89
|
-
include
|
90
|
-
include
|
91
|
-
|
92
|
-
extend RegisterEntityMixin
|
45
|
+
include Openable
|
46
|
+
include Callbacks
|
93
47
|
|
94
48
|
#
|
95
49
|
# API
|
@@ -98,16 +52,6 @@ module AMQ
|
|
98
52
|
# @return [Array<#call>]
|
99
53
|
attr_reader :callbacks
|
100
54
|
|
101
|
-
@@handlers ||= Hash.new
|
102
|
-
|
103
|
-
def self.handle(klass, &block)
|
104
|
-
@@handlers[klass] = block
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.handlers
|
108
|
-
@@handlers
|
109
|
-
end
|
110
|
-
|
111
55
|
|
112
56
|
def initialize(client)
|
113
57
|
@client = client
|
@@ -118,18 +62,12 @@ module AMQ
|
|
118
62
|
|
119
63
|
|
120
64
|
def error(exception)
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
else
|
126
|
-
# Asynchronous error handling.
|
127
|
-
# Set callback for given class (Queue for example)
|
128
|
-
# or for the Connection class (or instance, of course).
|
129
|
-
callbacks = [self.callbacks[:close], self.client.connection.callbacks[:close]].flatten.compact
|
65
|
+
# Asynchronous error handling.
|
66
|
+
# Set callback for given class (Queue for example)
|
67
|
+
# or for the Connection class (or instance, of course).
|
68
|
+
callbacks = [self.callbacks[:close], self.client.connection.callbacks[:close]].flatten.compact
|
130
69
|
|
131
|
-
|
132
|
-
end
|
70
|
+
callbacks.map { |c| c.call(exception) } if callbacks.any?
|
133
71
|
end
|
134
72
|
end
|
135
73
|
end
|
data/lib/amq/client/exchange.rb
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require "amq/client/entity"
|
4
|
-
require "amq/client/
|
4
|
+
require "amq/client/server_named_entity"
|
5
5
|
|
6
6
|
module AMQ
|
7
7
|
module Client
|
8
|
-
class Exchange
|
9
|
-
|
8
|
+
class Exchange
|
9
|
+
|
10
|
+
|
11
|
+
include Entity
|
12
|
+
include ServerNamedEntity
|
13
|
+
extend ProtocolMethodHandlers
|
10
14
|
|
11
15
|
TYPES = [:fanout, :direct, :topic, :headers].freeze
|
12
16
|
|
13
17
|
class IncompatibleExchangeTypeError < StandardError
|
14
18
|
def initialize(types, given)
|
15
|
-
super("
|
19
|
+
super("#{given.inspect} exchange type is unknown. Standard types are #{TYPES.inspect}, custom exchange types must begin with x-, for example: x-recent-history")
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
@@ -31,7 +35,7 @@ module AMQ
|
|
31
35
|
attr_reader :type
|
32
36
|
|
33
37
|
def initialize(client, channel, name, type = :fanout)
|
34
|
-
|
38
|
+
if !(TYPES.include?(type.to_sym) || type.to_s =~ /^x-.+/i)
|
35
39
|
raise IncompatibleExchangeTypeError.new(TYPES, type)
|
36
40
|
end
|
37
41
|
|
@@ -71,11 +75,6 @@ module AMQ
|
|
71
75
|
@channel.exchanges_awaiting_declare_ok.push(self)
|
72
76
|
end
|
73
77
|
|
74
|
-
|
75
|
-
if @client.sync?
|
76
|
-
@client.read_until_receives(Protocol::Exchange::DeclareOk) unless nowait
|
77
|
-
end
|
78
|
-
|
79
78
|
self
|
80
79
|
end
|
81
80
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module AMQ
|
2
|
+
module Client
|
3
|
+
class HandlersRegistry
|
4
|
+
|
5
|
+
@@handlers ||= Hash.new
|
6
|
+
|
7
|
+
|
8
|
+
#
|
9
|
+
# API
|
10
|
+
#
|
11
|
+
|
12
|
+
|
13
|
+
def self.register(klass, &block)
|
14
|
+
@@handlers[klass] = block
|
15
|
+
end
|
16
|
+
class << self
|
17
|
+
alias handle register
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find(klass)
|
21
|
+
@@handlers[klass]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.handlers
|
25
|
+
@@handlers
|
26
|
+
end
|
27
|
+
|
28
|
+
end # HandlersRegistry
|
29
|
+
end # Client
|
30
|
+
end # AMQ
|
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
module AMQ
|
4
4
|
module Client
|
5
|
-
module
|
5
|
+
module Openable
|
6
6
|
VALUES = [:opened, :closed, :opening, :closing].freeze
|
7
7
|
|
8
8
|
class ImproperStatusError < ArgumentError
|
9
9
|
def initialize(value)
|
10
|
-
super("Value #{value.inspect} isn't permitted. Choose one of: #{AMQ::Client::
|
10
|
+
super("Value #{value.inspect} isn't permitted. Choose one of: #{AMQ::Client::Openable::VALUES.inspect}")
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
data/lib/amq/client/queue.rb
CHANGED
@@ -2,18 +2,20 @@
|
|
2
2
|
|
3
3
|
require "amq/client/entity"
|
4
4
|
require "amq/client/adapter"
|
5
|
-
require "amq/client/
|
6
|
-
require "amq/
|
5
|
+
require "amq/client/server_named_entity"
|
6
|
+
require "amq/protocol/get_response"
|
7
7
|
|
8
8
|
module AMQ
|
9
9
|
module Client
|
10
|
-
class Queue
|
10
|
+
class Queue
|
11
11
|
|
12
12
|
#
|
13
13
|
# Behaviors
|
14
14
|
#
|
15
15
|
|
16
|
-
include
|
16
|
+
include Entity
|
17
|
+
include ServerNamedEntity
|
18
|
+
extend ProtocolMethodHandlers
|
17
19
|
|
18
20
|
|
19
21
|
#
|
@@ -92,10 +94,6 @@ module AMQ
|
|
92
94
|
@channel.queues_awaiting_declare_ok.push(self)
|
93
95
|
end
|
94
96
|
|
95
|
-
if @client.sync?
|
96
|
-
@client.read_until_receives(Protocol::Queue::DeclareOk) unless nowait
|
97
|
-
end
|
98
|
-
|
99
97
|
self
|
100
98
|
end
|
101
99
|
|
@@ -3,19 +3,21 @@
|
|
3
3
|
module AMQ
|
4
4
|
module Client
|
5
5
|
# Common behavior of AMQ entities that can be either client or server-named, for example, exchanges and queues.
|
6
|
-
module
|
6
|
+
module ServerNamedEntity
|
7
7
|
|
8
8
|
# @return [Boolean] true if this entity is anonymous (server-named)
|
9
|
-
def
|
9
|
+
def server_named?
|
10
10
|
@name.nil? or @name.empty?
|
11
11
|
end
|
12
|
+
# backwards compabitility. MK.
|
13
|
+
alias anonymous? server_named?
|
12
14
|
|
13
15
|
def dup
|
14
|
-
if
|
16
|
+
if server_named?
|
15
17
|
raise RuntimeError.new("You can't clone anonymous queue until it receives back the name in Queue.Declare-Ok response. Move the code with #dup to the callback for the #declare method.") # TODO: that's not true in all cases, imagine the user didn't call #declare yet.
|
16
18
|
end
|
17
19
|
super
|
18
20
|
end
|
19
|
-
end #
|
21
|
+
end # ServerNamedEntity
|
20
22
|
end # Client
|
21
23
|
end # AMQ
|
data/lib/amq/client/version.rb
CHANGED
File without changes
|
@@ -2,14 +2,45 @@ require 'spec_helper'
|
|
2
2
|
require 'integration/eventmachine/spec_helper'
|
3
3
|
|
4
4
|
describe AMQ::Client::EventMachineClient, "Exchange.Declare" do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Environment
|
8
|
+
#
|
9
|
+
|
5
10
|
include EventedSpec::SpecHelper
|
6
11
|
default_timeout 1
|
7
12
|
let(:exchange_name) { "amq-client.testexchange.#{Time.now.to_i}" }
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
#
|
17
|
+
# Examples
|
18
|
+
#
|
19
|
+
|
20
|
+
context "when exchange type is non-standard" do
|
21
|
+
context "and DOES NOT begin with x-" do
|
22
|
+
it "raises an exception" do
|
23
|
+
em_amqp_connect do |client|
|
24
|
+
channel = AMQ::Client::Channel.new(client, 1)
|
25
|
+
channel.open do
|
26
|
+
begin
|
27
|
+
AMQ::Client::Exchange.new(client, channel, exchange_name, "my_shiny_metal_exchange_type")
|
28
|
+
rescue AMQ::Client::Exchange::IncompatibleExchangeTypeError => e
|
29
|
+
done
|
30
|
+
end
|
31
|
+
end # channel.open
|
32
|
+
end # em_amqp_connect
|
33
|
+
end # it
|
34
|
+
end # context
|
35
|
+
end # context
|
36
|
+
|
37
|
+
|
38
|
+
|
8
39
|
it "should create an exchange and trigger a callback" do
|
9
40
|
em_amqp_connect do |client|
|
10
41
|
channel = AMQ::Client::Channel.new(client, 1)
|
11
42
|
channel.open do
|
12
|
-
exchange = AMQ::Client::Exchange.new(client, channel, exchange_name,
|
43
|
+
exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, "fanout")
|
13
44
|
exchange.declare do
|
14
45
|
exchange.delete
|
15
46
|
done(0.2)
|
@@ -4,8 +4,15 @@ require "spec_helper"
|
|
4
4
|
require "amq/client/entity"
|
5
5
|
|
6
6
|
describe AMQ::Client::Entity do
|
7
|
+
let(:klazz) do
|
8
|
+
Class.new do
|
9
|
+
include AMQ::Client::Entity
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
7
14
|
subject do
|
8
|
-
|
15
|
+
klazz.new(Object.new)
|
9
16
|
end
|
10
17
|
|
11
18
|
it "should maintain an associative array of callbacks" do
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
|
-
require "amq/client/
|
4
|
+
require "amq/client/openable"
|
5
5
|
|
6
|
-
describe AMQ::Client::
|
6
|
+
describe AMQ::Client::Openable do
|
7
7
|
subject do
|
8
|
-
Class.new { include AMQ::Client::
|
8
|
+
Class.new { include AMQ::Client::Openable }.new
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "#status=" do
|
@@ -17,7 +17,7 @@ describe AMQ::Client::StatusMixin do
|
|
17
17
|
|
18
18
|
context "when given value isn't in the permitted values" do
|
19
19
|
it "should raise ImproperStatusError" do
|
20
|
-
lambda { subject.status = :sleepy }.should raise_error(AMQ::Client::
|
20
|
+
lambda { subject.status = :sleepy }.should raise_error(AMQ::Client::Openable::ImproperStatusError)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/spec/unit/client_spec.rb
CHANGED
@@ -7,14 +7,12 @@ require "amq/client"
|
|
7
7
|
describe AMQ::Client do
|
8
8
|
if RUBY_PLATFORM =~ /java/
|
9
9
|
ADAPTERS = {
|
10
|
-
:event_machine => "EventMachineClient"
|
11
|
-
:socket => "SocketClient"
|
10
|
+
:event_machine => "EventMachineClient"
|
12
11
|
}
|
13
12
|
else
|
14
13
|
ADAPTERS = {
|
15
14
|
:event_machine => "EventMachineClient",
|
16
|
-
:coolio => "CoolioClient"
|
17
|
-
:socket => "SocketClient"
|
15
|
+
:coolio => "CoolioClient"
|
18
16
|
}
|
19
17
|
end
|
20
18
|
|
@@ -29,7 +27,7 @@ describe AMQ::Client do
|
|
29
27
|
end
|
30
28
|
|
31
29
|
it "should provide info about path to the adapter" do
|
32
|
-
|
30
|
+
require @meta[:path]
|
33
31
|
end
|
34
32
|
|
35
33
|
it "should provide info about const_name" do
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amq-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: -
|
4
|
+
hash: -3702664420
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 7
|
9
9
|
- 0
|
10
10
|
- alpha
|
11
|
-
-
|
12
|
-
version: 0.7.0.
|
11
|
+
- 24
|
12
|
+
version: 0.7.0.alpha24
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Jakub Stastny
|
@@ -20,7 +20,7 @@ autorequire:
|
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
22
|
|
23
|
-
date: 2011-05-
|
23
|
+
date: 2011-05-17 00:00:00 Z
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: eventmachine
|
@@ -127,9 +127,6 @@ files:
|
|
127
127
|
- examples/eventmachine_adapter/tx_commit.rb
|
128
128
|
- examples/eventmachine_adapter/tx_rollback.rb
|
129
129
|
- examples/eventmachine_adapter/tx_select.rb
|
130
|
-
- examples/socket_adapter/basics.rb
|
131
|
-
- examples/socket_adapter/connection.rb
|
132
|
-
- examples/socket_adapter/multiple_connections.rb
|
133
130
|
- examples/tls_certificates/client/cert.pem
|
134
131
|
- examples/tls_certificates/client/key.pem
|
135
132
|
- examples/tls_certificates/client/keycert.p12
|
@@ -155,7 +152,7 @@ files:
|
|
155
152
|
- lib/amq/client/adapter.rb
|
156
153
|
- lib/amq/client/adapters/coolio.rb
|
157
154
|
- lib/amq/client/adapters/event_machine.rb
|
158
|
-
- lib/amq/client/
|
155
|
+
- lib/amq/client/callbacks.rb
|
159
156
|
- lib/amq/client/channel.rb
|
160
157
|
- lib/amq/client/connection.rb
|
161
158
|
- lib/amq/client/entity.rb
|
@@ -166,13 +163,14 @@ files:
|
|
166
163
|
- lib/amq/client/extensions/rabbitmq/confirm.rb
|
167
164
|
- lib/amq/client/framing/io/frame.rb
|
168
165
|
- lib/amq/client/framing/string/frame.rb
|
166
|
+
- lib/amq/client/handlers_registry.rb
|
169
167
|
- lib/amq/client/logging.rb
|
170
|
-
- lib/amq/client/
|
171
|
-
- lib/amq/client/mixins/status.rb
|
172
|
-
- lib/amq/client/protocol/get_response.rb
|
168
|
+
- lib/amq/client/openable.rb
|
173
169
|
- lib/amq/client/queue.rb
|
170
|
+
- lib/amq/client/server_named_entity.rb
|
174
171
|
- lib/amq/client/settings.rb
|
175
172
|
- lib/amq/client/version.rb
|
173
|
+
- lib/amq/protocol/get_response.rb
|
176
174
|
- spec/benchmarks/adapters.rb
|
177
175
|
- spec/client/framing/io_frame_spec.rb
|
178
176
|
- spec/client/framing/string_frame_spec.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
|
4
|
-
require "bundler"
|
5
|
-
|
6
|
-
Bundler.setup
|
7
|
-
Bundler.require(:default)
|
8
|
-
|
9
|
-
$LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__))
|
10
|
-
|
11
|
-
require "amq/client/adapters/socket"
|
12
|
-
|
13
|
-
AMQ::Client::SocketClient.connect(:host => "localhost") do |client|
|
14
|
-
# Socket API is synchronous, so we don't need any callback here:
|
15
|
-
tasks = client.queue("tasks", 1)
|
16
|
-
tasks.consume do |headers, message| # TODO: this is async, we need to use a loop
|
17
|
-
puts ""
|
18
|
-
end
|
19
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
|
4
|
-
require "bundler"
|
5
|
-
|
6
|
-
Bundler.setup
|
7
|
-
Bundler.require(:default)
|
8
|
-
|
9
|
-
$LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__))
|
10
|
-
|
11
|
-
require "amq/client/adapters/socket"
|
12
|
-
require "amq/client/amqp/queue"
|
13
|
-
require "amq/client/amqp/exchange"
|
14
|
-
|
15
|
-
AMQ::Client::SocketClient.connect(:port => 5672) do |client|
|
16
|
-
begin
|
17
|
-
client.handshake
|
18
|
-
|
19
|
-
# Ruby developers are used to use blocks usually synchronously
|
20
|
-
# (so they are called +/- immediately), but this is NOT the case!
|
21
|
-
# We always have to wait for the response from the broker, so think
|
22
|
-
# about the following blocks are true callbacks as you know them
|
23
|
-
# from JavaScript (i. e. window.onload = function () {}).
|
24
|
-
|
25
|
-
# The only exception is when you use {nowait: true}, then the
|
26
|
-
# callback is called immediately.
|
27
|
-
channel = AMQ::Client::Channel.new(client, 1)
|
28
|
-
channel.open { puts "Channel #{channel.id} opened!" }
|
29
|
-
|
30
|
-
queue = AMQ::Client::Queue.new(client, "", channel)
|
31
|
-
queue.declare { puts "Queue #{queue.name.inspect} declared!" }
|
32
|
-
|
33
|
-
exchange = AMQ::Client::Exchange.new(client, "tasks", :fanout, channel)
|
34
|
-
exchange.declare { puts "Exchange #{exchange.name.inspect} declared!" }
|
35
|
-
|
36
|
-
until client.connection.closed?
|
37
|
-
client.receive_async
|
38
|
-
sleep 1
|
39
|
-
end
|
40
|
-
rescue Interrupt
|
41
|
-
warn "Manually interrupted, terminating ..."
|
42
|
-
rescue Exception => exception
|
43
|
-
STDERR.puts "\n\e[1;31m[#{exception.class}] #{exception.message}\e[0m"
|
44
|
-
exception.backtrace.each do |line|
|
45
|
-
line = "\e[0;36m#{line}\e[0m" if line.match(Regexp::quote(File.basename(__FILE__)))
|
46
|
-
STDERR.puts " - " + line
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# TODO:
|
52
|
-
# AMQ::Client.connect(:adapter => :socket)
|
53
|
-
# Support for frame_max, heartbeat from Connection.Tune
|
@@ -1,17 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
|
4
|
-
# Each connection respond to a TCP connection,
|
5
|
-
# hence we need to use more client.connect calls.
|
6
|
-
|
7
|
-
Thread.new do
|
8
|
-
AMQ::Client::SocketClient.connect(:port => 5672) do |client|
|
9
|
-
# ...
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
Thread.new do
|
14
|
-
AMQ::Client::SocketClient.connect(:port => 5672) do |client|
|
15
|
-
# ...
|
16
|
-
end
|
17
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "socket"
|
4
|
-
require "amq/client"
|
5
|
-
require "amq/client/framing/io/frame"
|
6
|
-
|
7
|
-
module AMQ
|
8
|
-
module Client
|
9
|
-
class SocketClient
|
10
|
-
|
11
|
-
#
|
12
|
-
# Behaviors
|
13
|
-
#
|
14
|
-
|
15
|
-
include AMQ::Client::Adapter
|
16
|
-
|
17
|
-
self.sync = true
|
18
|
-
|
19
|
-
#
|
20
|
-
# API
|
21
|
-
#
|
22
|
-
|
23
|
-
def establish_connection(settings)
|
24
|
-
# NOTE: this doesn't work with "localhost", I don't know why:
|
25
|
-
settings[:host] = "127.0.0.1" if settings[:host] == "localhost"
|
26
|
-
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
27
|
-
sockaddr = Socket.pack_sockaddr_in(settings[:port], settings[:host])
|
28
|
-
|
29
|
-
@socket.connect(sockaddr)
|
30
|
-
rescue Errno::ECONNREFUSED => exception
|
31
|
-
message = "Don't forget to start an AMQP broker first!\nThe original message: #{exception.message}"
|
32
|
-
raise exception.class.new(message)
|
33
|
-
rescue Exception => exception
|
34
|
-
self.disconnect if self.connected?
|
35
|
-
raise exception
|
36
|
-
end
|
37
|
-
|
38
|
-
def register_connection_callback(&block)
|
39
|
-
if block
|
40
|
-
block.call(self)
|
41
|
-
self.disconnect
|
42
|
-
else
|
43
|
-
self
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def connection
|
48
|
-
@socket
|
49
|
-
end # connection
|
50
|
-
|
51
|
-
def connected?
|
52
|
-
@socket && !@socket.closed?
|
53
|
-
end
|
54
|
-
|
55
|
-
def close_connection
|
56
|
-
@socket.close
|
57
|
-
end
|
58
|
-
|
59
|
-
def send_raw(data)
|
60
|
-
@socket.write(data)
|
61
|
-
end
|
62
|
-
|
63
|
-
def receive
|
64
|
-
frame = AMQ::Client::Framing::IO::Frame.decode(@socket)
|
65
|
-
self.receive_frame(frame)
|
66
|
-
frame
|
67
|
-
end
|
68
|
-
|
69
|
-
def receive_async
|
70
|
-
# NOTE: this might work with Socket#eof? as well, it can be better ...
|
71
|
-
# self.receive unless @socket.eof?
|
72
|
-
|
73
|
-
@sockets ||= [@socket] # It'll be always only one socket, but we don't want to create many arrays, mind the GC!
|
74
|
-
array = IO.select(@sockets, nil, nil, nil)
|
75
|
-
array[0].each do |socket|
|
76
|
-
res = self.receive
|
77
|
-
end
|
78
|
-
res
|
79
|
-
end
|
80
|
-
|
81
|
-
def read_until_receives(klass)
|
82
|
-
if self.sync?
|
83
|
-
until (frame = self.receive) && frame.is_a?(Protocol::MethodFrame) && frame.method_class == klass
|
84
|
-
sleep 0.1
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|