stompserver_ng 1.0.6
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/History.txt +159 -0
- data/Manifest.txt +71 -0
- data/README.txt +172 -0
- data/Rakefile +38 -0
- data/STATUS +5 -0
- data/bin/stompserver_ng +63 -0
- data/client/README.txt +1 -0
- data/client/both.rb +25 -0
- data/client/consume.rb +14 -0
- data/client/send.rb +17 -0
- data/config/stompserver_ng.conf +11 -0
- data/etc/19xcompat/notes.txt +223 -0
- data/etc/arutils/README-activerecord.txt +78 -0
- data/etc/arutils/cre_mysql.rb +34 -0
- data/etc/arutils/cre_postgres.rb +33 -0
- data/etc/arutils/cre_sqlite3.rb +28 -0
- data/etc/arutils/mysql_boot.sql +12 -0
- data/etc/arutils/postgres_boot.sql +14 -0
- data/etc/database.mysql.yml +9 -0
- data/etc/database.postgres.yml +9 -0
- data/etc/passwd.example +3 -0
- data/etc/ppqinfo.rb +15 -0
- data/etc/runserver.sh +17 -0
- data/etc/stompserver_ng +50 -0
- data/etc/stompserver_ng.conf +13 -0
- data/lib/stomp_server_ng.rb +471 -0
- data/lib/stomp_server_ng/protocols/http.rb +128 -0
- data/lib/stomp_server_ng/protocols/stomp.rb +407 -0
- data/lib/stomp_server_ng/qmonitor.rb +58 -0
- data/lib/stomp_server_ng/queue.rb +248 -0
- data/lib/stomp_server_ng/queue/activerecord_queue.rb +118 -0
- data/lib/stomp_server_ng/queue/ar_message.rb +21 -0
- data/lib/stomp_server_ng/queue/ar_reconnect.rb +18 -0
- data/lib/stomp_server_ng/queue/dbm_queue.rb +72 -0
- data/lib/stomp_server_ng/queue/file_queue.rb +56 -0
- data/lib/stomp_server_ng/queue/memory_queue.rb +64 -0
- data/lib/stomp_server_ng/queue_manager.rb +302 -0
- data/lib/stomp_server_ng/stomp_auth.rb +26 -0
- data/lib/stomp_server_ng/stomp_frame.rb +32 -0
- data/lib/stomp_server_ng/stomp_frame_recognizer.rb +77 -0
- data/lib/stomp_server_ng/stomp_id.rb +32 -0
- data/lib/stomp_server_ng/stomp_user.rb +17 -0
- data/lib/stomp_server_ng/test_server.rb +21 -0
- data/lib/stomp_server_ng/topic_manager.rb +46 -0
- data/setup.rb +1585 -0
- data/stompserver_ng.gemspec +136 -0
- data/test/devserver/props.yaml +5 -0
- data/test/devserver/runserver.sh +16 -0
- data/test/devserver/stompserver_ng.dbm.conf +12 -0
- data/test/devserver/stompserver_ng.file.conf +12 -0
- data/test/devserver/stompserver_ng.memory.conf +12 -0
- data/test/noserver/mocklogger.rb +12 -0
- data/test/noserver/test_queue_manager.rb +134 -0
- data/test/noserver/test_stomp_frame.rb +138 -0
- data/test/noserver/test_topic_manager.rb +79 -0
- data/test/noserver/ts_all_no_server.rb +12 -0
- data/test/props.yaml +5 -0
- data/test/runalltests.sh +14 -0
- data/test/runtest.sh +4 -0
- data/test/test_0000_base.rb +107 -0
- data/test/test_0001_conn.rb +47 -0
- data/test/test_0002_conn_sr.rb +94 -0
- data/test/test_0006_client.rb +41 -0
- data/test/test_0011_send_recv.rb +74 -0
- data/test/test_0015_ack_conn.rb +78 -0
- data/test/test_0017_ack_client.rb +78 -0
- data/test/test_0019_ack_no_ack.rb +145 -0
- data/test/test_0022_ack_noack_conn.rb +123 -0
- data/test/test_0030_subscr_id.rb +44 -0
- data/test/test_0040_receipt_conn.rb +87 -0
- data/test/ts_all_server.rb +10 -0
- metadata +196 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
|
2
|
+
class Mongrel::HttpRequest
|
3
|
+
attr_reader :body, :params
|
4
|
+
|
5
|
+
def initialize(params, initial_body)
|
6
|
+
@params = params
|
7
|
+
@body = StringIO.new
|
8
|
+
@body.write params.http_body
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module StompServer
|
13
|
+
module StompServer::Protocols
|
14
|
+
|
15
|
+
class Http < EventMachine::Connection
|
16
|
+
|
17
|
+
def initialize *args
|
18
|
+
super
|
19
|
+
@buf = ''
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def post_init
|
24
|
+
@parser = Mongrel::HttpParser.new
|
25
|
+
@params = Mongrel::HttpParams.new
|
26
|
+
@nparsed = 0
|
27
|
+
@request = nil
|
28
|
+
@request_method = nil
|
29
|
+
@request_length = 0
|
30
|
+
@state = :headers
|
31
|
+
@headers_out = {'Content-Length' => 0, 'Content-Type' => 'text/plain; charset=UTF-8'}
|
32
|
+
end
|
33
|
+
|
34
|
+
def receive_data data
|
35
|
+
parse_request(data)
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_request data
|
39
|
+
@buf << data
|
40
|
+
case @state
|
41
|
+
when :headers
|
42
|
+
@nparsed = @parser.execute(@params, @buf, @nparsed)
|
43
|
+
if @parser.finished?
|
44
|
+
@request = Mongrel::HttpRequest.new(@params,@buf)
|
45
|
+
@request_method = @request.params[Mongrel::Const::REQUEST_METHOD]
|
46
|
+
content_length = @request.params[Mongrel::Const::CONTENT_LENGTH].to_i
|
47
|
+
@request_length = @nparsed + content_length
|
48
|
+
@remain = content_length - @request.params.http_body.length
|
49
|
+
if @remain <= 0
|
50
|
+
@buf = @buf[@request_length+1..-1] || ''
|
51
|
+
process_request
|
52
|
+
post_init
|
53
|
+
return
|
54
|
+
end
|
55
|
+
@request.body.write @request.params.http_body
|
56
|
+
@state = :body
|
57
|
+
end
|
58
|
+
when :body
|
59
|
+
@remain -= @request.body.write data[0...@remain]
|
60
|
+
if @remain <= 0
|
61
|
+
@buf = @buf[@request_length+1..-1] || ''
|
62
|
+
process_request
|
63
|
+
post_init
|
64
|
+
return
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def process_request
|
70
|
+
begin
|
71
|
+
@request.body.rewind
|
72
|
+
dest = @request.params[Mongrel::Const::REQUEST_PATH]
|
73
|
+
case @request_method
|
74
|
+
when 'PUT'
|
75
|
+
@frame = StompServer::StompFrame.new
|
76
|
+
@frame.command = 'SEND'
|
77
|
+
@frame.body = @request.body.read
|
78
|
+
@frame.headers['destination'] = dest
|
79
|
+
if @@queue_manager.enqueue(@frame)
|
80
|
+
create_response('200','Message Enqueued')
|
81
|
+
else
|
82
|
+
create_response('500','Error enqueueing message')
|
83
|
+
end
|
84
|
+
when 'GET'
|
85
|
+
if frame = @@queue_manager.dequeue(dest)
|
86
|
+
@headers_out['message-id'] = frame.headers['message-id']
|
87
|
+
create_response('200',frame.body)
|
88
|
+
else
|
89
|
+
create_response('404','No messages in queue')
|
90
|
+
end
|
91
|
+
else
|
92
|
+
create_response('500','Invalid Command')
|
93
|
+
end
|
94
|
+
rescue Exception => e
|
95
|
+
puts "err: #{e} #{e.backtrace.join("\n")}"
|
96
|
+
create_response('500',e)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def unbind
|
101
|
+
puts "Closing connection"
|
102
|
+
close_connection_after_writing
|
103
|
+
end
|
104
|
+
|
105
|
+
def create_response(code,response_text)
|
106
|
+
response = ''
|
107
|
+
@headers_out['Content-Length'] = response_text.size
|
108
|
+
|
109
|
+
case code
|
110
|
+
when '200'
|
111
|
+
response << "HTTP/1.1 200 OK\r\n"
|
112
|
+
when '500'
|
113
|
+
response << "HTTP/1.1 500 Server Error\r\n"
|
114
|
+
when '404'
|
115
|
+
response << "HTTP/1.1 404 Message Not Found\r\n"
|
116
|
+
end
|
117
|
+
@headers_out.each_pair do |key, value|
|
118
|
+
response << "#{key}:#{value}\r\n"
|
119
|
+
end
|
120
|
+
response << "\r\n"
|
121
|
+
response << response_text
|
122
|
+
send_data(response)
|
123
|
+
unbind if @request.params['HTTP_CONNECTION'] == 'close'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,407 @@
|
|
1
|
+
#
|
2
|
+
module StompServer
|
3
|
+
module StompServer::Protocols
|
4
|
+
#
|
5
|
+
VALID_COMMANDS = [
|
6
|
+
:abort, # Explicit method supplied
|
7
|
+
:ack, # Explicit method supplied
|
8
|
+
:begin, # Explicit method supplied
|
9
|
+
:commit, # Explicit method supplied
|
10
|
+
:connect, # Explicit method supplied
|
11
|
+
:disconnect, # Explicit method supplied
|
12
|
+
:send, # Explicit method supplied
|
13
|
+
:subscribe, # Explicit method supplied
|
14
|
+
:unsubscribe # Explicit method supplied
|
15
|
+
]
|
16
|
+
#
|
17
|
+
# = Stomp Protocol Handler.
|
18
|
+
#
|
19
|
+
class Stomp < EventMachine::Connection
|
20
|
+
|
21
|
+
attr_reader :session_id
|
22
|
+
|
23
|
+
# Protocol handler initialization
|
24
|
+
def initialize(*args)
|
25
|
+
super(*args)
|
26
|
+
#
|
27
|
+
@@log = Logger.new(STDOUT)
|
28
|
+
@@log.level = StompServer::LogHelper.get_loglevel()
|
29
|
+
#
|
30
|
+
@@options = (Hash === args.last) ? args.pop : {}
|
31
|
+
# Arguments are passed from EventMachine::start_server
|
32
|
+
@@auth_required = args[0]
|
33
|
+
@@queue_manager = args[1]
|
34
|
+
@@topic_manager = args[2]
|
35
|
+
@@stompauth = args[3]
|
36
|
+
#
|
37
|
+
# N.B.: The session ID is an instance variable!
|
38
|
+
#
|
39
|
+
if @@options[:session_cache] == 0
|
40
|
+
lt = Time.now
|
41
|
+
@session_id = "ssng_#{lt.to_f}"
|
42
|
+
else
|
43
|
+
@session_id = StompServer::SessionIDManager.get_cache_id(@@options[:session_cache])
|
44
|
+
end
|
45
|
+
@@log.debug("#{@session_id} #{self} Session ID assigned")
|
46
|
+
#
|
47
|
+
@@log.warn("#{@session_id} #{self} Protocol initialization complete")
|
48
|
+
end
|
49
|
+
|
50
|
+
# :stopdoc:
|
51
|
+
#
|
52
|
+
# <tt>EM::Connection.close_connection()</tt>
|
53
|
+
#
|
54
|
+
# <tt>EM::Connection.close_connection_after_writing()</tt>
|
55
|
+
#
|
56
|
+
# <tt>EM::Connection.comm_inactivity_timeout()</tt>
|
57
|
+
#
|
58
|
+
# <tt>EM::Connection.comm_inactivity_timeout=(value)</tt>
|
59
|
+
#
|
60
|
+
# <tt>EM::Connection.connection_completed()</tt>
|
61
|
+
#
|
62
|
+
# <tt>EM::Connection.detach()</tt>
|
63
|
+
#
|
64
|
+
# <tt>EM::Connection.error?()</tt>
|
65
|
+
#
|
66
|
+
# <tt>EM::Connection.get_peer_cert()</tt>
|
67
|
+
#
|
68
|
+
# <tt>EM::Connection.get_peername()</tt>
|
69
|
+
#
|
70
|
+
# <tt>EM::Connection.get_pid()</tt>
|
71
|
+
#
|
72
|
+
# <tt>EM::Connection.get_sock_opt(level,option)</tt>
|
73
|
+
#
|
74
|
+
# <tt>EM::Connection.get_sockname()</tt>
|
75
|
+
#
|
76
|
+
# <tt>EM::Connection.get_status()</tt>
|
77
|
+
#
|
78
|
+
# <tt>EM::Connection.notify_readable=(mode)</tt>
|
79
|
+
#
|
80
|
+
# <tt>EM::Connection.notify_readable?()</tt>
|
81
|
+
#
|
82
|
+
# <tt>EM::Connection.notify_writable=(mode)</tt>
|
83
|
+
#
|
84
|
+
# <tt>EM::Connection.notify_writable?()</tt>
|
85
|
+
#
|
86
|
+
# <tt>EM::Connection.pause()</tt>
|
87
|
+
#
|
88
|
+
# <tt>EM::Connection.paused?()</tt>
|
89
|
+
#
|
90
|
+
# <tt>EM::Connection.pending_connect_timeout()</tt>
|
91
|
+
#
|
92
|
+
# <tt>EM::Connection.pending_connect_timeout=(value)</tt>
|
93
|
+
#
|
94
|
+
|
95
|
+
# :startdoc:
|
96
|
+
|
97
|
+
# <tt>EM::Connection.post_init()</tt>
|
98
|
+
#
|
99
|
+
# Protocol handler post initialization.
|
100
|
+
def post_init
|
101
|
+
@sfr = StompServer::StompFrameRecognizer.new
|
102
|
+
@transactions = {}
|
103
|
+
@connected = false
|
104
|
+
@@log.debug("#{@session_id} protocol post_init complete")
|
105
|
+
end
|
106
|
+
|
107
|
+
# :stopdoc:
|
108
|
+
|
109
|
+
#
|
110
|
+
# <tt>EM::Connection.proxy_incoming_to(conn,bufsize=0)</tt>
|
111
|
+
#
|
112
|
+
# <tt>EM::Connection.proxy_target_unbound()</tt>
|
113
|
+
#
|
114
|
+
|
115
|
+
# :startdoc:
|
116
|
+
|
117
|
+
# <tt>EM::Connection.receive_data(data)</tt>
|
118
|
+
#
|
119
|
+
# Delegate to stomp_receive_data helper.
|
120
|
+
#
|
121
|
+
def receive_data(data)
|
122
|
+
stomp_receive_data(data)
|
123
|
+
end
|
124
|
+
|
125
|
+
# :stopdoc:
|
126
|
+
|
127
|
+
# <tt>EM::Connection.reconnect(server,port)</tt>
|
128
|
+
#
|
129
|
+
# <tt>EM::Connection.resume()</tt>
|
130
|
+
#
|
131
|
+
|
132
|
+
# :startdoc:
|
133
|
+
|
134
|
+
# <tt>EM::Connection.send_data(data)</tt>
|
135
|
+
#
|
136
|
+
# Just calls super.
|
137
|
+
#
|
138
|
+
def send_data(data)
|
139
|
+
super(data)
|
140
|
+
end
|
141
|
+
|
142
|
+
# :stopdoc:
|
143
|
+
|
144
|
+
# <tt>EM::Connection.send_datagram(data,recipient_address,recipient_port)</tt>
|
145
|
+
#
|
146
|
+
# <tt>EM::Connection.send_file_data(filename)</tt>
|
147
|
+
#
|
148
|
+
# <tt>EM::Connection.set_comm_inactivity_timeout(value)</tt>
|
149
|
+
#
|
150
|
+
# <tt>EM::Connection.set_pending_connect_timeout(value)</tt>
|
151
|
+
#
|
152
|
+
# <tt>EM::Connection.ssl_handshake_completed()</tt>
|
153
|
+
#
|
154
|
+
# <tt>EM::Connection.ssl_verify_peer(cert)</tt>
|
155
|
+
#
|
156
|
+
# <tt>EM::Connection.start_tls(args={})</tt>
|
157
|
+
#
|
158
|
+
# <tt>EM::Connection.stop_proxying()</tt>
|
159
|
+
#
|
160
|
+
# <tt>EM::Connection.stream_file_data(filename, args={})</tt>
|
161
|
+
#
|
162
|
+
|
163
|
+
# :startdoc:
|
164
|
+
|
165
|
+
# <tt>EM::Connection.unbind()</tt>
|
166
|
+
#
|
167
|
+
# Unbind the connection.
|
168
|
+
#
|
169
|
+
def unbind()
|
170
|
+
@@log.warn "#{@session_id} Unbind called"
|
171
|
+
@connected = false
|
172
|
+
@@queue_manager.disconnect(self)
|
173
|
+
@@topic_manager.disconnect(self)
|
174
|
+
end
|
175
|
+
|
176
|
+
# :stopdoc:
|
177
|
+
|
178
|
+
# Stomp Protocol Verbs
|
179
|
+
|
180
|
+
# :startdoc:
|
181
|
+
#
|
182
|
+
# Stomp Protocol - ABORT
|
183
|
+
#
|
184
|
+
def abort(frame, trans=nil)
|
185
|
+
raise "#{@session_id} Missing transaction" unless trans
|
186
|
+
raise "#{@session_id} transaction does not exist" unless @transactions.has_key?(trans)
|
187
|
+
@transactions.delete(trans)
|
188
|
+
end
|
189
|
+
#
|
190
|
+
# Stomp Protocol - ACK
|
191
|
+
#
|
192
|
+
# Delegated to the queue manager.
|
193
|
+
#
|
194
|
+
def ack(frame)
|
195
|
+
@@queue_manager.ack(self, frame)
|
196
|
+
end
|
197
|
+
#
|
198
|
+
# Stomp Protocol - BEGIN
|
199
|
+
#
|
200
|
+
def begin(frame, trans=nil)
|
201
|
+
raise "#{@session_id} Missing transaction" unless trans
|
202
|
+
raise "#{@session_id} transaction exists" if @transactions.has_key?(trans)
|
203
|
+
@transactions[trans] = []
|
204
|
+
end
|
205
|
+
#
|
206
|
+
# Stomp Protocol - COMMIT
|
207
|
+
#
|
208
|
+
def commit(frame, trans=nil)
|
209
|
+
raise "#{@session_id} Missing transaction" unless trans
|
210
|
+
raise "#{@session_id} transaction does not exist" unless @transactions.has_key?(trans)
|
211
|
+
#
|
212
|
+
(@transactions[trans]).each do |frame|
|
213
|
+
frame.headers.delete('transaction')
|
214
|
+
process_frame(frame)
|
215
|
+
end
|
216
|
+
@transactions.delete(trans)
|
217
|
+
end
|
218
|
+
#
|
219
|
+
# Stomp Protocol - CONNECT
|
220
|
+
#
|
221
|
+
def connect(frame)
|
222
|
+
if @@auth_required
|
223
|
+
unless frame.headers['login'] and frame.headers['passcode'] and @@stompauth.authorized[frame.headers['login']] == frame.headers['passcode']
|
224
|
+
raise "#{@session_id} {self} Invalid Login"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
@@log.warn "#{@session_id} Connecting"
|
228
|
+
response = StompServer::StompFrame.new("CONNECTED", {'session' => @session_id})
|
229
|
+
#
|
230
|
+
stomp_send_data(response)
|
231
|
+
@connected = true
|
232
|
+
end
|
233
|
+
#
|
234
|
+
# Stomp Protocol - DISCONNECT
|
235
|
+
#
|
236
|
+
def disconnect(frame)
|
237
|
+
@@log.warn "#{@session_id} Polite disconnect"
|
238
|
+
close_connection_after_writing
|
239
|
+
end
|
240
|
+
#
|
241
|
+
# Stomp Protocol - SEND
|
242
|
+
#
|
243
|
+
# The stomp SEND verb is by routing through:
|
244
|
+
#
|
245
|
+
# * receive_data(data)
|
246
|
+
# * stomp_receive_data
|
247
|
+
# * process_frames
|
248
|
+
# * process_frame
|
249
|
+
# * use Object#__send__ to call this method
|
250
|
+
#
|
251
|
+
def send(frame)
|
252
|
+
# set message id
|
253
|
+
if frame.dest.match(%r|^/queue|)
|
254
|
+
@@queue_manager.sendmsg(frame)
|
255
|
+
else
|
256
|
+
frame.headers['message-id'] = "msg-#stompcma-#{@@topic_manager.next_index}"
|
257
|
+
@@topic_manager.sendmsg(frame)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
#
|
261
|
+
#
|
262
|
+
# Stomp Protocol - SUBSCRIBE
|
263
|
+
#
|
264
|
+
# Delegated to the queue or topic manager.
|
265
|
+
#
|
266
|
+
def subscribe(frame)
|
267
|
+
use_ack = false
|
268
|
+
use_ack = true if frame.headers['ack'] == 'client'
|
269
|
+
#
|
270
|
+
if frame.headers['id']
|
271
|
+
subid = frame.headers['id']
|
272
|
+
elsif frame.headers[:id]
|
273
|
+
subid = frame.headers[:id]
|
274
|
+
else
|
275
|
+
subid = nil
|
276
|
+
end
|
277
|
+
#
|
278
|
+
if frame.dest =~ %r|^/queue|
|
279
|
+
@@queue_manager.subscribe(frame.dest, self, use_ack, subid)
|
280
|
+
else
|
281
|
+
@@topic_manager.subscribe(frame.dest, self)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
#
|
285
|
+
# Stomp Protocol - UNSUBSCRIBE
|
286
|
+
#
|
287
|
+
# Delegated to the queue or topic manager.
|
288
|
+
#
|
289
|
+
def unsubscribe(frame)
|
290
|
+
if frame.dest =~ %r|^/queue|
|
291
|
+
@@queue_manager.unsubscribe(frame.dest,self)
|
292
|
+
else
|
293
|
+
@@topic_manager.unsubscribe(frame.dest,self)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# :stopdoc:
|
298
|
+
|
299
|
+
# Helper methods
|
300
|
+
|
301
|
+
# :startdoc:
|
302
|
+
#
|
303
|
+
# stomp_receive_data
|
304
|
+
#
|
305
|
+
# Called from <tt>EM::Connection.receive_data(data)</tt>. This is where
|
306
|
+
# we begin processing a set of data fresh off the wire.
|
307
|
+
#
|
308
|
+
def stomp_receive_data(data)
|
309
|
+
begin
|
310
|
+
# Limit log message length.
|
311
|
+
logdata = data
|
312
|
+
logdata = data[0..256] + "...truncated..." if data.length > 256
|
313
|
+
@@log.debug "#{@session_id} receive_data: #{logdata.inspect}"
|
314
|
+
# Append all data to the recognizer buffer.
|
315
|
+
@sfr << data
|
316
|
+
# Process any stomp frames in this set of data.
|
317
|
+
process_frames
|
318
|
+
rescue Exception => e
|
319
|
+
@@log.error "#{@session_id} err: #{e} #{e.backtrace.join("\n")}"
|
320
|
+
send_error(e.to_s)
|
321
|
+
close_connection_after_writing
|
322
|
+
end
|
323
|
+
end
|
324
|
+
#
|
325
|
+
# process_frames
|
326
|
+
#
|
327
|
+
# Handle all stomp frames currently in the recognizer's accumulated
|
328
|
+
# array of frames.
|
329
|
+
#
|
330
|
+
def process_frames
|
331
|
+
frame = nil
|
332
|
+
process_frame(frame) while frame = @sfr.frames.shift
|
333
|
+
end
|
334
|
+
#
|
335
|
+
# process_frame
|
336
|
+
#
|
337
|
+
# Process and individual stomp frame.
|
338
|
+
#
|
339
|
+
def process_frame(frame)
|
340
|
+
cmd = frame.command.downcase.to_sym
|
341
|
+
raise "#{@session_id} #{self} Unhandled frame: #{cmd}" unless VALID_COMMANDS.include?(cmd)
|
342
|
+
raise "#{@session_id} #{self} Not connected" if !@connected && cmd != :connect
|
343
|
+
@@log.debug("#{@session_id} process_frame: #{frame.command}")
|
344
|
+
# Add session ID to the frame headers
|
345
|
+
frame.headers['session'] = @session_id
|
346
|
+
# Send receipt first if required
|
347
|
+
send_receipt(frame.headers['receipt']) if frame.headers['receipt']
|
348
|
+
#
|
349
|
+
if trans = frame.headers['transaction']
|
350
|
+
# Handle transactional frame if required.
|
351
|
+
handle_transaction(frame, trans, cmd)
|
352
|
+
else
|
353
|
+
# Otherwise, just route the non-transactional frame.
|
354
|
+
__send__(cmd, frame) # Object#send alias call
|
355
|
+
end
|
356
|
+
end
|
357
|
+
#
|
358
|
+
# handle_transaction
|
359
|
+
#
|
360
|
+
def handle_transaction(frame, trans, cmd)
|
361
|
+
if [:begin, :commit, :abort].include?(cmd)
|
362
|
+
__send__(cmd, frame, trans) # Object#send alias call
|
363
|
+
else
|
364
|
+
raise "#{@session_id} transaction does not exist" unless @transactions.has_key?(trans)
|
365
|
+
@transactions[trans] << frame
|
366
|
+
end
|
367
|
+
end
|
368
|
+
#
|
369
|
+
# send_error
|
370
|
+
#
|
371
|
+
# Send a single error frame.
|
372
|
+
#
|
373
|
+
def send_error(msg)
|
374
|
+
send_frame("ERROR",{'message' => 'See below'},msg)
|
375
|
+
end
|
376
|
+
#
|
377
|
+
# send_frame
|
378
|
+
#
|
379
|
+
# Send an individual stomp frame.
|
380
|
+
#
|
381
|
+
def send_frame(command, headers={}, body='')
|
382
|
+
headers['content-length'] = body.size.to_s
|
383
|
+
response = StompServer::StompFrame.new(command, headers, body)
|
384
|
+
stomp_send_data(response)
|
385
|
+
end
|
386
|
+
#
|
387
|
+
# send_receipt
|
388
|
+
#
|
389
|
+
# Send a single receipt frame.
|
390
|
+
#
|
391
|
+
def send_receipt(id)
|
392
|
+
send_frame("RECEIPT", { 'receipt-id' => id})
|
393
|
+
end
|
394
|
+
#
|
395
|
+
# stomp_send_data
|
396
|
+
#
|
397
|
+
def stomp_send_data(frame)
|
398
|
+
@@log.debug "#{@session_id} Sending frame #{frame.to_s}"
|
399
|
+
send_data(frame.to_s)
|
400
|
+
end
|
401
|
+
|
402
|
+
#
|
403
|
+
end # class Stomp < EventMachine::Connection
|
404
|
+
#
|
405
|
+
end # module StompServer::Protocols
|
406
|
+
end # module StompServer
|
407
|
+
|