onstomp 1.0.0pre1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/Rakefile +8 -0
- data/examples/openuri.rb +36 -0
- data/lib/onstomp.rb +4 -0
- data/lib/onstomp/client.rb +6 -5
- data/lib/onstomp/components.rb +0 -1
- data/lib/onstomp/components/frame_headers.rb +35 -38
- data/lib/onstomp/components/threaded_processor.rb +13 -0
- data/lib/onstomp/connections/base.rb +15 -8
- data/lib/onstomp/connections/stomp_1.rb +0 -6
- data/lib/onstomp/connections/stomp_1_0.rb +8 -0
- data/lib/onstomp/connections/stomp_1_1.rb +8 -0
- data/lib/onstomp/failover.rb +16 -0
- data/lib/onstomp/failover/buffers.rb +8 -0
- data/lib/onstomp/failover/buffers/written.rb +91 -0
- data/lib/onstomp/failover/client.rb +127 -0
- data/lib/onstomp/failover/failover_configurable.rb +63 -0
- data/lib/onstomp/failover/failover_events.rb +96 -0
- data/lib/onstomp/failover/new_with_failover.rb +20 -0
- data/lib/onstomp/failover/pools.rb +8 -0
- data/lib/onstomp/failover/pools/base.rb +39 -0
- data/lib/onstomp/failover/pools/round_robin.rb +17 -0
- data/lib/onstomp/failover/uri.rb +34 -0
- data/lib/onstomp/interfaces/client_configurable.rb +2 -6
- data/lib/onstomp/interfaces/client_events.rb +4 -0
- data/lib/onstomp/interfaces/connection_events.rb +3 -3
- data/lib/onstomp/interfaces/event_manager.rb +8 -0
- data/lib/onstomp/interfaces/uri_configurable.rb +7 -7
- data/lib/onstomp/open-uri.rb +37 -0
- data/lib/onstomp/open-uri/client_extensions.rb +88 -0
- data/lib/onstomp/open-uri/message_queue.rb +38 -0
- data/lib/onstomp/version.rb +1 -1
- data/spec/onstomp/client_spec.rb +1 -4
- data/spec/onstomp/components/frame_headers_spec.rb +2 -5
- data/spec/onstomp/connections/stomp_1_0_spec.rb +22 -0
- data/spec/onstomp/connections/stomp_1_1_spec.rb +22 -0
- data/spec/onstomp/connections/stomp_1_spec.rb +2 -19
- data/spec/onstomp/connections_spec.rb +4 -0
- data/spec/onstomp/failover/buffers/written_spec.rb +8 -0
- data/spec/onstomp/failover/client_spec.rb +38 -0
- data/spec/onstomp/failover/failover_events_spec.rb +75 -0
- data/spec/onstomp/failover/new_with_failover_spec.rb +16 -0
- data/spec/onstomp/failover/pools/base_spec.rb +54 -0
- data/spec/onstomp/failover/pools/round_robin_spec.rb +27 -0
- data/spec/onstomp/failover/uri_spec.rb +21 -0
- data/spec/onstomp/full_stacks/failover_spec.rb +55 -0
- data/spec/onstomp/full_stacks/onstomp_spec.rb +15 -0
- data/spec/onstomp/full_stacks/open-uri_spec.rb +40 -0
- data/spec/onstomp/full_stacks/ssl/README +6 -0
- data/spec/onstomp/full_stacks/ssl/broker_cert.csr +17 -0
- data/spec/onstomp/full_stacks/ssl/broker_cert.pem +72 -0
- data/spec/onstomp/full_stacks/ssl/broker_key.pem +27 -0
- data/spec/onstomp/full_stacks/ssl/client_cert.csr +17 -0
- data/spec/onstomp/full_stacks/ssl/client_cert.pem +72 -0
- data/spec/onstomp/full_stacks/ssl/client_key.pem +27 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/cacert.pem +17 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/index.txt +2 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/index.txt.attr +1 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/index.txt.attr.old +1 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/index.txt.old +1 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/newcerts/01.pem +72 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/newcerts/02.pem +72 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/private/cakey.pem +17 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/serial +1 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/serial.old +1 -0
- data/spec/onstomp/full_stacks/test_broker.rb +251 -0
- data/spec/onstomp/interfaces/connection_events_spec.rb +3 -1
- data/spec/onstomp/open-uri/client_extensions_spec.rb +113 -0
- data/spec/onstomp/open-uri/message_queue_spec.rb +29 -0
- data/spec/onstomp/open-uri_spec.rb +43 -0
- data/spec/spec_helper.rb +2 -0
- data/yard_extensions.rb +5 -1
- metadata +82 -8
- data/lib/onstomp/components/nil_processor.rb +0 -20
- data/spec/onstomp/components/nil_processor_spec.rb +0 -32
data/README.md
CHANGED
@@ -62,7 +62,7 @@ See the full {file:docs/LICENSE.md LICENSE} for details.
|
|
62
62
|
There are a few people/groups I'd like to thank for helping me with the
|
63
63
|
creation of this gem.
|
64
64
|
|
65
|
-
* Lionel Cons the good suggestions while I was implementing support for the
|
65
|
+
* Lionel Cons for the good suggestions while I was implementing support for the
|
66
66
|
STOMP 1.1 spec. Check out his Perl client [Net::STOMP::Client](http://search.cpan.org/~lcons/Net-STOMP-Client-0.9.5/lib/Net/STOMP/Client.pm)
|
67
67
|
* Brian McCallister, Johan Sørensen, Guy M. Allard and Thiago Morello for
|
68
68
|
their work on the `stomp` gem which introduced me to the STOMP protocol.
|
data/Rakefile
CHANGED
@@ -4,3 +4,11 @@ Bundler::GemHelper.install_tasks
|
|
4
4
|
require 'yard'
|
5
5
|
require File.expand_path("../yard_extensions", __FILE__)
|
6
6
|
YARD::Rake::YardocTask.new
|
7
|
+
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
desc "Run specs"
|
10
|
+
RSpec::Core::RakeTask.new do |t|
|
11
|
+
t.verbose = false
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :spec
|
data/examples/openuri.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
3
|
+
require 'onstomp'
|
4
|
+
require 'onstomp/open-uri'
|
5
|
+
|
6
|
+
open('stomp://localhost/queue/onstomp/openuri') do |c|
|
7
|
+
c.send "hello world!"
|
8
|
+
c.send "a fine day to you"
|
9
|
+
c.send "what rhymes with you?"
|
10
|
+
c.puts "may the rats eat your eyes"
|
11
|
+
c.send "I am now lost to your cause"
|
12
|
+
c.puts "the inquisition is here for a reason"
|
13
|
+
end
|
14
|
+
|
15
|
+
open('stomp://localhost/queue/onstomp/openuri') do |c|
|
16
|
+
c.each do |m|
|
17
|
+
puts "Got a message: #{m.body}"
|
18
|
+
break if m.body == 'what rhymes with you?'
|
19
|
+
end
|
20
|
+
|
21
|
+
c.take(2).each { |m| puts "From take(2): #{m.body}" }
|
22
|
+
|
23
|
+
puts "And finally: #{c.first.body}"
|
24
|
+
end
|
25
|
+
|
26
|
+
puts "Done with open-uri examples!"
|
27
|
+
|
28
|
+
# Example output:
|
29
|
+
#
|
30
|
+
# Got a message: hello world!
|
31
|
+
# Got a message: a fine day to you
|
32
|
+
# Got a message: what rhymes with you?
|
33
|
+
# From take(2): may the rats eat your eyes
|
34
|
+
# From take(2): I am now lost to your cause
|
35
|
+
# And finally: the inquisition is here for a reason
|
36
|
+
# Done with open-uri examples!
|
data/lib/onstomp.rb
CHANGED
@@ -33,6 +33,10 @@ require 'monitor'
|
|
33
33
|
|
34
34
|
# Primary namespace for the +onstomp+ gem
|
35
35
|
module OnStomp
|
36
|
+
# Class to use for creating enumerator objects, which depends upon the
|
37
|
+
# version of Ruby being used.
|
38
|
+
ENUMERATOR_KLASS = (RUBY_VERSION >= '1.9') ? Enumerator : Enumerable::Enumerator
|
39
|
+
|
36
40
|
# A common base class for errors raised by the OnStomp gem
|
37
41
|
# @abstract
|
38
42
|
class OnStompError < StandardError; end
|
data/lib/onstomp/client.rb
CHANGED
@@ -50,7 +50,7 @@ class OnStomp::Client
|
|
50
50
|
# Creates a new client for the specified uri and optional hash of options.
|
51
51
|
# @param [String,URI] uri
|
52
52
|
# @param [{Symbol => Object}] options
|
53
|
-
def initialize
|
53
|
+
def initialize uri, options={}
|
54
54
|
@uri = uri.is_a?(::URI) ? uri : ::URI.parse(uri)
|
55
55
|
@ssl = options.delete(:ssl)
|
56
56
|
configure_configurable options
|
@@ -65,7 +65,7 @@ class OnStomp::Client
|
|
65
65
|
# headers in the CONNECT frame, if specified.
|
66
66
|
# @param [{#to_sym => #to_s}] headers
|
67
67
|
# @return [self]
|
68
|
-
def connect
|
68
|
+
def connect headers={}
|
69
69
|
@connection = OnStomp::Connections.connect self, headers,
|
70
70
|
{ :'accept-version' => @versions.join(','), :host => @host,
|
71
71
|
:'heart-beat' => @heartbeats.join(','), :login => @login,
|
@@ -80,7 +80,8 @@ class OnStomp::Client
|
|
80
80
|
# the broker will get processed barring any IO exceptions.
|
81
81
|
# @param [{#to_sym => #to_s}] headers
|
82
82
|
# @return [OnStomp::Components::Frame] transmitted DISCONNECT frame
|
83
|
-
def disconnect_with_flush
|
83
|
+
def disconnect_with_flush headers={}
|
84
|
+
processor_inst.prepare_to_close
|
84
85
|
disconnect_without_flush(headers).tap do
|
85
86
|
processor_inst.join
|
86
87
|
end
|
@@ -111,11 +112,11 @@ class OnStomp::Client
|
|
111
112
|
# This method should not be invoked directly. Use the frame methods provided
|
112
113
|
# by the {OnStomp::Interfaces:FrameMethod} interface.
|
113
114
|
# @return [OnStomp::Components::Frame]
|
114
|
-
def transmit
|
115
|
+
def transmit frame, cbs={}
|
115
116
|
frame.tap do
|
116
117
|
register_callbacks frame, cbs
|
117
118
|
trigger_before_transmitting frame
|
118
|
-
connection.write_frame_nonblock
|
119
|
+
connection && connection.write_frame_nonblock(frame)
|
119
120
|
end
|
120
121
|
end
|
121
122
|
|
data/lib/onstomp/components.rb
CHANGED
@@ -8,6 +8,5 @@ require 'onstomp/components/uri'
|
|
8
8
|
require 'onstomp/components/frame_headers'
|
9
9
|
require 'onstomp/components/frame'
|
10
10
|
require 'onstomp/components/subscription'
|
11
|
-
require 'onstomp/components/nil_processor'
|
12
11
|
require 'onstomp/components/threaded_processor'
|
13
12
|
require 'onstomp/components/scopes'
|
@@ -14,7 +14,7 @@ class OnStomp::Components::FrameHeaders
|
|
14
14
|
# @see #merge!
|
15
15
|
def initialize(headers={})
|
16
16
|
@values = {}
|
17
|
-
|
17
|
+
initialize_names
|
18
18
|
merge! headers
|
19
19
|
end
|
20
20
|
|
@@ -115,7 +115,7 @@ class OnStomp::Components::FrameHeaders
|
|
115
115
|
def delete(name)
|
116
116
|
name = name.to_sym
|
117
117
|
if @values.key? name
|
118
|
-
|
118
|
+
delete_name name
|
119
119
|
@values.delete name
|
120
120
|
end
|
121
121
|
end
|
@@ -150,7 +150,7 @@ class OnStomp::Components::FrameHeaders
|
|
150
150
|
def []=(name, val)
|
151
151
|
name = name.to_sym
|
152
152
|
val = val.to_s
|
153
|
-
|
153
|
+
add_name name
|
154
154
|
@values[name] = [val]
|
155
155
|
val
|
156
156
|
end
|
@@ -162,51 +162,48 @@ class OnStomp::Components::FrameHeaders
|
|
162
162
|
@values.inject({}) { |h, (k,v)| h[k] = v.first; h }
|
163
163
|
end
|
164
164
|
|
165
|
+
# Iterates over header name / value pairs, yielding them as a pair
|
166
|
+
# of strings to the supplied block.
|
167
|
+
# @yield [header_name, header_value]
|
168
|
+
# @yieldparam [String] header_name
|
169
|
+
# @yieldparam [String] header_value
|
170
|
+
def each &block
|
171
|
+
if block_given?
|
172
|
+
iterate_each &block
|
173
|
+
self
|
174
|
+
else
|
175
|
+
OnStomp::ENUMERATOR_KLASS.new(self)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
165
179
|
if RUBY_VERSION >= "1.9"
|
166
180
|
def names; @values.keys; end
|
167
181
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
end
|
182
|
+
private
|
183
|
+
def iterate_each
|
184
|
+
@values.each do |name, vals|
|
185
|
+
name_str = name.to_s
|
186
|
+
vals.each do |val|
|
187
|
+
yield [name_str, val]
|
175
188
|
end
|
176
|
-
self
|
177
|
-
else
|
178
|
-
Enumerator.new(self)
|
179
189
|
end
|
180
190
|
end
|
181
|
-
|
182
|
-
|
183
|
-
def
|
184
|
-
def __delete_name__(name); end
|
185
|
-
def __add_name__(name); end
|
191
|
+
def initialize_names; end
|
192
|
+
def delete_name(name); end
|
193
|
+
def add_name(name); end
|
186
194
|
else
|
187
195
|
attr_reader :names
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
def each(&block)
|
195
|
-
if block_given?
|
196
|
-
@names.each do |name|
|
197
|
-
@values[name].each do |val|
|
198
|
-
yield [name.to_s, val]
|
199
|
-
end
|
196
|
+
|
197
|
+
private
|
198
|
+
def iterate_each
|
199
|
+
@names.each do |name|
|
200
|
+
@values[name].each do |val|
|
201
|
+
yield [name.to_s, val]
|
200
202
|
end
|
201
|
-
self
|
202
|
-
else
|
203
|
-
Enumerable::Enumerator.new(self)
|
204
203
|
end
|
205
204
|
end
|
206
|
-
|
207
|
-
|
208
|
-
def
|
209
|
-
def __delete_name__(name); @names.delete name; end
|
210
|
-
def __add_name__(name); @names << name unless @values.key?(name); end
|
205
|
+
def initialize_names; @names = []; end
|
206
|
+
def delete_name(name); @names.delete name; end
|
207
|
+
def add_name(name); @names << name unless @values.key?(name); end
|
211
208
|
end
|
212
209
|
end
|
@@ -7,6 +7,7 @@ class OnStomp::Components::ThreadedProcessor
|
|
7
7
|
def initialize client
|
8
8
|
@client = client
|
9
9
|
@run_thread = nil
|
10
|
+
@closing = false
|
10
11
|
end
|
11
12
|
|
12
13
|
# Returns true if its IO thread has been created and is alive, otherwise
|
@@ -25,6 +26,7 @@ class OnStomp::Components::ThreadedProcessor
|
|
25
26
|
begin
|
26
27
|
while @client.connected?
|
27
28
|
@client.connection.io_process
|
29
|
+
Thread.stop if @closing
|
28
30
|
end
|
29
31
|
rescue OnStomp::StopReceiver
|
30
32
|
rescue Exception
|
@@ -34,6 +36,17 @@ class OnStomp::Components::ThreadedProcessor
|
|
34
36
|
self
|
35
37
|
end
|
36
38
|
|
39
|
+
# Prepares the conneciton for closing by flushing its write buffer.
|
40
|
+
def prepare_to_close
|
41
|
+
if running?
|
42
|
+
@closing = true
|
43
|
+
Thread.pass until @run_thread.stop?
|
44
|
+
@client.connection.flush_write_buffer
|
45
|
+
@closing = false
|
46
|
+
@run_thread.wakeup
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
37
50
|
# Causes the thread this method was invoked in to +pass+ until the
|
38
51
|
# processor is no longer {#running? running}.
|
39
52
|
# @return [self]
|
@@ -93,13 +93,19 @@ class OnStomp::Connections::Base
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
# Flushes the write buffer by invoking {#io_process_write} until the
|
97
|
+
# buffer is empty.
|
98
|
+
def flush_write_buffer
|
99
|
+
io_process_write until @write_buffer.empty?
|
100
|
+
end
|
101
|
+
|
96
102
|
# Makes a single call to {#io_process_write} and a single call to
|
97
103
|
# {#io_process_read}
|
98
104
|
def io_process &cb
|
99
105
|
io_process_write &cb
|
100
106
|
io_process_read &cb
|
101
107
|
if @connection_up && !connected?
|
102
|
-
triggered_close :died
|
108
|
+
triggered_close 'connection timed out', :died
|
103
109
|
end
|
104
110
|
end
|
105
111
|
|
@@ -162,13 +168,13 @@ class OnStomp::Connections::Base
|
|
162
168
|
unshift_write_buffer data, frame
|
163
169
|
break
|
164
170
|
rescue Exception
|
165
|
-
triggered_close :terminated
|
171
|
+
triggered_close $!.message, :terminated
|
166
172
|
raise
|
167
173
|
end
|
168
174
|
end
|
169
175
|
end
|
170
176
|
if @write_buffer.empty? && @closing
|
171
|
-
triggered_close
|
177
|
+
triggered_close 'client disconnected'
|
172
178
|
end
|
173
179
|
end
|
174
180
|
|
@@ -189,20 +195,21 @@ class OnStomp::Connections::Base
|
|
189
195
|
rescue Errno::EINTR, Errno::EAGAIN, Errno::EWOULDBLOCK
|
190
196
|
# do not
|
191
197
|
rescue EOFError
|
192
|
-
triggered_close
|
198
|
+
triggered_close $!.message
|
193
199
|
rescue Exception
|
194
|
-
triggered_close :terminated
|
200
|
+
triggered_close $!.message, :terminated
|
195
201
|
raise
|
196
202
|
end
|
197
203
|
end
|
198
204
|
end
|
199
205
|
|
200
206
|
private
|
201
|
-
def triggered_close *evs
|
207
|
+
def triggered_close msg, *evs
|
202
208
|
@connection_up = false
|
203
209
|
@closing = false
|
204
210
|
socket.close
|
205
|
-
evs.each { |ev| trigger_connection_event ev }
|
206
|
-
trigger_connection_event :closed
|
211
|
+
evs.each { |ev| trigger_connection_event ev, msg }
|
212
|
+
trigger_connection_event :closed, msg
|
213
|
+
@write_buffer.clear
|
207
214
|
end
|
208
215
|
end
|
@@ -38,12 +38,6 @@ module OnStomp::Connections::Stomp_1
|
|
38
38
|
create_frame 'DISCONNECT', [h]
|
39
39
|
end
|
40
40
|
|
41
|
-
# Creates a SUBSCRIBE frame
|
42
|
-
# @return [OnStomp::Components::Frame] SUBSCRIBE frame
|
43
|
-
def subscribe_frame d, h
|
44
|
-
create_frame 'SUBSCRIBE', [{:id => OnStomp.next_serial}, h, {:destination => d}]
|
45
|
-
end
|
46
|
-
|
47
41
|
# Creates an UNSUBSCRIBE frame
|
48
42
|
# @return [OnStomp::Components::Frame] UNSUBSCRIBE frame
|
49
43
|
def unsubscribe_frame f, h
|
@@ -14,6 +14,14 @@ class OnStomp::Connections::Stomp_1_0 < OnStomp::Connections::Base
|
|
14
14
|
super
|
15
15
|
@serializer = OnStomp::Connections::Serializers::Stomp_1_0.new
|
16
16
|
end
|
17
|
+
|
18
|
+
# Creates a SUBSCRIBE frame. Sets +ack+ header to 'auto' unless it is
|
19
|
+
# already set to 'client'.
|
20
|
+
# @return [OnStomp::Components::Frame] SUBSCRIBE frame
|
21
|
+
def subscribe_frame d, h
|
22
|
+
h[:ack] = 'auto' unless h[:ack] == 'client'
|
23
|
+
create_frame 'SUBSCRIBE', [{:id => OnStomp.next_serial}, h, {:destination => d}]
|
24
|
+
end
|
17
25
|
|
18
26
|
# Creates an ACK frame
|
19
27
|
# @return [OnStomp::Components::Frame] ACK frame
|
@@ -31,6 +31,14 @@ class OnStomp::Connections::Stomp_1_1 < OnStomp::Connections::Base
|
|
31
31
|
super && pulse?
|
32
32
|
end
|
33
33
|
|
34
|
+
# Creates a SUBSCRIBE frame. Sets +ack+ header to 'auto' unless it is
|
35
|
+
# already set to 'client' or 'client-individual'.
|
36
|
+
# @return [OnStomp::Components::Frame] SUBSCRIBE frame
|
37
|
+
def subscribe_frame d, h
|
38
|
+
h[:ack] = 'auto' unless ['client', 'client-individual'].include?(h[:ack])
|
39
|
+
create_frame 'SUBSCRIBE', [{:id => OnStomp.next_serial}, h, {:destination => d}]
|
40
|
+
end
|
41
|
+
|
34
42
|
# Creates an ACK frame
|
35
43
|
# @return [OnStomp::Components::Frame] ACK frame
|
36
44
|
def ack_frame *args
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
# Namespace for failover extensions.
|
4
|
+
module OnStomp::Failover
|
5
|
+
# Raised if the supplied failover: URI is not properly formatted as
|
6
|
+
# +failover:(uri,uri,...)?optionalParams=values+
|
7
|
+
class InvalidFailoverURIError < OnStomp::OnStompError; end
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'onstomp/failover/uri'
|
11
|
+
require 'onstomp/failover/failover_configurable'
|
12
|
+
require 'onstomp/failover/failover_events'
|
13
|
+
require 'onstomp/failover/buffers'
|
14
|
+
require 'onstomp/failover/pools'
|
15
|
+
require 'onstomp/failover/client'
|
16
|
+
require 'onstomp/failover/new_with_failover'
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
# A buffer that ensures frames are at least written to a
|
4
|
+
# {OnStomp::Client client}'s {OnStomp::Connections::Base connection} and
|
5
|
+
# replays the ones that were not when the
|
6
|
+
# {OnStomp::Failover::Client failover} client reconnects.
|
7
|
+
class OnStomp::Failover::Buffers::Written
|
8
|
+
def initialize failover
|
9
|
+
@failover = failover
|
10
|
+
@buffer_mutex = Mutex.new
|
11
|
+
@buffer = []
|
12
|
+
@txs = {}
|
13
|
+
|
14
|
+
failover.before_send &method(:buffer_frame)
|
15
|
+
failover.before_commit &method(:buffer_frame)
|
16
|
+
failover.before_abort &method(:buffer_frame)
|
17
|
+
failover.before_subscribe &method(:buffer_frame)
|
18
|
+
failover.before_begin &method(:buffer_transaction)
|
19
|
+
# We can scrub the subscription before UNSUBSCRIBE is fully written
|
20
|
+
# because if we replay before UNSUBSCRIBE was sent, we still don't
|
21
|
+
# want to be subscribed when we reconnect.
|
22
|
+
failover.before_unsubscribe &method(:debuffer_subscription)
|
23
|
+
# We only want to scrub the transactions if ABORT or COMMIT was
|
24
|
+
# at least written fully to the socket.
|
25
|
+
failover.on_commit &method(:debuffer_transaction)
|
26
|
+
failover.on_abort &method(:debuffer_transaction)
|
27
|
+
failover.on_send &method(:debuffer_non_transactional_frame)
|
28
|
+
|
29
|
+
failover.on_failover_connected &method(:replay)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Adds a frame to a buffer so that it may be replayed if the
|
33
|
+
# {OnStomp::Failover::Client failover} client re-connects
|
34
|
+
def buffer_frame f, *_
|
35
|
+
@buffer_mutex.synchronize do
|
36
|
+
unless f.header? :'x-onstomp-failover-replay'
|
37
|
+
@buffer << f
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Records the start of a transaction so that it may be replayed if the
|
43
|
+
# {OnStomp::Failover::Client failover} client re-connects
|
44
|
+
def buffer_transaction f, *_
|
45
|
+
@txs[f[:transaction]] = true
|
46
|
+
buffer_frame f
|
47
|
+
end
|
48
|
+
|
49
|
+
# Removes the recorded transaction from the buffer after it has been
|
50
|
+
# written the broker socket so that it will not be replayed when the
|
51
|
+
# {OnStomp::Failover::Client failover} client re-connects
|
52
|
+
def debuffer_transaction f, *_
|
53
|
+
tx = f[:transaction]
|
54
|
+
if @txs.delete tx
|
55
|
+
@buffer_mutex.synchronize do
|
56
|
+
@buffer.reject! { |bf| bf[:transaction] == tx }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Removes the matching SUBSCRIBE frame from the buffer after the
|
62
|
+
# UNSUBSCRIBE has been added to the connection's write buffer
|
63
|
+
# so that it will not be replayed when the
|
64
|
+
# {OnStomp::Failover::Client failover} client re-connects
|
65
|
+
def debuffer_subscription f, *_
|
66
|
+
@buffer_mutex.synchronize do
|
67
|
+
@buffer.reject! { |bf| bf.command == 'SUBSCRIBE' && bf[:id] == f[:id] }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Removes a frame that is not part of a transaction from the buffer
|
72
|
+
# after it has been written the broker socket so that it will not be
|
73
|
+
# replayed when the {OnStomp::Failover::Client failover} client re-connects
|
74
|
+
def debuffer_non_transactional_frame f, *_
|
75
|
+
unless @txs.key?(f[:transaction])
|
76
|
+
@buffer_mutex.synchronize { @buffer.delete f }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Called when the {OnStomp::Failover::Client failover} client triggers
|
81
|
+
# +on_failover_connected+ to start replaying any frames in the buffer.
|
82
|
+
def replay fail, client, *_
|
83
|
+
replay_frames = @buffer_mutex.synchronize do
|
84
|
+
@buffer.select { |f| f[:'x-onstomp-failover-replay'] = '1'; true }
|
85
|
+
end
|
86
|
+
|
87
|
+
replay_frames.each do |f|
|
88
|
+
client.transmit f
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|