stomper 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|