amq-client 0.7.0.alpha3 → 0.7.0.alpha4
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 +1 -0
- data/Gemfile +4 -3
- data/amq-client.gemspec +1 -1
- data/examples/coolio_adapter/example_helper.rb +1 -1
- data/examples/eventmachine_adapter/connection_loss_handler.rb +43 -0
- data/lib/amq/client.rb +55 -0
- data/lib/amq/client/adapter.rb +17 -49
- data/lib/amq/client/adapters/coolio.rb +16 -66
- data/lib/amq/client/adapters/event_machine.rb +130 -45
- data/lib/amq/client/adapters/socket.rb +9 -8
- data/lib/amq/client/channel.rb +23 -5
- data/lib/amq/client/connection.rb +6 -5
- data/lib/amq/client/entity.rb +55 -40
- data/lib/amq/client/version.rb +1 -1
- data/spec/benchmarks/adapters.rb +1 -1
- data/spec/integration/coolio/basic_ack_spec.rb +1 -4
- data/spec/integration/coolio/basic_get_spec.rb +1 -1
- data/spec/integration/coolio/basic_return_spec.rb +1 -1
- data/spec/integration/coolio/channel_close_spec.rb +1 -1
- data/spec/integration/coolio/channel_flow_spec.rb +1 -1
- data/spec/integration/coolio/spec_helper.rb +1 -1
- data/spec/integration/coolio/tx_commit_spec.rb +1 -1
- data/spec/integration/coolio/tx_rollback_spec.rb +1 -1
- data/spec/regression/bad_frame_slicing_in_adapters_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/client_spec.rb +74 -0
- metadata +209 -187
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -3,16 +3,17 @@
|
|
3
3
|
source :rubygems
|
4
4
|
|
5
5
|
# Use local clones if possible.
|
6
|
+
# If you want to use your local copy, just symlink it to vendor.
|
6
7
|
def custom_gem(name, options = Hash.new)
|
7
|
-
local_path = File.expand_path("
|
8
|
-
if
|
8
|
+
local_path = File.expand_path("../vendor/#{name}", __FILE__)
|
9
|
+
if File.exist?(local_path)
|
9
10
|
gem name, options.merge(:path => local_path).delete_if { |key, _| [:git, :branch].include?(key) }
|
10
11
|
else
|
11
12
|
gem name, options
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
15
|
-
gem "eventmachine"
|
16
|
+
gem "eventmachine"
|
16
17
|
# cool.io uses iobuffer that won't compile on JRuby
|
17
18
|
# (and, probably, Windows)
|
18
19
|
gem "cool.io", :platform => :ruby
|
data/amq-client.gemspec
CHANGED
@@ -17,7 +17,7 @@ end
|
|
17
17
|
|
18
18
|
|
19
19
|
def amq_client_example(description = "", &block)
|
20
|
-
AMQ::Client::
|
20
|
+
AMQ::Client::CoolioClient.connect(:port => 5672, :vhost => "/amq_client_testbed") do |client|
|
21
21
|
begin
|
22
22
|
puts
|
23
23
|
puts
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
__dir = File.join(File.dirname(File.expand_path(__FILE__)))
|
5
|
+
require File.join(__dir, "example_helper")
|
6
|
+
|
7
|
+
|
8
|
+
EM.run do
|
9
|
+
reconnector = Proc.new { |client, settings|
|
10
|
+
puts "Asked to reconnect to #{settings[:host]}:#{settings[:port]}"
|
11
|
+
|
12
|
+
|
13
|
+
}
|
14
|
+
|
15
|
+
|
16
|
+
AMQ::Client::EventMachineClient.connect(:port => 5672,
|
17
|
+
:vhost => "/amq_client_testbed",
|
18
|
+
:user => "amq_client_gem",
|
19
|
+
:password => "amq_client_gem_password",
|
20
|
+
:connection_timeout => 0.3,
|
21
|
+
:on_tcp_connection_failure => Proc.new { |settings| puts "Failed to connect, this was NOT expected"; EM.stop }) do |client|
|
22
|
+
|
23
|
+
client.on_tcp_connection_loss do |cl, settings|
|
24
|
+
puts "tcp_connection_loss handler kicks in"
|
25
|
+
cl.reconnect(1)
|
26
|
+
end
|
27
|
+
|
28
|
+
show_stopper = Proc.new {
|
29
|
+
client.disconnect {
|
30
|
+
puts "Disconnected. Exiting…"
|
31
|
+
EM.stop
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
Signal.trap "INT", show_stopper
|
36
|
+
Signal.trap "TERM", show_stopper
|
37
|
+
|
38
|
+
EM.add_timer(30, show_stopper)
|
39
|
+
|
40
|
+
|
41
|
+
puts "Connected, authenticated. To really exercise this example, shut AMQP broker down for a few seconds. If you don't it will exit gracefully in 30 seconds."
|
42
|
+
end
|
43
|
+
end
|
data/lib/amq/client.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
require "amq/client/version"
|
4
4
|
require "amq/client/exceptions"
|
5
5
|
require "amq/client/adapter"
|
6
|
+
require "amq/client/channel"
|
7
|
+
require "amq/client/exchange"
|
8
|
+
require "amq/client/queue"
|
6
9
|
|
7
10
|
begin
|
8
11
|
require "amq/protocol/client"
|
@@ -13,3 +16,55 @@ rescue LoadError => exception
|
|
13
16
|
raise exception
|
14
17
|
end
|
15
18
|
end
|
19
|
+
|
20
|
+
module AMQ
|
21
|
+
module Client
|
22
|
+
# List all the available as a hash of {adapter_name: metadata},
|
23
|
+
# where metadata are hash with :path and :const_name keys.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# AMQ::Client.adapters[:socket]
|
27
|
+
# # => {path: full_path, const_name: "SocketClient"}}
|
28
|
+
# @return [Hash]
|
29
|
+
# @api public
|
30
|
+
def self.adapters
|
31
|
+
@adapters ||= begin
|
32
|
+
root = File.expand_path("../client/adapters", __FILE__)
|
33
|
+
Dir.glob("#{root}/*.rb").inject(Hash.new) do |buffer, path|
|
34
|
+
name = path.match(/([^\/]+)\.rb$/)[1]
|
35
|
+
const_base = name.to_s.gsub(/(^|_)(.)/) { $2.upcase! }
|
36
|
+
meta = {:path => path, :const_name => "#{const_base}Client"}
|
37
|
+
buffer.merge!(name.to_sym => meta)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Establishes connection to AMQ broker using given adapter
|
43
|
+
# (defaults to the socket adapter) and returns it. The new
|
44
|
+
# connection object is yielded to the block if it is given.
|
45
|
+
#
|
46
|
+
# @example
|
47
|
+
# AMQ::Client.connect(adapter: "socket") do |client|
|
48
|
+
# # Use the client.
|
49
|
+
# end
|
50
|
+
# @param [Hash] Connection parameters, including :adapter to use.
|
51
|
+
# @api public
|
52
|
+
def self.connect(settings = nil, &block)
|
53
|
+
adapter = (settings && settings.delete(:adapter)) || :socket
|
54
|
+
adapter = load_adapter(adapter)
|
55
|
+
adapter.connect(settings, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Loads adapter from amq/client/adapters.
|
59
|
+
#
|
60
|
+
# @raise [InvalidAdapterNameError] When loading attempt failed (LoadError was raised).
|
61
|
+
def self.load_adapter(adapter)
|
62
|
+
meta = self.adapters[adapter.to_sym]
|
63
|
+
|
64
|
+
require meta[:path]
|
65
|
+
const_get(meta[:const_name])
|
66
|
+
rescue LoadError
|
67
|
+
raise InvalidAdapterNameError.new(adapter)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/amq/client/adapter.rb
CHANGED
@@ -4,6 +4,7 @@ require "amq/client/logging"
|
|
4
4
|
require "amq/client/settings"
|
5
5
|
require "amq/client/entity"
|
6
6
|
require "amq/client/connection"
|
7
|
+
require "amq/client/channel"
|
7
8
|
|
8
9
|
module AMQ
|
9
10
|
# For overview of AMQP client adapters API, see {AMQ::Client::Adapter}
|
@@ -104,55 +105,25 @@ module AMQ
|
|
104
105
|
end
|
105
106
|
|
106
107
|
|
107
|
-
# @example Registering Channel implementation
|
108
|
-
# Adapter.register_entity(:channel, Channel)
|
109
|
-
# # ... so then I can do:
|
110
|
-
# channel = client.channel(1)
|
111
|
-
# # instead of:
|
112
|
-
# channel = Channel.new(client, 1)
|
113
|
-
def register_entity(name, klass)
|
114
|
-
define_method(name) do |*args, &block|
|
115
|
-
klass.new(self, *args, &block)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
108
|
# Establishes connection to AMQ broker and returns it. New connection object is yielded to
|
120
109
|
# the block if it is given.
|
121
110
|
#
|
111
|
+
# @example Specifying adapter via the :adapter option
|
112
|
+
# AMQ::Client::Adapter.connect(adapter: "socket")
|
113
|
+
# @example Specifying using custom adapter class
|
114
|
+
# AMQ::Client::SocketClient.connect
|
122
115
|
# @param [Hash] Connection parameters, including :adapter to use.
|
123
116
|
# @api public
|
124
117
|
def connect(settings = nil, &block)
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
adapter = self
|
129
|
-
end
|
118
|
+
# TODO: this doesn't look very nice, do we need it?
|
119
|
+
# Let's make it an instance thing by instance = self.new(settings)
|
120
|
+
@settings = settings = Settings.configure(settings)
|
130
121
|
|
131
|
-
|
132
|
-
instance
|
133
|
-
instance.
|
134
|
-
# We don't need anything more, once the server receives the preable, he sends Connection.Start, we just have to reply.
|
122
|
+
instance = self.new
|
123
|
+
instance.establish_connection(settings)
|
124
|
+
instance.register_connection_callback(&block)
|
135
125
|
|
136
|
-
|
137
|
-
block.call(instance)
|
138
|
-
|
139
|
-
instance.disconnect
|
140
|
-
else
|
141
|
-
instance
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
|
146
|
-
# Loads adapter from amq/client/adapters.
|
147
|
-
#
|
148
|
-
# @raise [InvalidAdapterNameError] When loading attempt failed (LoadError was raised).
|
149
|
-
def load_adapter(adapter)
|
150
|
-
require "amq/client/adapters/#{adapter}"
|
151
|
-
|
152
|
-
const_name = adapter.to_s.gsub(/(^|_)(.)/) { $2.upcase! }
|
153
|
-
const_get(const_name)
|
154
|
-
rescue LoadError
|
155
|
-
raise InvalidAdapterNameError.new(adapter)
|
126
|
+
instance
|
156
127
|
end
|
157
128
|
|
158
129
|
# @see AMQ::Client::Adapter
|
@@ -184,17 +155,14 @@ module AMQ
|
|
184
155
|
|
185
156
|
include AMQ::Client::StatusMixin
|
186
157
|
|
158
|
+
extend RegisterEntityMixin
|
159
|
+
|
160
|
+
register_entity :channel, AMQ::Client::Channel
|
187
161
|
|
188
162
|
#
|
189
163
|
# API
|
190
164
|
#
|
191
165
|
|
192
|
-
def self.load_adapter(adapter)
|
193
|
-
ClassMethods.load_adapter(adapter)
|
194
|
-
end
|
195
|
-
|
196
|
-
|
197
|
-
|
198
166
|
def initialize(*args)
|
199
167
|
super(*args)
|
200
168
|
|
@@ -229,6 +197,8 @@ module AMQ
|
|
229
197
|
# @todo This method should await broker's response with Close-Ok. {http://github.com/michaelklishin MK}.
|
230
198
|
# @see #close_connection
|
231
199
|
def disconnect(reply_code = 200, reply_text = "Goodbye", &block)
|
200
|
+
@intentionally_closing_connection = true
|
201
|
+
|
232
202
|
self.on_disconnection(&block)
|
233
203
|
closing!
|
234
204
|
self.connection.close(reply_code, reply_text)
|
@@ -352,5 +322,3 @@ module AMQ
|
|
352
322
|
end # Adapter
|
353
323
|
end # Client
|
354
324
|
end # AMQ
|
355
|
-
|
356
|
-
require "amq/client/channel"
|
@@ -4,12 +4,11 @@
|
|
4
4
|
|
5
5
|
require "cool.io"
|
6
6
|
require "amq/client"
|
7
|
-
|
8
7
|
require "amq/client/framing/string/frame"
|
9
8
|
|
10
9
|
module AMQ
|
11
10
|
module Client
|
12
|
-
class
|
11
|
+
class CoolioClient
|
13
12
|
class Socket < ::Coolio::TCPSocket
|
14
13
|
attr_accessor :adapter
|
15
14
|
|
@@ -48,27 +47,31 @@ module AMQ
|
|
48
47
|
end
|
49
48
|
end
|
50
49
|
|
50
|
+
#
|
51
51
|
# Behaviors
|
52
|
+
#
|
53
|
+
|
52
54
|
include AMQ::Client::Adapter
|
55
|
+
include AMQ::Client::CallbacksMixin
|
53
56
|
|
54
57
|
self.sync = false
|
55
58
|
|
59
|
+
#
|
56
60
|
# API
|
61
|
+
#
|
62
|
+
|
57
63
|
attr_accessor :socket
|
58
64
|
attr_accessor :callbacks
|
59
65
|
attr_accessor :connections
|
60
66
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
instance.on_connection(&block)
|
70
|
-
instance
|
71
|
-
end
|
67
|
+
def establish_connection(settings)
|
68
|
+
socket = Socket.connect(self, settings[:host], settings[:port])
|
69
|
+
socket.attach(Cool.io::Loop.default)
|
70
|
+
self.socket = socket
|
71
|
+
end
|
72
|
+
|
73
|
+
def register_connection_callback(&block)
|
74
|
+
self.on_connection(&block)
|
72
75
|
end
|
73
76
|
|
74
77
|
def initialize
|
@@ -138,59 +141,6 @@ module AMQ
|
|
138
141
|
end
|
139
142
|
|
140
143
|
|
141
|
-
|
142
|
-
#
|
143
|
-
# Callbacks
|
144
|
-
#
|
145
|
-
|
146
|
-
def redefine_callback(event, callable = nil, &block)
|
147
|
-
f = (callable || block)
|
148
|
-
# yes, re-assign!
|
149
|
-
@callbacks[event] = [f]
|
150
|
-
|
151
|
-
self
|
152
|
-
end
|
153
|
-
|
154
|
-
def define_callback(event, callable = nil, &block)
|
155
|
-
f = (callable || block)
|
156
|
-
@callbacks[event] ||= []
|
157
|
-
|
158
|
-
@callbacks[event] << f if f
|
159
|
-
|
160
|
-
self
|
161
|
-
end # define_callback(event, &block)
|
162
|
-
alias append_callback define_callback
|
163
|
-
|
164
|
-
def prepend_callback(event, &block)
|
165
|
-
@callbacks[event] ||= []
|
166
|
-
@callbacks[event].unshift(block)
|
167
|
-
|
168
|
-
self
|
169
|
-
end # prepend_callback(event, &block)
|
170
|
-
|
171
|
-
|
172
|
-
def exec_callback(name, *args, &block)
|
173
|
-
callbacks = Array(self.callbacks[name])
|
174
|
-
callbacks.map { |c| c.call(*args, &block) } if callbacks.any?
|
175
|
-
end
|
176
|
-
|
177
|
-
def exec_callback_once(name, *args, &block)
|
178
|
-
callbacks = Array(self.callbacks.delete(name))
|
179
|
-
callbacks.map { |c| c.call(*args, &block) } if callbacks.any?
|
180
|
-
end
|
181
|
-
|
182
|
-
def exec_callback_yielding_self(name, *args, &block)
|
183
|
-
callbacks = Array(self.callbacks[name])
|
184
|
-
callbacks.map { |c| c.call(self, *args, &block) } if callbacks.any?
|
185
|
-
end
|
186
|
-
|
187
|
-
def exec_callback_once_yielding_self(name, *args, &block)
|
188
|
-
callbacks = Array(self.callbacks.delete(name))
|
189
|
-
callbacks.map { |c| c.call(self, *args, &block) } if callbacks.any?
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
|
194
144
|
protected
|
195
145
|
|
196
146
|
def post_init
|
@@ -1,12 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require "eventmachine"
|
3
4
|
require "amq/client"
|
4
|
-
require "amq/client/channel"
|
5
|
-
require "amq/client/exchange"
|
6
5
|
require "amq/client/framing/string/frame"
|
7
6
|
|
8
|
-
require "eventmachine"
|
9
|
-
|
10
7
|
module AMQ
|
11
8
|
module Client
|
12
9
|
class EventMachineClient < EM::Connection
|
@@ -23,27 +20,52 @@ module AMQ
|
|
23
20
|
|
24
21
|
self.sync = false
|
25
22
|
|
26
|
-
register_entity :channel, AMQ::Client::Channel
|
27
|
-
register_entity :exchange, AMQ::Client::Exchange
|
28
|
-
|
29
23
|
#
|
30
24
|
# API
|
31
25
|
#
|
32
26
|
|
33
27
|
def self.connect(settings = nil, &block)
|
34
|
-
settings =
|
28
|
+
@settings = settings = Settings.configure(settings)
|
29
|
+
|
35
30
|
instance = EventMachine.connect(settings[:host], settings[:port], self, settings)
|
31
|
+
instance.register_connection_callback(&block)
|
32
|
+
|
33
|
+
instance
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def reconnect(period = 5, force = false)
|
38
|
+
if @reconnecting and not force
|
39
|
+
EventMachine::Timer.new(period) {
|
40
|
+
reconnect(period, true)
|
41
|
+
}
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
if !@reconnecting
|
46
|
+
@reconnecting = true
|
47
|
+
@connections.each { |c| c.handle_connection_interruption }
|
48
|
+
self.reset
|
49
|
+
end
|
50
|
+
|
51
|
+
self.reconnect(@settings[:host], @settings[:port])
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def establish_connection(settings)
|
56
|
+
# Unfortunately there doesn't seem to be any sane way
|
57
|
+
# how to get EventMachine connect to the instance level.
|
58
|
+
end
|
36
59
|
|
60
|
+
def register_connection_callback(&block)
|
37
61
|
unless block.nil?
|
38
62
|
# delay calling block we were given till after we receive
|
39
63
|
# connection.open-ok. Connection will notify us when
|
40
64
|
# that happens.
|
41
|
-
|
42
|
-
block.call(
|
65
|
+
self.on_connection do
|
66
|
+
block.call(self)
|
43
67
|
end
|
44
68
|
end
|
45
|
-
|
46
|
-
instance
|
47
69
|
end
|
48
70
|
|
49
71
|
|
@@ -53,24 +75,21 @@ module AMQ
|
|
53
75
|
def initialize(*args)
|
54
76
|
super(*args)
|
55
77
|
|
78
|
+
@connections = Array.new
|
79
|
+
# track TCP connection state, used to detect initial TCP connection failures.
|
80
|
+
@tcp_connection_established = false
|
81
|
+
@tcp_connection_failed = false
|
82
|
+
@intentionally_closing_connection = false
|
83
|
+
|
56
84
|
# EventMachine::Connection's and Adapter's constructors arity
|
57
85
|
# make it easier to use *args. MK.
|
58
|
-
@settings
|
59
|
-
@connections = Array.new
|
86
|
+
@settings = args.first
|
60
87
|
@on_possible_authentication_failure = @settings[:on_possible_authentication_failure]
|
61
|
-
@on_tcp_connection_failure = @settings[:on_tcp_connection_failure] || Proc.new { |settings|
|
88
|
+
@on_tcp_connection_failure = @settings[:on_tcp_connection_failure] || Proc.new { |settings|
|
89
|
+
raise AMQ::Client::TCPConnectionFailed.new(settings)
|
90
|
+
}
|
62
91
|
|
63
|
-
|
64
|
-
@connection_deferrable = Deferrable.new
|
65
|
-
@disconnection_deferrable = Deferrable.new
|
66
|
-
|
67
|
-
@authenticating = false
|
68
|
-
|
69
|
-
# succeeds when connection is open, that is, vhost is selected
|
70
|
-
# and client is given green light to proceed.
|
71
|
-
@connection_opened_deferrable = Deferrable.new
|
72
|
-
|
73
|
-
@tcp_connection_established = false
|
92
|
+
self.reset
|
74
93
|
|
75
94
|
if self.heartbeat_interval > 0
|
76
95
|
@last_server_heartbeat = Time.now
|
@@ -79,10 +98,6 @@ module AMQ
|
|
79
98
|
end # initialize(*args)
|
80
99
|
|
81
100
|
|
82
|
-
def establish_connection(settings)
|
83
|
-
# an intentional no-op
|
84
|
-
end
|
85
|
-
|
86
101
|
alias send_raw send_data
|
87
102
|
|
88
103
|
|
@@ -111,8 +126,6 @@ module AMQ
|
|
111
126
|
# to take some time and to not be worth in as long as #post_init
|
112
127
|
# works fine. MK.
|
113
128
|
upgrade_to_tls_if_necessary
|
114
|
-
|
115
|
-
self.handshake
|
116
129
|
rescue Exception => error
|
117
130
|
raise error
|
118
131
|
end # post_init
|
@@ -121,8 +134,22 @@ module AMQ
|
|
121
134
|
def connection_completed
|
122
135
|
# we only can safely set this value here because EventMachine is a lovely piece of
|
123
136
|
# software that calls #post_init before #unbind even when TCP connection
|
124
|
-
# fails.
|
125
|
-
@tcp_connection_established
|
137
|
+
# fails. MK.
|
138
|
+
@tcp_connection_established = true
|
139
|
+
# again, this is because #unbind is called in different situations
|
140
|
+
# and there is no easy way to tell initial connection failure
|
141
|
+
# from connection loss. Not in EventMachine 0.12.x, anyway. MK.
|
142
|
+
@had_successfull_connected_before = true
|
143
|
+
|
144
|
+
@reconnecting = false
|
145
|
+
|
146
|
+
self.handshake
|
147
|
+
end
|
148
|
+
|
149
|
+
def close_connection(*args)
|
150
|
+
@intentionally_closing_connection = true
|
151
|
+
|
152
|
+
super(*args)
|
126
153
|
end
|
127
154
|
|
128
155
|
# Called by EventMachine reactor when
|
@@ -132,19 +159,22 @@ module AMQ
|
|
132
159
|
# * There is a network connection issue
|
133
160
|
# * Initial TCP connection fails
|
134
161
|
def unbind
|
135
|
-
if !@tcp_connection_established
|
162
|
+
if !@tcp_connection_established && !@had_successfull_connected_before
|
163
|
+
@tcp_connection_failed = true
|
136
164
|
self.tcp_connection_failed
|
137
165
|
end
|
138
166
|
|
139
167
|
closing!
|
140
|
-
|
141
168
|
@tcp_connection_established = false
|
142
169
|
|
143
|
-
@connections.each { |c| c.
|
170
|
+
@connections.each { |c| c.handle_connection_interruption }
|
144
171
|
@disconnection_deferrable.succeed
|
145
172
|
|
146
173
|
closed!
|
147
174
|
|
175
|
+
|
176
|
+
self.tcp_connection_lost if !@intentionally_closing_connection && @had_successfull_connected_before
|
177
|
+
|
148
178
|
# since AMQP spec dictates that authentication failure is a protocol exception
|
149
179
|
# and protocol exceptions result in connection closure, check whether we are
|
150
180
|
# in the authentication stage. If so, it is likely to signal an authentication
|
@@ -170,23 +200,35 @@ module AMQ
|
|
170
200
|
end
|
171
201
|
end
|
172
202
|
|
173
|
-
|
174
|
-
|
203
|
+
# Defines a callback that will be executed when AMQP connection is considered open,
|
204
|
+
# after client and broker has agreed on max channel identifier and maximum allowed frame
|
205
|
+
# size. You can define more than one callback.
|
206
|
+
#
|
207
|
+
# @see #on_open
|
208
|
+
# @api public
|
175
209
|
def on_connection(&block)
|
176
210
|
@connection_deferrable.callback(&block)
|
177
211
|
end # on_connection(&block)
|
178
212
|
|
179
|
-
#
|
213
|
+
# Called by AMQ::Client::Connection after we receive connection.open-ok.
|
214
|
+
# @api public
|
180
215
|
def connection_successful
|
181
216
|
@connection_deferrable.succeed
|
182
217
|
end # connection_successful
|
183
218
|
|
184
219
|
|
185
|
-
|
220
|
+
# Defines a callback that will be executed when AMQP connection is considered open,
|
221
|
+
# before client and broker has agreed on max channel identifier and maximum allowed frame
|
222
|
+
# size. You can define more than one callback.
|
223
|
+
#
|
224
|
+
# @see #on_connection
|
225
|
+
# @api public
|
186
226
|
def on_open(&block)
|
187
227
|
@connection_opened_deferrable.callback(&block)
|
188
228
|
end # on_open(&block)
|
189
229
|
|
230
|
+
# Called by AMQ::Client::Connection after we receive connection.tune.
|
231
|
+
# @api public
|
190
232
|
def open_successful
|
191
233
|
@authenticating = false
|
192
234
|
@connection_opened_deferrable.succeed
|
@@ -195,31 +237,61 @@ module AMQ
|
|
195
237
|
end # open_successful
|
196
238
|
|
197
239
|
|
198
|
-
|
240
|
+
# Defines a callback that will be run when broker confirms connection termination
|
241
|
+
# (client receives connection.close-ok). You can define more than one callback.
|
242
|
+
#
|
243
|
+
# @api public
|
199
244
|
def on_disconnection(&block)
|
200
245
|
@disconnection_deferrable.callback(&block)
|
201
246
|
end # on_disconnection(&block)
|
202
247
|
|
203
|
-
#
|
248
|
+
# Called by AMQ::Client::Connection after we receive connection.close-ok.
|
249
|
+
#
|
250
|
+
# @api public
|
204
251
|
def disconnection_successful
|
205
252
|
@disconnection_deferrable.succeed
|
206
253
|
|
207
254
|
self.close_connection
|
255
|
+
self.reset
|
208
256
|
closed!
|
209
257
|
end # disconnection_successful
|
210
258
|
|
211
259
|
|
212
|
-
|
260
|
+
# Defines a callback that will be run when initial TCP connection fails.
|
261
|
+
# You can define only one callback.
|
262
|
+
#
|
263
|
+
# @api public
|
213
264
|
def on_tcp_connection_failure(&block)
|
214
265
|
@on_tcp_connection_failure = block
|
215
266
|
end
|
216
267
|
|
268
|
+
# Called when initial TCP connection fails.
|
269
|
+
# @api public
|
217
270
|
def tcp_connection_failed
|
218
271
|
@on_tcp_connection_failure.call(@settings) if @on_tcp_connection_failure
|
219
272
|
end
|
220
273
|
|
221
274
|
|
275
|
+
# Defines a callback that will be run when initial TCP connection fails.
|
276
|
+
# You can define only one callback.
|
277
|
+
#
|
278
|
+
# @api public
|
279
|
+
def on_tcp_connection_loss(&block)
|
280
|
+
@on_tcp_connection_loss = block
|
281
|
+
end
|
282
|
+
|
283
|
+
# Called when initial TCP connection fails.
|
284
|
+
# @api public
|
285
|
+
def tcp_connection_lost
|
286
|
+
@on_tcp_connection_loss.call(self, @settings) if @on_tcp_connection_loss
|
287
|
+
end
|
288
|
+
|
289
|
+
|
222
290
|
|
291
|
+
# Defines a callback that will be run when TCP connection is closed before authentication
|
292
|
+
# finishes. Usually this means authentication failure. You can define only one callback.
|
293
|
+
#
|
294
|
+
# @api public
|
223
295
|
def on_possible_authentication_failure(&block)
|
224
296
|
@on_possible_authentication_failure = block
|
225
297
|
end
|
@@ -243,6 +315,19 @@ module AMQ
|
|
243
315
|
@size = 0
|
244
316
|
@payload = ""
|
245
317
|
@frames = Array.new
|
318
|
+
|
319
|
+
@chunk_buffer = ""
|
320
|
+
@connection_deferrable = Deferrable.new
|
321
|
+
@disconnection_deferrable = Deferrable.new
|
322
|
+
# succeeds when connection is open, that is, vhost is selected
|
323
|
+
# and client is given green light to proceed.
|
324
|
+
@connection_opened_deferrable = Deferrable.new
|
325
|
+
|
326
|
+
# used to track down whether authentication succeeded. AMQP 0.9.1 dictates
|
327
|
+
# that on authentication failure broker must close TCP connection without sending
|
328
|
+
# any more data. This is why we need to explicitly track whether we are past
|
329
|
+
# authentication stage to signal possible authentication failures.
|
330
|
+
@authenticating = false
|
246
331
|
end
|
247
332
|
|
248
333
|
# @see http://tools.ietf.org/rfc/rfc2595.txt RFC 2595
|
@@ -272,7 +357,7 @@ module AMQ
|
|
272
357
|
start_tls(tls_options)
|
273
358
|
elsif tls_options
|
274
359
|
start_tls
|
275
|
-
end
|
360
|
+
end
|
276
361
|
end
|
277
362
|
end # EventMachineClient
|
278
363
|
end # Client
|