nebulous_stomp 2.0.2 → 3.0.0
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.
- checksums.yaml +4 -4
- data/.hgignore +2 -0
- data/.hgtags +1 -0
- data/README.md +225 -28
- data/feature/connection_example.yaml +24 -0
- data/feature/feature_test_spec.rb +247 -0
- data/feature/gimme.rb +91 -0
- data/lib/nebulous_stomp/listener.rb +107 -0
- data/lib/nebulous_stomp/message.rb +132 -265
- data/lib/nebulous_stomp/msg/body.rb +169 -0
- data/lib/nebulous_stomp/msg/header.rb +98 -0
- data/lib/nebulous_stomp/param.rb +16 -35
- data/lib/nebulous_stomp/redis_handler.rb +19 -29
- data/lib/nebulous_stomp/redis_handler_null.rb +12 -11
- data/lib/nebulous_stomp/redis_helper.rb +110 -0
- data/lib/nebulous_stomp/request.rb +212 -0
- data/lib/nebulous_stomp/stomp_handler.rb +30 -96
- data/lib/nebulous_stomp/stomp_handler_null.rb +8 -22
- data/lib/nebulous_stomp/target.rb +52 -0
- data/lib/nebulous_stomp/version.rb +1 -1
- data/lib/nebulous_stomp.rb +63 -50
- data/md/LICENSE.txt +20 -2
- data/md/nebulous_protocol.md +25 -18
- data/spec/listener_spec.rb +104 -0
- data/spec/message_spec.rb +227 -116
- data/spec/nebulous_spec.rb +44 -9
- data/spec/param_spec.rb +16 -33
- data/spec/redis_handler_null_spec.rb +0 -2
- data/spec/redis_handler_spec.rb +0 -2
- data/spec/redis_helper_spec.rb +107 -0
- data/spec/request_spec.rb +249 -0
- data/spec/stomp_handler_null_spec.rb +33 -34
- data/spec/stomp_handler_spec.rb +1 -74
- data/spec/target_spec.rb +97 -0
- metadata +20 -11
- data/lib/nebulous_stomp/nebrequest.rb +0 -259
- data/lib/nebulous_stomp/nebrequest_null.rb +0 -37
- data/spec/nebrequest_null_spec.rb +0 -219
- data/spec/nebrequest_spec.rb +0 -239
- data/spec/through_test_spec.rb +0 -80
@@ -0,0 +1,107 @@
|
|
1
|
+
require_relative 'target'
|
2
|
+
require_relative 'stomp_handler'
|
3
|
+
|
4
|
+
|
5
|
+
module NebulousStomp
|
6
|
+
|
7
|
+
|
8
|
+
##
|
9
|
+
# Implements the Request-Response use case; consume Requests from an input queue and send
|
10
|
+
# Responses.
|
11
|
+
#
|
12
|
+
# listener = NebulousStomp::Listener.new(target)
|
13
|
+
# listener.consume_messages do |msg|
|
14
|
+
# begin
|
15
|
+
#
|
16
|
+
# case msg.verb
|
17
|
+
# when "ping"
|
18
|
+
# listener.reply *msg.respond_with_success
|
19
|
+
# when "time"
|
20
|
+
# listener.reply *msg.respond_with_protocol("timeresponce", Time.now)
|
21
|
+
# else
|
22
|
+
# listener.reply *msg.respond_with_error("Bad verb #{msg.verb}")
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# rescue
|
26
|
+
# listener.reply *msg.respond_with_error($!)
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# loop { sleep 5 }
|
31
|
+
#
|
32
|
+
class Listener
|
33
|
+
|
34
|
+
# the queue name we are listening to
|
35
|
+
attr_reader :queue
|
36
|
+
|
37
|
+
# Insert a StompHandler object for test purposes
|
38
|
+
attr_writer :stomp_handler
|
39
|
+
|
40
|
+
##
|
41
|
+
# When creating a Listener, pass the queue name to listen on.
|
42
|
+
#
|
43
|
+
# This can be something stringlike, or a Target (in which case we listen on the target's
|
44
|
+
# receiving queue).
|
45
|
+
#
|
46
|
+
def initialize(queue)
|
47
|
+
case
|
48
|
+
when queue.respond_to?(:receive_queue) then @queue = queue.receive_queue
|
49
|
+
when queue.respond_to?(:to_s) then @queue = queue.to_s
|
50
|
+
else fail ArgumentError, "Unknown object passed as queue"
|
51
|
+
end
|
52
|
+
|
53
|
+
NebulousStomp.logger.debug(__FILE__) { "Listening on #@queue" }
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# :call-seq:
|
58
|
+
# listener.consume_message(queue) {|msg| ... }
|
59
|
+
#
|
60
|
+
# Consume messages from the queue, yielding each.
|
61
|
+
#
|
62
|
+
# Note that we don't block for input here. Just as with the Stomp gem, and with StompHandler,
|
63
|
+
# you will need to take your own measures to ensure that your program does not end when it
|
64
|
+
# should be waiting for messages to arrive. The simplest solution is something like:
|
65
|
+
#
|
66
|
+
# loop { sleep 5 }
|
67
|
+
#
|
68
|
+
# Note also that this method runs inside a Thread, and so does the block you pass to it. By
|
69
|
+
# default threads do not report errors, so you must arrange to do that yourself.
|
70
|
+
#
|
71
|
+
def consume_messages
|
72
|
+
stomp_handler.listen(@queue) {|msg| yield msg }
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Send a message in reply
|
77
|
+
#
|
78
|
+
# Queue must be a queue name; message must be a Message. The usual way to get these is from the
|
79
|
+
# Message class, for example by calling `message.respond_with_success`.
|
80
|
+
#
|
81
|
+
def reply(queue, message)
|
82
|
+
NebulousStomp.logger.debug(__FILE__) { "Replying to #{queue}" }
|
83
|
+
stomp_handler.send_message(queue, message)
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Disconnect from Stomp.
|
89
|
+
#
|
90
|
+
# You probably don't need this; Stomp connections are quite short lived.
|
91
|
+
#
|
92
|
+
def quit
|
93
|
+
stomp_handler.stomp_disconnect
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def stomp_handler
|
100
|
+
@stomp_handler ||= StompHandler.new(Param.get :stompConnectHash)
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
end
|
107
|
+
|
@@ -1,177 +1,156 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'forwardable'
|
2
3
|
|
3
4
|
require_relative 'stomp_handler'
|
5
|
+
require_relative 'msg/header'
|
6
|
+
require_relative 'msg/body'
|
4
7
|
|
5
8
|
|
6
9
|
module NebulousStomp
|
7
10
|
|
8
11
|
|
9
12
|
##
|
10
|
-
# A class to encapsulate a Nebulous message (which is built on top of a
|
11
|
-
# STOMP message)
|
13
|
+
# A class to encapsulate a Nebulous message (which is built on top of a STOMP message)
|
12
14
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
15
|
+
# This class is entirely read-only, except for reply_id, which is set by Request when the
|
16
|
+
# message is sent.
|
17
|
+
#
|
18
|
+
# Much of this class is handled by two helper classes: the message headers are handled by
|
19
|
+
# Msg::Header and the message body by Msg::Body. You should look at them, too, for the full
|
20
|
+
# picture.
|
18
21
|
#
|
19
22
|
class Message
|
23
|
+
extend Forwardable
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
def_delegators :@header, :stomp_headers, :reply_to, :in_reply_to, :reply_id, :content_type,
|
26
|
+
:reply_id=, :content_is_json?, :headers_for_stomp
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
# The content type of the message
|
28
|
-
attr_reader :content_type
|
28
|
+
def_delegators :@body, :stomp_body, :body, :verb, :params, :desc,
|
29
|
+
:body_to_h, :protocol_json, :body_for_stomp
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
# writable, which is not ideal.
|
33
|
-
attr_reader :verb, :params, :desc
|
34
|
-
attr_reader :reply_to, :in_reply_to
|
31
|
+
alias :parameters :params
|
32
|
+
alias :description :desc
|
35
33
|
|
36
34
|
|
37
35
|
class << self
|
38
36
|
|
39
|
-
|
40
37
|
##
|
41
|
-
#
|
38
|
+
# :call-seq:
|
39
|
+
# Message.in_reply_to(message, args) -> Message
|
42
40
|
#
|
43
|
-
#
|
44
|
-
# message by hand in Ruby, this is only reasonable.
|
41
|
+
# Build a Message that replies to an existing Message
|
45
42
|
#
|
46
|
-
#
|
43
|
+
# * msg - the Nebulous::Message that you are replying to
|
44
|
+
# * args - hash as per Message.new
|
47
45
|
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
# * verb, params, desc - The Protocol; the message to pass
|
46
|
+
# See also #respond, #respond_with_protocol, etc, etc. (which you are probably better off
|
47
|
+
# calling, to be honest).
|
51
48
|
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
else params.to_s
|
62
|
-
end
|
63
|
-
|
64
|
-
self.new( replyTo: replyTo.to_s,
|
65
|
-
inReplyTo: inReplyTo.to_s,
|
66
|
-
verb: verb.to_s,
|
67
|
-
params: p,
|
68
|
-
desc: desc.nil? ? nil : desc.to_s,
|
69
|
-
contentType: 'application/json' )
|
70
|
-
|
71
|
-
end
|
49
|
+
# Note that this method absolutely enforces the protocol with regard to the content type and
|
50
|
+
# (of course) the id of the message it is replying to; for example, even if you pass a
|
51
|
+
# different content type it will take the content type of the msg in preference. If you want
|
52
|
+
# something weirder, you will have to use Message.new.
|
53
|
+
#
|
54
|
+
def in_reply_to(msg, args)
|
55
|
+
fail ArgumentError, 'bad message' unless msg.kind_of? Message
|
56
|
+
fail ArgumentError, 'bad hash' unless args.kind_of? Hash
|
57
|
+
fail ArgumentError, 'message has no reply ID' unless msg.reply_id
|
72
58
|
|
59
|
+
NebulousStomp.logger.debug(__FILE__){ "New message in reply to #{msg}" }
|
73
60
|
|
74
|
-
|
75
|
-
|
76
|
-
#
|
77
|
-
# * msg - the Nebulous::Message that you are replying to
|
78
|
-
# * verb, params, desc - the new message Protocol
|
79
|
-
#
|
80
|
-
def in_reply_to(msg, verb, params=nil, desc=nil, replyTo=nil)
|
81
|
-
raise ArgumentError, 'bad message' unless msg.kind_of? Message
|
82
|
-
|
83
|
-
NebulousStomp.logger.debug(__FILE__){ "New message reply" }
|
84
|
-
|
85
|
-
p =
|
86
|
-
case params
|
87
|
-
when NilClass then nil
|
88
|
-
when Array then params.dup
|
89
|
-
else params.to_s
|
90
|
-
end
|
91
|
-
|
92
|
-
m = msg.clone
|
93
|
-
self.new( replyTo: replyTo.to_s,
|
94
|
-
verb: verb.to_s,
|
95
|
-
params: p,
|
96
|
-
desc: desc.to_s,
|
97
|
-
inReplyTo: m.reply_id,
|
98
|
-
contentType: m.content_type )
|
61
|
+
hash = { inReplyTo: msg.reply_id,
|
62
|
+
contentType: msg.content_type }
|
99
63
|
|
64
|
+
self.new(args.merge hash)
|
100
65
|
end
|
101
66
|
|
102
|
-
|
103
67
|
##
|
104
|
-
#
|
68
|
+
# :call-seq:
|
69
|
+
# Message.from_stomp(stompmessage) -> Message
|
70
|
+
#
|
71
|
+
# Build a Message from a (presumably incoming) STOMP message; stompmessage must be a
|
72
|
+
# Stomp::Message.
|
105
73
|
#
|
106
74
|
def from_stomp(stompMsg)
|
107
|
-
|
108
|
-
unless stompMsg.kind_of? Stomp::Message
|
109
|
-
|
75
|
+
fail ArgumentError, 'not a stomp message' unless stompMsg.kind_of? Stomp::Message
|
110
76
|
NebulousStomp.logger.debug(__FILE__){ "New message from STOMP" }
|
111
77
|
|
112
78
|
s = Marshal.load( Marshal.dump(stompMsg) )
|
113
|
-
|
114
|
-
stompBody: s.body )
|
115
|
-
|
79
|
+
self.new(stompHeaders: s.headers, stompBody: s.body)
|
116
80
|
end
|
117
81
|
|
118
|
-
|
119
82
|
##
|
120
|
-
#
|
83
|
+
# :call-seq:
|
84
|
+
# Message.from_cache(hash) -> Message
|
85
|
+
#
|
86
|
+
# To build a Nebmessage from a record in the Redis cache.
|
121
87
|
#
|
122
|
-
# See #
|
88
|
+
# See #to_h for details of the hash that Redis should be storing
|
123
89
|
#
|
124
90
|
def from_cache(json)
|
125
|
-
|
126
|
-
unless json.kind_of? String
|
127
|
-
|
91
|
+
fail ArgumentError, "That can't be JSON, it's not a string" unless json.kind_of? String
|
128
92
|
NebulousStomp.logger.debug(__FILE__){ "New message from cache" }
|
129
93
|
|
130
|
-
# Note that the message body at this point, for a JSON message, is
|
131
|
-
#
|
132
|
-
#
|
133
|
-
# with this so long as the whole string is not double-encoded.
|
94
|
+
# Note that the message body at this point, for a JSON message, is actually encoded to JSON
|
95
|
+
# *twice* - the second time was when the cache hash as a whole was encoded for store in
|
96
|
+
# Redis. the JSON gem copes with this so long as the whole string is not double-encoded.
|
134
97
|
hash = JSON.parse(json, :symbolize_names => true)
|
135
|
-
|
98
|
+
fail ArgumentError, 'Empty cache entry' if hash == {}
|
136
99
|
|
137
|
-
# So now if the content type is JSON then the body is still JSON now.
|
138
|
-
#
|
139
|
-
# Now join us for this weeks' episode...
|
100
|
+
# So now if the content type is JSON then the body is still JSON now. It's only the rest of
|
101
|
+
# the cache hash that is a now a hash. Confused? Now join us for this weeks' episode...
|
140
102
|
self.new( hash.clone )
|
141
103
|
|
142
104
|
rescue JSON::ParserError => err
|
143
|
-
|
105
|
+
fail ArgumentError, "Bad JSON: #{err.message}"
|
144
106
|
end
|
145
107
|
|
146
|
-
end
|
147
|
-
##
|
148
|
-
|
149
|
-
|
150
|
-
alias :parameters :params
|
151
|
-
alias :description :desc
|
152
|
-
|
153
|
-
|
154
|
-
def to_s
|
155
|
-
"<Message[#{@reply_id}] to:#{@reply_to} r-to:#{@in_reply_to} " \
|
156
|
-
<< "v:#{@verb}>"
|
157
|
-
|
158
|
-
end
|
108
|
+
end # class << self
|
159
109
|
|
160
110
|
|
161
111
|
##
|
162
|
-
#
|
112
|
+
# Create a new message,
|
113
|
+
#
|
114
|
+
# There are three ways that a message could get created:
|
115
|
+
#
|
116
|
+
# 1. The user could create one directly.
|
117
|
+
#
|
118
|
+
# 2. A message could be created from an incoming STOMP message, in which case we should
|
119
|
+
# call Message.from_stomp to create it.
|
163
120
|
#
|
164
|
-
|
165
|
-
|
121
|
+
# 3. A message could be created because we have retreived it from the Redis cache, in which
|
122
|
+
# case we should call Message.from_cache to create it (and, note, it will originally
|
123
|
+
# have been created in one of the other two ways...)
|
124
|
+
#
|
125
|
+
# The full list of useful hash keys is (as per Message.from_cache, #to_h):
|
126
|
+
#
|
127
|
+
# * :body -- the message body
|
128
|
+
# * :contentType -- Stomp content type string
|
129
|
+
# * :description / :desc -- part of The Protocol
|
130
|
+
# * :inReplyTo -- message ID that message is a response to
|
131
|
+
# * :parameters / :params -- part of The Protocol
|
132
|
+
# * :replyId -- the 'unique' ID of this Nebulous message
|
133
|
+
# * :replyTo -- for a request, the queue to be used for the response
|
134
|
+
# * :stompBody -- for a message from Stomp, the raw Stomp message body
|
135
|
+
# * :stompHeaders -- for a message from Stomp, the raw Stomp Headers string
|
136
|
+
# * :verb -- part of The Protocol
|
137
|
+
#
|
138
|
+
def initialize(hash)
|
139
|
+
@header = Msg::Header.new(hash)
|
140
|
+
@body = Msg::Body.new(content_is_json?, hash)
|
166
141
|
end
|
167
142
|
|
143
|
+
def to_s
|
144
|
+
"<Message[#{reply_id}] to:#{reply_to} r-to:#{in_reply_to} v:#{verb}>"
|
145
|
+
end
|
168
146
|
|
169
147
|
##
|
170
|
-
# Output a hash for serialization to the cache.
|
148
|
+
# Output a hash for serialization to the Redis cache.
|
171
149
|
#
|
172
150
|
# Currently this looks like:
|
173
151
|
# { stompHeaders: @stomp_headers,
|
174
152
|
# stompBody: @stomp_body,
|
153
|
+
# body: @body
|
175
154
|
# verb: @verb,
|
176
155
|
# params: @params,
|
177
156
|
# desc: @desc,
|
@@ -180,186 +159,74 @@ module NebulousStomp
|
|
180
159
|
# inReplyTo: @in_reply_to,
|
181
160
|
# contentType: @content_type }
|
182
161
|
#
|
183
|
-
|
184
|
-
|
185
|
-
stompBody: @stomp_body,
|
186
|
-
verb: @verb,
|
187
|
-
params: @params.kind_of?(Enumerable) ? @params.dup : @params,
|
188
|
-
desc: @desc,
|
189
|
-
replyTo: @reply_to,
|
190
|
-
replyId: @reply_id,
|
191
|
-
inReplyTo: @in_reply_to,
|
192
|
-
contentType: @content_type }
|
193
|
-
|
194
|
-
end
|
195
|
-
|
196
|
-
|
197
|
-
##
|
198
|
-
# Return the hash of additional headers for the Stomp gem
|
162
|
+
# Note that if :stompBody is set then :body will be nil. This is to attempt to reduce
|
163
|
+
# duplication of what might be a rather large string.
|
199
164
|
#
|
200
|
-
def
|
201
|
-
|
202
|
-
"neb-reply-id" => @reply_id }
|
203
|
-
|
204
|
-
headers["neb-reply-to"] = @reply_to if @reply_to
|
205
|
-
headers["neb-in-reply-to"] = @in_reply_to if @in_reply_to
|
206
|
-
|
207
|
-
headers
|
208
|
-
end
|
209
|
-
|
210
|
-
|
211
|
-
##
|
212
|
-
# Return a body object for the Stomp gem
|
213
|
-
#
|
214
|
-
def body_for_stomp
|
215
|
-
hash = protocol_hash
|
216
|
-
|
217
|
-
if content_is_json?
|
218
|
-
hash.to_json
|
219
|
-
else
|
220
|
-
hash.map {|k,v| "#{k}: #{v}" }.join("\n") << "\n\n"
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
|
225
|
-
##
|
226
|
-
# :call-seq:
|
227
|
-
# message.body_to_h -> (Hash || nil)
|
228
|
-
#
|
229
|
-
# If the body is in JSON, return a hash.
|
230
|
-
# If body is nil, or is not JSON, then return nil; don't raise an exception
|
231
|
-
#
|
232
|
-
def body_to_h
|
233
|
-
x = StompHandler.body_to_hash(stomp_headers, stomp_body, @content_type)
|
234
|
-
x == {} ? nil : x
|
165
|
+
def to_h
|
166
|
+
@header.to_h.merge @body.to_h
|
235
167
|
end
|
236
168
|
|
169
|
+
alias :to_cache :to_h # old name
|
237
170
|
|
238
171
|
##
|
239
|
-
#
|
240
|
-
#
|
241
|
-
# Raise an exception if the message body doesn't follow the protocol.
|
172
|
+
# :call-seq:
|
173
|
+
# message.respond_with_protocol(verb, params=[], desc="") -> queue, Message
|
242
174
|
#
|
243
|
-
#
|
175
|
+
# Repond with a message using The Protocol.
|
244
176
|
#
|
245
|
-
def
|
246
|
-
|
247
|
-
|
177
|
+
def respond_with_protocol(verb, params=[], desc="")
|
178
|
+
fail NebulousError, "Don't know which queue to reply to" unless reply_to
|
179
|
+
|
180
|
+
hash = {verb: verb, params: params, desc: desc}
|
181
|
+
[ reply_to, Message.in_reply_to(self, hash) ]
|
248
182
|
end
|
249
183
|
|
250
|
-
|
251
184
|
##
|
252
|
-
#
|
253
|
-
#
|
254
|
-
# returns [queue, message] so you can just pass it to
|
255
|
-
# stomphandler.send_message.
|
185
|
+
# :call-seq:
|
186
|
+
# message.respond_with_protocol(body) -> queue, Message
|
256
187
|
#
|
257
|
-
|
258
|
-
|
188
|
+
# Repond with a message body (presumably a custom one that's non-Protocol).
|
189
|
+
#
|
190
|
+
def respond(body)
|
191
|
+
fail NebulousError, "Don't know which queue to reply to" unless reply_to
|
259
192
|
|
260
|
-
|
261
|
-
|
262
|
-
end
|
193
|
+
# Easy to do by mistake, pain in the arse to work out what's going on if you do
|
194
|
+
fail ArgumentError, "Respond takes a body, not a message" if body.is_a? Message
|
263
195
|
|
264
|
-
|
196
|
+
mess = Message.in_reply_to(self, body: body)
|
197
|
+
[ reply_to, mess ]
|
265
198
|
end
|
266
199
|
|
267
|
-
|
268
200
|
##
|
269
|
-
#
|
270
|
-
#
|
271
|
-
# err can be a string or an exception
|
201
|
+
# :call-seq:
|
202
|
+
# message.respond_with_success -> queue, Message
|
272
203
|
#
|
273
|
-
#
|
274
|
-
# stomphandler.send_message.
|
204
|
+
# Make a new 'success verb' message in response to this one.
|
275
205
|
#
|
276
|
-
def
|
277
|
-
|
278
|
-
|
279
|
-
NebulousStomp.logger.info(__FILE__) do
|
280
|
-
"Responded to #{self} with 'error': #{err}"
|
281
|
-
end
|
282
|
-
|
283
|
-
reply = Message.in_reply_to(self, 'error', fields, err.to_s)
|
284
|
-
|
285
|
-
[ @reply_to, reply ]
|
206
|
+
def respond_with_success
|
207
|
+
fail NebulousError, "Don't know which queue to reply to" unless reply_to
|
208
|
+
respond_with_protocol('success')
|
286
209
|
end
|
287
210
|
|
288
|
-
|
289
|
-
private
|
290
|
-
|
211
|
+
alias :respond_success :respond_with_success # old name
|
291
212
|
|
292
213
|
##
|
293
|
-
#
|
294
|
-
#
|
295
|
-
# .in_reply_to.
|
214
|
+
# :call-seq:
|
215
|
+
# message.respond_with_error(error, fields=[]) -> queue, Message
|
296
216
|
#
|
297
|
-
|
298
|
-
@stomp_headers = hash[:stompHeaders]
|
299
|
-
@stomp_body = hash[:stompBody]
|
300
|
-
|
301
|
-
@verb = hash[:verb]
|
302
|
-
@params = hash[:params]
|
303
|
-
@desc = hash[:desc]
|
304
|
-
@reply_to = hash[:replyTo]
|
305
|
-
@reply_id = hash[:replyId]
|
306
|
-
@in_reply_to = hash[:inReplyTo]
|
307
|
-
@content_type = hash[:contentType]
|
308
|
-
|
309
|
-
fill_from_message
|
310
|
-
end
|
311
|
-
|
312
|
-
|
313
|
-
##
|
314
|
-
# Return The Protocol of the message as a hash.
|
217
|
+
# Make a new 'error verb' message in response to this one.
|
315
218
|
#
|
316
|
-
|
317
|
-
|
318
|
-
h[:parameters] = @params unless @params.nil?
|
319
|
-
h[:description] = @desc unless @desc.nil?
|
320
|
-
|
321
|
-
h
|
322
|
-
end
|
323
|
-
|
324
|
-
|
325
|
-
##
|
326
|
-
# Fill all the other attributes, if you can, from @stomp_headers and
|
327
|
-
# @stomp_body.
|
219
|
+
# Error can be a string or an exception. Fields is an arbitrary array of values, designed as a
|
220
|
+
# list of the parameter keys with problems; but of course you can use it for whatever you like.
|
328
221
|
#
|
329
|
-
def
|
330
|
-
|
331
|
-
|
332
|
-
@content_type ||= @stomp_headers['content-type']
|
333
|
-
@reply_id ||= @stomp_headers['neb-reply-id']
|
334
|
-
@reply_to ||= @stomp_headers['neb-reply-to']
|
335
|
-
@in_reply_to ||= @stomp_headers['neb-in-reply-to']
|
336
|
-
end
|
337
|
-
|
338
|
-
# decode the body, which should either be a JSON string or a series of
|
339
|
-
# text fields. And use the body to set Protocol attributes.
|
340
|
-
if @stomp_body && !@stomp_body.empty?
|
341
|
-
|
342
|
-
raise "body is not a string, something is very wrong here!" \
|
343
|
-
unless @stomp_body.kind_of? String
|
344
|
-
|
345
|
-
h = StompHandler.body_to_hash( @stomp_headers,
|
346
|
-
@stomp_body,
|
347
|
-
@content_type )
|
348
|
-
|
349
|
-
@verb ||= h["verb"]
|
350
|
-
@params ||= h["parameters"] || h["params"]
|
351
|
-
@desc ||= h["description"] || h["desc"]
|
352
|
-
|
353
|
-
# Assume that if verb is missing, the other two are just part of a
|
354
|
-
# response which has nothing to do with the protocol
|
355
|
-
@params = @desc = nil unless @verb
|
356
|
-
end
|
357
|
-
|
358
|
-
self
|
222
|
+
def respond_with_error(err, fields=[])
|
223
|
+
fail NebulousError, "Don't know which queue to reply to" unless reply_to
|
224
|
+
respond_with_protocol('error', Array(fields).flatten.map(&:to_s), err.to_s)
|
359
225
|
end
|
360
226
|
|
361
|
-
|
362
|
-
|
227
|
+
alias :respond_error :respond_with_error # old name
|
228
|
+
|
229
|
+
end # Message
|
363
230
|
|
364
231
|
|
365
232
|
end
|