amq-client 0.7.0.alpha23 → 0.7.0.alpha24
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.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
|