stomper 2.0.1 → 2.0.2
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/CHANGELOG.md +28 -0
- data/README.md +1 -17
- data/features/protocol_version_negotiation.feature +6 -6
- data/features/steps/{acking_messages_steps.rb → ack_and_nack_steps.rb} +9 -1
- data/features/steps/broker_steps.rb +52 -0
- data/features/steps/client_steps.rb +137 -0
- data/features/steps/{receipts_steps.rb → receipt_steps.rb} +0 -0
- data/features/steps/{scopes_steps.rb → scope_steps.rb} +0 -16
- data/features/steps/subscription_steps.rb +80 -0
- data/lib/stomper/connection.rb +29 -29
- data/lib/stomper/receipt_manager.rb +5 -0
- data/lib/stomper/subscription_manager.rb +8 -3
- data/lib/stomper/version.rb +1 -1
- data/spec/stomper/connection_spec.rb +16 -1
- data/spec/stomper/frame_serializer_spec.rb +299 -280
- data/spec/stomper/subscription_manager_spec.rb +2 -3
- data/spec/stomper_spec.rb +0 -1
- data/spec/support/frame_header_matchers.rb +25 -0
- metadata +17 -60
- data/features/steps/disconnecting_steps.rb +0 -8
- data/features/steps/establish_connection_steps.rb +0 -77
- data/features/steps/frame_transmission_steps.rb +0 -40
- data/features/steps/protocol_version_negotiation_steps.rb +0 -15
- data/features/steps/secure_connections_steps.rb +0 -43
- data/features/steps/send_and_message_steps.rb +0 -35
- data/features/steps/subscribing_steps.rb +0 -36
- data/features/steps/threaded_receiver_steps.rb +0 -8
- data/features/steps/transactions_steps.rb +0 -0
- data/spec/stomper/frame_serializer_1.8_spec.rb +0 -318
data/CHANGELOG.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Changes
|
2
|
+
|
3
|
+
## 2.0.2 - 2011-03-01
|
4
|
+
|
5
|
+
* updated to-do's and version number in README.md
|
6
|
+
|
7
|
+
* added CHANGELOG.md
|
8
|
+
|
9
|
+
* connection's @close@ method now clears remaining subscriptions and receipt
|
10
|
+
handlers after all events are fired. should ease the work
|
11
|
+
the failover extension has to do to re-subscribe appropriately.
|
12
|
+
|
13
|
+
* corrected spec tests to handle features introduced in 2.0.1 - should not
|
14
|
+
have pushed a new version until those specs were run.
|
15
|
+
|
16
|
+
## 2.0.1 - 2011-02-27
|
17
|
+
|
18
|
+
* connection now raises exception in threaded receiver to stop, prevents
|
19
|
+
blocking on @receive@
|
20
|
+
|
21
|
+
* connection terminated event now fires properly, fixes #1
|
22
|
+
|
23
|
+
* subscription manager clears remaining subscriptions when the connection
|
24
|
+
is closed, fixes #2
|
25
|
+
|
26
|
+
## 2.0.0 - 2011-02-22
|
27
|
+
|
28
|
+
* Rewrite of stomper
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#Stomper 2.0
|
1
|
+
#Stomper 2.0
|
2
2
|
|
3
3
|
Stomper is a library for connecting to and interacting with a message broker
|
4
4
|
service that supports the Stomp [1.0](http://stomp.github.com/stomp-specification-1-0.html)
|
@@ -15,22 +15,6 @@ rather unpleasant to deal with for common use cases.
|
|
15
15
|
This gem is in no way related to the [Python stomper](http://code.google.com/p/stomper/)
|
16
16
|
library.
|
17
17
|
|
18
|
-
##Still in the Works
|
19
|
-
|
20
|
-
There are a few features that have not yet been implemented, hence why we're
|
21
|
-
still on a prerelease version number. The following is a list of the major
|
22
|
-
deficiencies of the gem, but this list is not necessarily exhaustive.
|
23
|
-
|
24
|
-
* Write some features to test other connections:
|
25
|
-
* Authenticated logins
|
26
|
-
* SSL Client verification (just to ensure that SSL params are being
|
27
|
-
delivered appropriately)
|
28
|
-
* A bit of refactoring is in order
|
29
|
-
* Refactor specs a bit, clean up separation between 1.9 and 1.8 specific tests
|
30
|
-
|
31
|
-
As these issues are resolved, I'll drop them from the list (and potentially
|
32
|
-
add other issues)
|
33
|
-
|
34
18
|
##Example Usage
|
35
19
|
|
36
20
|
# Establish a connection to the broker
|
@@ -5,17 +5,17 @@ Feature: Protocol version negotiation
|
|
5
5
|
|
6
6
|
Scenario: By default, allow 1.1 from broker
|
7
7
|
Given a Stomp 1.1 broker
|
8
|
-
When
|
8
|
+
When the connection is told to connect
|
9
9
|
Then the connection should be using the 1.1 protocol
|
10
10
|
|
11
11
|
Scenario: By default, allow 1.0 from broker
|
12
12
|
Given a Stomp 1.0 broker
|
13
|
-
When
|
13
|
+
When the connection is told to connect
|
14
14
|
Then the connection should be using the 1.0 protocol
|
15
15
|
|
16
16
|
Scenario: By default, assume 1.0 from version-less broker
|
17
17
|
Given an unversioned Stomp broker
|
18
|
-
When
|
18
|
+
When the connection is told to connect
|
19
19
|
Then the connection should be using the 1.0 protocol
|
20
20
|
|
21
21
|
Scenario: By default, raise error if the broker's version isn't supported
|
@@ -26,13 +26,13 @@ Feature: Protocol version negotiation
|
|
26
26
|
Scenario: A 1.0 client should accept a 1.0 broker
|
27
27
|
Given a Stomp 1.0 broker
|
28
28
|
When the client protocol version is "1.0"
|
29
|
-
And
|
29
|
+
And the connection is told to connect
|
30
30
|
Then the connection should be using the 1.0 protocol
|
31
31
|
|
32
32
|
Scenario: A 1.0 client should accept a version-less broker
|
33
33
|
Given an unversioned Stomp broker
|
34
34
|
When the client protocol version is "1.0"
|
35
|
-
And
|
35
|
+
And the connection is told to connect
|
36
36
|
Then the connection should be using the 1.0 protocol
|
37
37
|
|
38
38
|
Scenario: A 1.0 client should not accept a 1.1 broker
|
@@ -44,7 +44,7 @@ Feature: Protocol version negotiation
|
|
44
44
|
Scenario: A 1.1 client should accept a 1.1 broker
|
45
45
|
Given a Stomp 1.1 broker
|
46
46
|
When the client protocol version is "1.1"
|
47
|
-
And
|
47
|
+
And the connection is told to connect
|
48
48
|
Then the connection should be using the 1.1 protocol
|
49
49
|
|
50
50
|
Scenario: A 1.1 client should not accept a 1.0 broker
|
@@ -38,4 +38,12 @@ end
|
|
38
38
|
|
39
39
|
Then /^the client nacking the last MESSAGE should raise an argument error$/ do
|
40
40
|
lambda { @connection.nack @received_frames.select { |f| f.command == "MESSAGE" }.last }.should raise_error(ArgumentError)
|
41
|
-
end
|
41
|
+
end
|
42
|
+
|
43
|
+
When /^the client acks a message by ID "([^"]*)" and subscription "([^"]*)" within the scope$/ do |message_id, subscription|
|
44
|
+
@scope.ack message_id, subscription
|
45
|
+
end
|
46
|
+
|
47
|
+
When /^the client nacks a message by ID "([^"]*)" and subscription "([^"]*)" within the scope$/ do |message_id, subscription|
|
48
|
+
@scope.nack message_id, subscription
|
49
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
Given /^a Stomp (\d+\.\d+)?\s*broker$/ do |version|
|
2
|
+
version ||= '1.0'
|
3
|
+
@broker_uri_string = "stomp:///"
|
4
|
+
@broker_uri = URI.parse(@broker_uri_string)
|
5
|
+
@broker = TestStompServer.new(version)
|
6
|
+
@broker.start
|
7
|
+
@connection = Stomper::Connection.new(@broker_uri)
|
8
|
+
end
|
9
|
+
|
10
|
+
Given /^an erroring Stomp broker$/ do
|
11
|
+
@broker_uri_string = "stomp:///"
|
12
|
+
@broker_uri = URI.parse(@broker_uri_string)
|
13
|
+
@broker = TestStompServer.new('1.0')
|
14
|
+
@broker.session_class = TestStompServer::StompErrorOnConnectSession
|
15
|
+
@broker.start
|
16
|
+
@connection = Stomper::Connection.new(@broker_uri)
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^the broker should have received an? "([^"]*)" frame$/ do |command|
|
20
|
+
Then "the broker should have received a \"#{command}\" frame with headers", table(%{
|
21
|
+
| header-name | header-value |
|
22
|
+
})
|
23
|
+
end
|
24
|
+
|
25
|
+
Then /^the broker should have received an? "([^"]*)" frame with headers$/ do |command, table|
|
26
|
+
headers = table_to_headers table
|
27
|
+
@broker.session.received_frames.any? do |f|
|
28
|
+
f.command == command && headers.all? { |(k,v)| headers[k] == f[k] }
|
29
|
+
end.should be_true
|
30
|
+
end
|
31
|
+
|
32
|
+
When /^the broker sends a "([^"]*)" frame with headers$/ do |command, table|
|
33
|
+
headers = table_to_headers table
|
34
|
+
@broker.session.send_frame command, headers
|
35
|
+
end
|
36
|
+
|
37
|
+
When /^the broker closes the connection unexpectedly$/ do
|
38
|
+
@broker.force_stop
|
39
|
+
end
|
40
|
+
|
41
|
+
Given /^a Stomp (\d+\.\d+)?\s*SSL broker$/ do |version|
|
42
|
+
@broker = TestSSLStompServer.new(version)
|
43
|
+
@broker.start
|
44
|
+
end
|
45
|
+
|
46
|
+
Given /^an unversioned Stomp broker$/ do
|
47
|
+
@broker_uri_string = "stomp:///"
|
48
|
+
@broker_uri = URI.parse(@broker_uri_string)
|
49
|
+
@broker = TestStompServer.new(nil)
|
50
|
+
@broker.start
|
51
|
+
@connection = Stomper::Connection.new(@broker_uri)
|
52
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
After do |s|
|
2
|
+
begin
|
3
|
+
@connection && @connection.stop
|
4
|
+
@broker && @broker.force_stop
|
5
|
+
rescue Exception => ex
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^a (\d+\.\d+)?\s*connection between client and broker$/ do |version|
|
10
|
+
version ||= '1.0'
|
11
|
+
@broker_uri_string = "stomp:///"
|
12
|
+
@broker_uri = URI.parse(@broker_uri_string)
|
13
|
+
@broker = TestStompServer.new(version)
|
14
|
+
@broker.start
|
15
|
+
@connection = Stomper::Connection.new(@broker_uri)
|
16
|
+
@received_frames = []
|
17
|
+
@sent_frames = []
|
18
|
+
@connection.before_transmitting do |f, c|
|
19
|
+
@sent_frames << f
|
20
|
+
end
|
21
|
+
@connection.after_receiving do |f, c|
|
22
|
+
@received_frames << f
|
23
|
+
end
|
24
|
+
@connection.start
|
25
|
+
end
|
26
|
+
|
27
|
+
When /^the frame exchange is completed$/ do
|
28
|
+
@connection.disconnect(:receipt => 'TERMINATE_POLITELY_12345')
|
29
|
+
@connection.stop
|
30
|
+
@broker.stop
|
31
|
+
end
|
32
|
+
|
33
|
+
When /^the frame exchange is completed without client disconnect$/ do
|
34
|
+
@connection.stop
|
35
|
+
@broker.stop
|
36
|
+
end
|
37
|
+
|
38
|
+
When /^a connection is created from the broker's URI$/ do
|
39
|
+
#@connection = Stomper::Connection.new(@broker_uri)
|
40
|
+
end
|
41
|
+
|
42
|
+
When /^a connection is created from the broker's URI string$/ do
|
43
|
+
@connection = Stomper::Connection.new(@broker_uri_string)
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^the connection is told to connect$/ do
|
47
|
+
@connection.connect
|
48
|
+
end
|
49
|
+
|
50
|
+
When /^the client protocol version is "([^"]*)"$/ do |arg1|
|
51
|
+
@connection.versions = arg1.split(",")
|
52
|
+
end
|
53
|
+
|
54
|
+
Then /^the connection should be connected$/ do
|
55
|
+
@connection.connected?.should be_true
|
56
|
+
end
|
57
|
+
|
58
|
+
Then /^the connection should be using the (\d+\.\d+) protocol$/ do |version|
|
59
|
+
@connection.version.should == version
|
60
|
+
end
|
61
|
+
|
62
|
+
Then /^connecting should raise an unsupported protocol version error$/ do
|
63
|
+
lambda { @connection.connect }.should raise_error(Stomper::Errors::UnsupportedProtocolVersionError)
|
64
|
+
end
|
65
|
+
|
66
|
+
Then /^the (connection|client) should not be connected$/ do |arbitrary_name|
|
67
|
+
@connection.connected?.should be_false
|
68
|
+
end
|
69
|
+
|
70
|
+
Then /^connecting should raise an connect failed error$/ do
|
71
|
+
lambda { @connection.connect }.should raise_error(Stomper::Errors::ConnectFailedError)
|
72
|
+
end
|
73
|
+
|
74
|
+
Then /^the client should have received an? "([^"]*)" frame with headers$/ do |command, table|
|
75
|
+
headers = table_to_headers table
|
76
|
+
@received_frames.any? do |f|
|
77
|
+
f.command == command && headers.all? { |(k,v)| headers[k] == f[k] }
|
78
|
+
end.should be_true
|
79
|
+
end
|
80
|
+
|
81
|
+
When /^the client waits for (\d+) "([^"]*)" frames?$/ do |count, command|
|
82
|
+
count = count.to_i
|
83
|
+
Thread.pass while @received_frames.select { |f| f.command == command }.size < count
|
84
|
+
end
|
85
|
+
|
86
|
+
Given /^an established connection$/ do
|
87
|
+
@connection.connect
|
88
|
+
end
|
89
|
+
|
90
|
+
When /^the client disconnects$/ do
|
91
|
+
@connection.disconnect
|
92
|
+
@broker.stop
|
93
|
+
end
|
94
|
+
|
95
|
+
Then /^after (\d+\.\d+) seconds, the receiver should no longer be running$/ do |sleep_for|
|
96
|
+
sleep sleep_for.to_f
|
97
|
+
@connection.running?.should be_false
|
98
|
+
end
|
99
|
+
|
100
|
+
When /^a connection is created for the SSL broker$/ do
|
101
|
+
@connection = Stomper::Connection.new("stomp+ssl:///")
|
102
|
+
end
|
103
|
+
|
104
|
+
When /^the broker's host is "([^"]*)"$/ do |hostname|
|
105
|
+
@connection.host = hostname
|
106
|
+
end
|
107
|
+
|
108
|
+
When /^no SSL verification is performed$/ do
|
109
|
+
@connection.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
|
110
|
+
end
|
111
|
+
|
112
|
+
When /^SSL verification is performed$/ do
|
113
|
+
@connection.ssl[:verify_mode] = ::OpenSSL::SSL::VERIFY_PEER | ::OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
114
|
+
end
|
115
|
+
|
116
|
+
When /^an SSL post connection check is performed on "([^"]*)"$/ do |host|
|
117
|
+
@connection.ssl[:post_connection_check] = host
|
118
|
+
end
|
119
|
+
|
120
|
+
Then /^connecting should raise an openssl error$/ do
|
121
|
+
lambda { @connection.connect }.should raise_error(OpenSSL::SSL::SSLError)
|
122
|
+
# It is problematic that this is needed...
|
123
|
+
@broker.stop
|
124
|
+
end
|
125
|
+
|
126
|
+
When /^an SSL post connection check is not performed$/ do
|
127
|
+
@connection.ssl[:post_connection_check] = false
|
128
|
+
end
|
129
|
+
|
130
|
+
When /^the broker's certificate is verified by CA$/ do
|
131
|
+
@connection.ssl[:ca_file] = File.expand_path('../../support/ssl/demoCA/cacert.pem', __FILE__)
|
132
|
+
end
|
133
|
+
|
134
|
+
When /^the client's certificate and key are specified$/ do
|
135
|
+
@connection.ssl[:cert] = OpenSSL::X509::Certificate.new(File.read(File.expand_path('../../support/ssl/client_cert.pem', __FILE__)))
|
136
|
+
@connection.ssl[:key] = OpenSSL::PKey::RSA.new(File.read(File.expand_path('../../support/ssl/client_key.pem', __FILE__)))
|
137
|
+
end
|
File without changes
|
@@ -3,19 +3,6 @@ Given /^a header scope with headers$/ do |table|
|
|
3
3
|
@scope = @connection.with_headers(headers)
|
4
4
|
end
|
5
5
|
|
6
|
-
When /^the client acks a message by ID "([^"]*)" and subscription "([^"]*)" within the scope$/ do |message_id, subscription|
|
7
|
-
@scope.ack message_id, subscription
|
8
|
-
end
|
9
|
-
|
10
|
-
When /^the client subscribes to "([^"]*)" with headers within the scope$/ do |dest, table|
|
11
|
-
@subscribe_frames ||= []
|
12
|
-
headers = table_to_headers table
|
13
|
-
@default_subscription_triggered = 0
|
14
|
-
@subscribe_frames << @scope.subscribe(dest, headers) do |m|
|
15
|
-
@default_subscription_triggered += 1
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
6
|
Given /^a transaction scope named "([^"]*)"$/ do |tx|
|
20
7
|
@scope = @connection.with_transaction(:transaction => tx)
|
21
8
|
end
|
@@ -24,9 +11,6 @@ When /^the client begins the transaction scope$/ do
|
|
24
11
|
@scope.begin
|
25
12
|
end
|
26
13
|
|
27
|
-
When /^the client nacks a message by ID "([^"]*)" and subscription "([^"]*)" within the scope$/ do |message_id, subscription|
|
28
|
-
@scope.nack message_id, subscription
|
29
|
-
end
|
30
14
|
|
31
15
|
When /^the client aborts the transaction scope$/ do
|
32
16
|
@scope.abort
|
@@ -0,0 +1,80 @@
|
|
1
|
+
When /^the client subscribes to "([^"]*)" with headers$/ do |dest, table|
|
2
|
+
@subscribe_frames ||= []
|
3
|
+
headers = table_to_headers table
|
4
|
+
@default_subscription_triggered = 0
|
5
|
+
@subscribe_frames << @connection.subscribe(dest, headers) do |m|
|
6
|
+
@default_subscription_triggered += 1
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
Then /^the default subscription callback should have been triggered( (\d+) times?)?$/ do |full, times|
|
11
|
+
if times.nil? || times.empty?
|
12
|
+
@default_subscription_triggered.should >= 1
|
13
|
+
else
|
14
|
+
@default_subscription_triggered.should == times.to_i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Then /^the default subscription callback should not have been triggered$/ do
|
19
|
+
@default_subscription_triggered.should == 0
|
20
|
+
end
|
21
|
+
|
22
|
+
When /^the client unsubscribes by ID$/ do
|
23
|
+
@connection.unsubscribe(@subscribe_frames.last[:id])
|
24
|
+
end
|
25
|
+
|
26
|
+
When /^the client unsubscribes by destination$/ do
|
27
|
+
@connection.unsubscribe(@subscribe_frames.last[:destination])
|
28
|
+
end
|
29
|
+
|
30
|
+
When /^the client unsubscribes by frame$/ do
|
31
|
+
@connection.unsubscribe(@subscribe_frames.last)
|
32
|
+
end
|
33
|
+
|
34
|
+
When /^the client unsubscribes from destination "([^"]*)"$/ do |destination|
|
35
|
+
@connection.unsubscribe(destination)
|
36
|
+
end
|
37
|
+
|
38
|
+
Given /^the client subscribes to (\/.*)$/ do |dest|
|
39
|
+
@messages_for_subscription ||= []
|
40
|
+
@connection.subscribe(dest) do |m|
|
41
|
+
sub = m[:subscription]
|
42
|
+
@messages_for_subscription << m
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^the client sends a "([^"]*)" "([^"]*)" to (\/.*)$/ do |ct, body, dest|
|
47
|
+
@connection.send(dest, body, :'content-type' => ct)
|
48
|
+
end
|
49
|
+
|
50
|
+
Then /^the client should have received a "([^"]*)" message of "([^"]*)"$/ do |ct, body|
|
51
|
+
@messages_for_subscription.any? do |m|
|
52
|
+
m.content_type == ct && m.body == body
|
53
|
+
end.should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
When /^the client sends a "([^"]*)" encoded as "([^"]*)" to (\/.*)$/ do |body, enc, dest|
|
57
|
+
body.force_encoding(enc) if body.respond_to?(:force_encoding)
|
58
|
+
@connection.send(dest, body)
|
59
|
+
end
|
60
|
+
|
61
|
+
Then /^the client should have received a "([^"]*)" message of "([^"]*)" encoded as "([^"]*)"$/ do |ct, body, enc|
|
62
|
+
@messages_for_subscription.any? do |m|
|
63
|
+
ct_check = (m.content_type == ct || m.content_type.nil? && ct.empty?)
|
64
|
+
b_check = body == m.body
|
65
|
+
if body.respond_to?(:encoding)
|
66
|
+
ct_check && b_check && m.body.encoding.name == enc
|
67
|
+
else
|
68
|
+
ct_check && b_check
|
69
|
+
end
|
70
|
+
end.should be_true
|
71
|
+
end
|
72
|
+
|
73
|
+
When /^the client subscribes to "([^"]*)" with headers within the scope$/ do |dest, table|
|
74
|
+
@subscribe_frames ||= []
|
75
|
+
headers = table_to_headers table
|
76
|
+
@default_subscription_triggered = 0
|
77
|
+
@subscribe_frames << @scope.subscribe(dest, headers) do |m|
|
78
|
+
@default_subscription_triggered += 1
|
79
|
+
end
|
80
|
+
end
|
data/lib/stomper/connection.rb
CHANGED
@@ -171,7 +171,7 @@ class Stomper::Connection
|
|
171
171
|
@connecting = false
|
172
172
|
@disconnecting = false
|
173
173
|
@disconnected = false
|
174
|
-
@
|
174
|
+
@close_mutex = ::Mutex.new
|
175
175
|
|
176
176
|
on_connected do |cf, con|
|
177
177
|
unless connected?
|
@@ -272,34 +272,32 @@ class Stomper::Connection
|
|
272
272
|
# connection has been established and you're ready to go, otherwise the
|
273
273
|
# socket will be closed and an error will be raised.
|
274
274
|
def connect(headers={})
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
raise ::Stomper::Errors::ConnectFailedError, 'broker did not send CONNECTED frame'
|
299
|
-
end
|
275
|
+
unless @connected
|
276
|
+
@socket = @uri.create_socket(@ssl)
|
277
|
+
@serializer = ::Stomper::FrameSerializer.new(@socket)
|
278
|
+
m_headers = {
|
279
|
+
:'accept-version' => @versions.join(','),
|
280
|
+
:host => @host,
|
281
|
+
:'heart-beat' => @heartbeats.join(','),
|
282
|
+
:login => @login,
|
283
|
+
:passcode => @passcode
|
284
|
+
}
|
285
|
+
@disconnecting = false
|
286
|
+
@disconnected = false
|
287
|
+
@connecting = true
|
288
|
+
transmit create_frame('CONNECT', headers, m_headers)
|
289
|
+
receive.tap do |f|
|
290
|
+
if f.command == 'CONNECTED'
|
291
|
+
@connected_frame = f
|
292
|
+
@connected = true
|
293
|
+
@connecting = false
|
294
|
+
trigger_event(:on_connection_established, self)
|
295
|
+
else
|
296
|
+
close
|
297
|
+
raise ::Stomper::Errors::ConnectFailedError, 'broker did not send CONNECTED frame'
|
300
298
|
end
|
301
299
|
end
|
302
|
-
|
300
|
+
end
|
303
301
|
end
|
304
302
|
alias :open :connect
|
305
303
|
|
@@ -372,7 +370,7 @@ class Stomper::Connection
|
|
372
370
|
# @param [true,false] fire_terminated (false) If true, trigger
|
373
371
|
# {Stomper::Extensions::Events#on_connection_terminated}
|
374
372
|
def close
|
375
|
-
|
373
|
+
@close_mutex.synchronize do
|
376
374
|
if @connected
|
377
375
|
begin
|
378
376
|
trigger_event(:on_connection_terminated, self) unless @disconnected
|
@@ -384,8 +382,10 @@ class Stomper::Connection
|
|
384
382
|
@connected = false
|
385
383
|
end
|
386
384
|
trigger_event(:on_connection_closed, self)
|
385
|
+
subscription_manager.clear
|
386
|
+
receipt_manager.clear
|
387
387
|
end
|
388
|
-
|
388
|
+
end
|
389
389
|
end
|
390
390
|
|
391
391
|
# Transmits a frame to the broker. This is a low-level method used internally
|
@@ -9,7 +9,6 @@ class Stomper::SubscriptionManager
|
|
9
9
|
@subscriptions = {}
|
10
10
|
connection.on_message { |m, con| dispatch(m) }
|
11
11
|
connection.on_unsubscribe { |u, con| remove(u[:id]) }
|
12
|
-
connection.on_connection_closed { |con| @subscriptions.clear }
|
13
12
|
end
|
14
13
|
|
15
14
|
# Adds a callback handler for a MESSAGE frame that is sent via the subscription
|
@@ -46,12 +45,18 @@ class Stomper::SubscriptionManager
|
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
49
|
-
# Returns all current subscriptions
|
50
|
-
# @return [Array<Stomper::
|
48
|
+
# Returns all current subscriptions.
|
49
|
+
# @return [Array<Stomper::SubscriptionManager::Subscription>]
|
51
50
|
def subscriptions
|
52
51
|
@mon.synchronize { @subscriptions.values }
|
53
52
|
end
|
54
53
|
|
54
|
+
# Remove all subscriptions. This method does not send UNSUBSCRIBE frames
|
55
|
+
# to the broker.
|
56
|
+
def clear
|
57
|
+
@mon.synchronize { @subscriptions.clear }
|
58
|
+
end
|
59
|
+
|
55
60
|
private
|
56
61
|
def dispatch(message)
|
57
62
|
s_id = message[:subscription]
|
data/lib/stomper/version.rb
CHANGED
@@ -218,6 +218,22 @@ module Stomper
|
|
218
218
|
@connection.connected?.should be_false
|
219
219
|
end
|
220
220
|
|
221
|
+
it "should clear subscriptions on close" do
|
222
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
223
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
224
|
+
@connection.connect
|
225
|
+
@connection.subscription_manager.should_receive(:clear)
|
226
|
+
@connection.close
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should clear receipt handlers on close" do
|
230
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
231
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
232
|
+
@connection.connect
|
233
|
+
@connection.receipt_manager.should_receive(:clear)
|
234
|
+
@connection.close
|
235
|
+
end
|
236
|
+
|
221
237
|
describe "frame reading" do
|
222
238
|
before(:each) do
|
223
239
|
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
@@ -394,7 +410,6 @@ module Stomper
|
|
394
410
|
lambda { @connection.receive }.should raise_error(SystemCallError)
|
395
411
|
triggered.should be_true
|
396
412
|
end
|
397
|
-
|
398
413
|
end
|
399
414
|
|
400
415
|
describe "frame events" do
|