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,212 @@
|
|
1
|
+
require_relative 'stomp_handler'
|
2
|
+
require_relative 'redis_handler'
|
3
|
+
require_relative 'message'
|
4
|
+
require_relative 'target'
|
5
|
+
|
6
|
+
|
7
|
+
module NebulousStomp
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
# Class to handle a request which returns a Message; the Question-Answer use case.
|
12
|
+
#
|
13
|
+
# message = NebulousStomp::Message.new(verb: "ping")
|
14
|
+
# request = NebulousStomp::Request.new(:target1, message)
|
15
|
+
# response1 = request.send
|
16
|
+
#
|
17
|
+
# This replaces the old NebRequest class; it's much more clearly a wrapper for a Message, now.
|
18
|
+
#
|
19
|
+
class Request
|
20
|
+
|
21
|
+
# The Target object we are sending the request to
|
22
|
+
attr_reader :target
|
23
|
+
|
24
|
+
# The message we are sending (might not be the Message object you passed...)
|
25
|
+
attr_reader :message
|
26
|
+
|
27
|
+
# If you are testing you can write these with a test object like StompHandlerNull for example
|
28
|
+
attr_writer :stomp_handler, :redis_handler
|
29
|
+
|
30
|
+
##
|
31
|
+
# :call-seq:
|
32
|
+
# Request.new(target, message)
|
33
|
+
#
|
34
|
+
# Pass either a Target or a target name; and a Message (which has a verb)
|
35
|
+
#
|
36
|
+
def initialize(target, message)
|
37
|
+
@target = parse_target(target)
|
38
|
+
@message = parse_message(message, @target)
|
39
|
+
NebulousStomp.logger.debug(__FILE__) { "New Request for verb #{@message.verb}" }
|
40
|
+
|
41
|
+
# Get a connection to StompHandler ASAP and set reply_id on @message
|
42
|
+
ensure_stomp_connected if NebulousStomp.on?
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# :call-seq:
|
47
|
+
# request.send_no_cache -> (Message)
|
48
|
+
# request.send_no_cache(mtimeout) -> (Message)
|
49
|
+
#
|
50
|
+
# Send a request and return the response, without using the cache.
|
51
|
+
#
|
52
|
+
# Parameters:
|
53
|
+
# * mTimeout -- Message timout in seconds; defaults to #message_timeout
|
54
|
+
#
|
55
|
+
# Raises ArgumentError, NebulousTimeout or NebulousError as necessary.
|
56
|
+
#
|
57
|
+
# Note that this routine completely ignores Redis. It doesn't just not check the cache; it also
|
58
|
+
# doesn't update it.
|
59
|
+
#
|
60
|
+
def send_no_cache(mtimeout=message_timeout)
|
61
|
+
return nil unless NebulousStomp.on?
|
62
|
+
NebulousStomp.logger.info(__FILE__) { "Sending request to target #{@target.name}" }
|
63
|
+
|
64
|
+
ensure_stomp_connected
|
65
|
+
neb_qna(mtimeout)
|
66
|
+
ensure
|
67
|
+
stomp_handler.stomp_disconnect
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# :call-seq:
|
72
|
+
# request.send -> (Message)
|
73
|
+
# request.send(mTImeout) -> (Message)
|
74
|
+
# request.send(mtimeout,ctimeout) -> (Message)
|
75
|
+
#
|
76
|
+
# As send_nocache, but without not using the cache :)
|
77
|
+
#
|
78
|
+
# Parameters:
|
79
|
+
# * mtimeout -- Message timout in seconds; defaults to @mTimeout
|
80
|
+
# * ctimeout -- Cache timout in seconds; defaults to @cTimeout
|
81
|
+
#
|
82
|
+
# Raises ArgumentError, NebulousTimeout, NebulousError as necessary.
|
83
|
+
#
|
84
|
+
def send(mtimeout=message_timeout, ctimeout=cache_timeout)
|
85
|
+
return nil unless NebulousStomp.on?
|
86
|
+
return send_no_cache(mtimeout) unless NebulousStomp.redis_on?
|
87
|
+
ensure_redis_connected
|
88
|
+
|
89
|
+
if (mess = cache_read).nil?
|
90
|
+
mess = send_no_cache(mtimeout)
|
91
|
+
cache_write(mess, ctimeout)
|
92
|
+
end
|
93
|
+
|
94
|
+
mess
|
95
|
+
ensure
|
96
|
+
redis_handler.quit
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# :call-seq:
|
101
|
+
# request.clear_cache -> self
|
102
|
+
#
|
103
|
+
# Clear the cache of responses to this request - just this request.
|
104
|
+
#
|
105
|
+
def clear_cache
|
106
|
+
return self unless NebulousStomp.redis_on?
|
107
|
+
ensure_redis_connected
|
108
|
+
redis_handler.del(@message.protocol_json)
|
109
|
+
self
|
110
|
+
ensure
|
111
|
+
redis_handler.quit
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Returns the default message timeout
|
116
|
+
#
|
117
|
+
def message_timeout
|
118
|
+
@target.message_timeout || Param.get(:messageTimeout)
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Returns the default cache timeout
|
123
|
+
#
|
124
|
+
def cache_timeout
|
125
|
+
Param.get(:cacheTimeout)
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def stomp_handler
|
131
|
+
@stomp_handler ||= StompHandler.new(Param.get :stompConnectHash)
|
132
|
+
end
|
133
|
+
|
134
|
+
def redis_handler
|
135
|
+
@redis_handler ||= RedisHandler.new(Param.get :redisConnectHash)
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Helper routine for initialize
|
140
|
+
#
|
141
|
+
def parse_message(message, target)
|
142
|
+
fail ArgumentError, "Message was not a Message" unless message.is_a? Message
|
143
|
+
fail ArgumentError, "Message does not have a verb" unless message.verb
|
144
|
+
|
145
|
+
new_message = ->(h){ Message.new(message.to_h.merge h) }
|
146
|
+
message.reply_to ? message : new_message.(replyTo: target.send_queue)
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Helper routine for initialize
|
151
|
+
#
|
152
|
+
def parse_target(target)
|
153
|
+
t = target.is_a?(Target) ? target : Param.get_target(target)
|
154
|
+
fail ArgumentError, "Target was not a Target or a target name" unless t
|
155
|
+
t
|
156
|
+
end
|
157
|
+
|
158
|
+
##
|
159
|
+
# Connect to Stomp
|
160
|
+
# If we've lost the connection then reconnect but *keep replyID*
|
161
|
+
#
|
162
|
+
def ensure_stomp_connected
|
163
|
+
stomp_handler.stomp_connect unless stomp_handler.connected?
|
164
|
+
@message.reply_id = stomp_handler.calc_reply_id if @message.reply_id.nil?
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# Connect to Redis
|
169
|
+
#
|
170
|
+
def ensure_redis_connected
|
171
|
+
redis_handler.connect unless redis_handler.connected?
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# Send a message via STOMP and wait for a response
|
176
|
+
#
|
177
|
+
def neb_qna(mTimeout)
|
178
|
+
stomp_handler.send_message(@target.receive_queue, @message)
|
179
|
+
|
180
|
+
response = nil
|
181
|
+
stomp_handler.listen_with_timeout(@target.send_queue, mTimeout) do |msg|
|
182
|
+
if @message.reply_id && msg.in_reply_to != @message.reply_id
|
183
|
+
false
|
184
|
+
else
|
185
|
+
response = msg
|
186
|
+
true
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
response
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# Read from the Redis cache
|
195
|
+
#
|
196
|
+
def cache_read
|
197
|
+
found = redis_handler.get(@message.protocol_json)
|
198
|
+
found.nil? ? nil : Message.from_cache(found)
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# Write to the Redis cache
|
203
|
+
#
|
204
|
+
def cache_write(response, timeout)
|
205
|
+
redis_handler.set(@message.protocol_json, response.to_h, ex: timeout)
|
206
|
+
end
|
207
|
+
|
208
|
+
end # Request
|
209
|
+
|
210
|
+
|
211
|
+
end
|
212
|
+
|
@@ -8,9 +8,9 @@ module NebulousStomp
|
|
8
8
|
##
|
9
9
|
# A Class to deal with talking to STOMP via the Stomp gem.
|
10
10
|
#
|
11
|
-
# You
|
12
|
-
#
|
13
|
-
#
|
11
|
+
# You shouldn't ever need to instantiate this yourself. For listening to messages and
|
12
|
+
# responding, use NebulousStomp::Listener. For sending a message and waiting for a response, you
|
13
|
+
# want NebulousStomp::Request (passing it a NebulousStomp::Message).
|
14
14
|
#
|
15
15
|
class StompHandler
|
16
16
|
|
@@ -22,51 +22,6 @@ module NebulousStomp
|
|
22
22
|
#
|
23
23
|
class << self
|
24
24
|
|
25
|
-
|
26
|
-
##
|
27
|
-
# Parse stomp headers & body and return body as something Ruby-ish.
|
28
|
-
# It might not be a hash, in fact -- it could be an array of hashes.
|
29
|
-
#
|
30
|
-
# We assume that you are getting this from a STOMP message; the routine
|
31
|
-
# might not work if it is passed something other than Stomp::Message
|
32
|
-
# headers.
|
33
|
-
#
|
34
|
-
# If you have better intelligence as to the content type of the message,
|
35
|
-
# pass the content type as the optional third parameter.
|
36
|
-
#
|
37
|
-
def body_to_hash(headers, body, contentType=nil)
|
38
|
-
hdrs = headers || {}
|
39
|
-
|
40
|
-
raise ArgumentError, "headers is not a hash" \
|
41
|
-
unless hdrs.kind_of? Hash
|
42
|
-
|
43
|
-
type = contentType \
|
44
|
-
|| hdrs["content-type"] || hdrs[:content_type] \
|
45
|
-
|| hdrs["contentType"] || hdrs[:contentType]
|
46
|
-
|
47
|
-
hash = nil
|
48
|
-
|
49
|
-
if type =~ /json$/i
|
50
|
-
begin
|
51
|
-
hash = JSON.parse(body)
|
52
|
-
rescue JSON::ParserError, TypeError
|
53
|
-
hash = {}
|
54
|
-
end
|
55
|
-
|
56
|
-
else
|
57
|
-
# We assume that text looks like STOMP headers, or nothing
|
58
|
-
hash = {}
|
59
|
-
body.to_s.split("\n").each do |line|
|
60
|
-
k,v = line.split(':', 2).each{|x| x.strip! }
|
61
|
-
hash[k] = v
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
hash
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
25
|
##
|
71
26
|
# :call-seq:
|
72
27
|
# StompHandler.with_timeout(secs) -> (nil)
|
@@ -79,17 +34,16 @@ module NebulousStomp
|
|
79
34
|
# r.signal
|
80
35
|
# end
|
81
36
|
#
|
82
|
-
# Use `r.signal` to signal when the process has finished. You need to
|
83
|
-
#
|
37
|
+
# Use `r.signal` to signal when the process has finished. You need to arrange your own method
|
38
|
+
# of working out whether the timeout fired or not.
|
84
39
|
#
|
85
|
-
# Also, please note that when the timeout period expires, your code will
|
86
|
-
#
|
87
|
-
#
|
88
|
-
# for anything else...
|
40
|
+
# Also, please note that when the timeout period expires, your code will keep running. The
|
41
|
+
# timeout will only be honoured when your block completes. This is very useful for
|
42
|
+
# Stomp.subscribe, but probably not for anything else...
|
89
43
|
#
|
90
|
-
# There is a Ruby standard library for this, Timeout. But there appears to
|
91
|
-
#
|
92
|
-
#
|
44
|
+
# There is a Ruby standard library for this, Timeout. But there appears to be some argument
|
45
|
+
# as to whether it is threadsafe; so, we roll our own. It probably doesn't matter since both
|
46
|
+
# Redis and Stomp do use Timeout. But.
|
93
47
|
#
|
94
48
|
def with_timeout(secs)
|
95
49
|
mutex = Mutex.new
|
@@ -98,7 +52,6 @@ module NebulousStomp
|
|
98
52
|
t = Thread.new do
|
99
53
|
mutex.synchronize { yield resource }
|
100
54
|
end
|
101
|
-
|
102
55
|
mutex.synchronize { resource.wait(mutex, secs) }
|
103
56
|
|
104
57
|
nil
|
@@ -111,18 +64,12 @@ module NebulousStomp
|
|
111
64
|
##
|
112
65
|
# Initialise StompHandler by passing the parameter hash.
|
113
66
|
#
|
114
|
-
# If no hash is set we try and get it from NebulousStomp::Param.
|
115
|
-
# ONLY set testClient when testing.
|
116
|
-
#
|
117
67
|
def initialize(connectHash=nil, testClient=nil)
|
118
|
-
@stomp_hash
|
119
|
-
@stomp_hash ||= Param.get(:stompConnectHash)
|
120
|
-
|
68
|
+
@stomp_hash = connectHash ? connectHash.dup : nil
|
121
69
|
@test_client = testClient
|
122
70
|
@client = nil
|
123
71
|
end
|
124
72
|
|
125
|
-
|
126
73
|
##
|
127
74
|
# Connect to the STOMP client.
|
128
75
|
#
|
@@ -131,20 +78,18 @@ module NebulousStomp
|
|
131
78
|
NebulousStomp.logger.info(__FILE__) {"Connecting to STOMP"}
|
132
79
|
|
133
80
|
@client = @test_client || Stomp::Client.new( @stomp_hash )
|
134
|
-
|
81
|
+
fail ConnectionError, "Stomp Connection failed" unless connected?
|
135
82
|
|
136
83
|
conn = @client.connection_frame()
|
137
84
|
if conn.command == Stomp::CMD_ERROR
|
138
|
-
|
85
|
+
fail ConnectionError, "Connect Error: #{conn.body}"
|
139
86
|
end
|
140
87
|
|
141
88
|
self
|
142
|
-
|
143
89
|
rescue => err
|
144
90
|
raise ConnectionError, err
|
145
91
|
end
|
146
92
|
|
147
|
-
|
148
93
|
##
|
149
94
|
# Drop the connection to the STOMP Client
|
150
95
|
#
|
@@ -158,7 +103,6 @@ module NebulousStomp
|
|
158
103
|
self
|
159
104
|
end
|
160
105
|
|
161
|
-
|
162
106
|
##
|
163
107
|
# return true if we are connected to the STOMP server
|
164
108
|
#
|
@@ -166,7 +110,6 @@ module NebulousStomp
|
|
166
110
|
@client && @client.open?
|
167
111
|
end
|
168
112
|
|
169
|
-
|
170
113
|
##
|
171
114
|
# return true if Nebulous is turned on in the parameters
|
172
115
|
#
|
@@ -174,17 +117,19 @@ module NebulousStomp
|
|
174
117
|
@stomp_hash && !@stomp_hash.empty?
|
175
118
|
end
|
176
119
|
|
177
|
-
|
178
120
|
##
|
179
121
|
# Block for incoming messages on a queue. Yield each message.
|
180
122
|
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
123
|
+
# This method automatically consumes every message it reads, since the assumption is that we
|
124
|
+
# are using it for the request-response use case. If you don't want that, try
|
125
|
+
# listen_with_timeout(), instead.
|
126
|
+
#
|
127
|
+
# Note that the blocking happens in a thread somewhere inside the STOMP client. I have no idea
|
128
|
+
# how to join that, and if the examples on the STOMP gem are to be believed, you flat out can't
|
129
|
+
# -- the examples just have the main thread sleeping so that it does not termimate while the
|
130
|
+
# thread is running. So to use this make sure that you at some point do something
|
186
131
|
# like:
|
187
|
-
# loop
|
132
|
+
# loop { sleep 5 }
|
188
133
|
#
|
189
134
|
def listen(queue)
|
190
135
|
return unless nebulous_on?
|
@@ -207,10 +152,9 @@ module NebulousStomp
|
|
207
152
|
|
208
153
|
end
|
209
154
|
|
210
|
-
|
211
155
|
##
|
212
|
-
# As listen() but give up after yielding a single message, and only wait
|
213
|
-
#
|
156
|
+
# As listen() but give up after yielding a single message, and only wait for a set number of
|
157
|
+
# seconds before giving up anyway.
|
214
158
|
#
|
215
159
|
# The behaviour here is slightly different than listen(). If you return true from your block,
|
216
160
|
# the message will be consumed and the method will end. Otherwise it will continue until it
|
@@ -221,15 +165,10 @@ module NebulousStomp
|
|
221
165
|
#
|
222
166
|
def listen_with_timeout(queue, timeout)
|
223
167
|
return unless nebulous_on?
|
224
|
-
|
225
|
-
NebulousStomp.logger.info(__FILE__) do
|
226
|
-
"Subscribing to #{queue} with timeout #{timeout}"
|
227
|
-
end
|
168
|
+
NebulousStomp.logger.info(__FILE__) { "Subscribing to #{queue} with timeout #{timeout}" }
|
228
169
|
|
229
170
|
stomp_connect unless @client
|
230
|
-
|
231
171
|
@client.publish( queue, "boo" )
|
232
|
-
|
233
172
|
done = false
|
234
173
|
|
235
174
|
StompHandler.with_timeout(timeout) do |resource|
|
@@ -258,16 +197,15 @@ module NebulousStomp
|
|
258
197
|
resource.signal if done #or here. either, but.
|
259
198
|
end # of with_timeout
|
260
199
|
|
261
|
-
|
200
|
+
fail NebulousTimeout unless done
|
262
201
|
end
|
263
202
|
|
264
|
-
|
265
203
|
##
|
266
204
|
# Send a Message to a queue; return the message.
|
267
205
|
#
|
268
206
|
def send_message(queue, mess)
|
269
207
|
return nil unless nebulous_on?
|
270
|
-
|
208
|
+
fail NebulousStomp::NebulousError, "That's not a Message" \
|
271
209
|
unless mess.respond_to?(:body_for_stomp) \
|
272
210
|
&& mess.respond_to?(:headers_for_stomp)
|
273
211
|
|
@@ -275,17 +213,15 @@ module NebulousStomp
|
|
275
213
|
|
276
214
|
headers = mess.headers_for_stomp.reject{|k,v| v.nil? || v == "" }
|
277
215
|
@client.publish(queue, mess.body_for_stomp, headers)
|
278
|
-
|
279
216
|
mess
|
280
217
|
end
|
281
218
|
|
282
|
-
|
283
219
|
##
|
284
220
|
# Return the neb-reply-id we're going to use for this connection
|
285
221
|
#
|
286
222
|
def calc_reply_id
|
287
223
|
return nil unless nebulous_on?
|
288
|
-
|
224
|
+
fail ConnectionError, "Client not connected" unless @client
|
289
225
|
|
290
226
|
@client.connection_frame().headers["session"] \
|
291
227
|
<< "_" \
|
@@ -293,9 +229,7 @@ module NebulousStomp
|
|
293
229
|
|
294
230
|
end
|
295
231
|
|
296
|
-
|
297
|
-
end
|
298
|
-
##
|
232
|
+
end # StompHandler
|
299
233
|
|
300
234
|
|
301
235
|
end
|
@@ -10,85 +10,71 @@ module NebulousStomp
|
|
10
10
|
|
11
11
|
|
12
12
|
##
|
13
|
-
# Behaves just like StompHandler, except, does nothing and expects no stomp
|
14
|
-
# connection
|
13
|
+
# Behaves just like StompHandler, except, does nothing and expects no stomp connection
|
15
14
|
#
|
16
15
|
class StompHandlerNull < StompHandler
|
17
16
|
|
18
|
-
attr_reader :
|
19
|
-
|
17
|
+
attr_reader :fake_messages
|
20
18
|
|
21
19
|
def initialize(hash={})
|
22
20
|
super(hash)
|
23
|
-
@
|
21
|
+
@fake_messages = []
|
24
22
|
end
|
25
23
|
|
26
|
-
|
27
24
|
def insert_fake(message)
|
28
|
-
@
|
25
|
+
@fake_messages << message
|
29
26
|
end
|
30
27
|
|
31
|
-
|
32
28
|
def stomp_connect
|
33
29
|
NebulousStomp.logger.info(__FILE__) {"Connecting to STOMP (Null)"}
|
34
|
-
|
35
30
|
@client = true
|
36
31
|
self
|
37
32
|
end
|
38
33
|
|
39
|
-
|
40
34
|
def stomp_disconnect
|
41
35
|
NebulousStomp.logger.info(__FILE__) {"STOMP Disconnect (Null)"}
|
42
36
|
@client = nil
|
43
37
|
self
|
44
38
|
end
|
45
|
-
|
46
39
|
|
47
40
|
def connected?
|
48
|
-
@
|
41
|
+
@fake_messages != []
|
49
42
|
end
|
50
43
|
|
51
|
-
|
52
44
|
def listen(queue)
|
53
45
|
NebulousStomp.logger.info(__FILE__) {"Subscribing to #{queue} (on Null)"}
|
54
|
-
yield
|
46
|
+
@fake_messages.each{|m| yield m }
|
55
47
|
end
|
56
48
|
|
57
|
-
|
58
49
|
def listen_with_timeout(queue, timeout)
|
59
50
|
NebulousStomp.logger.info(__FILE__) {"Subscribing to #{queue} (on Null)"}
|
60
51
|
|
61
|
-
if @
|
62
|
-
yield
|
52
|
+
if @fake_messages != []
|
53
|
+
@fake_messages.each{|m| yield m }
|
63
54
|
else
|
64
55
|
sleep timeout
|
65
56
|
raise NebulousStomp::NebulousTimeout
|
66
57
|
end
|
67
58
|
end
|
68
59
|
|
69
|
-
|
70
60
|
def send_message(queue, nebMess)
|
71
61
|
nebMess
|
72
62
|
end
|
73
63
|
|
74
|
-
|
75
64
|
def respond_success(nebMess)
|
76
65
|
NebulousStomp.logger.info(__FILE__) do
|
77
66
|
"Responded to #{nebMess} with 'success' verb (to Null)"
|
78
67
|
end
|
79
68
|
end
|
80
69
|
|
81
|
-
|
82
70
|
def respond_error(nebMess,err,fields=[])
|
83
71
|
NebulousStomp.logger.info(__FILE__) do
|
84
72
|
"Responded to #{nebMess} with 'error' verb: #{err} (to Null)"
|
85
73
|
end
|
86
74
|
end
|
87
75
|
|
88
|
-
|
89
76
|
def calc_reply_id; 'ABCD123456789'; end
|
90
77
|
|
91
|
-
|
92
78
|
end
|
93
79
|
|
94
80
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module NebulousStomp
|
2
|
+
|
3
|
+
|
4
|
+
##
|
5
|
+
# Represents a single Target. Read only.
|
6
|
+
#
|
7
|
+
# NebulousStomp.add_target returns a Target, or you can retreive one from the config using
|
8
|
+
# NebulousStomp.get_target.
|
9
|
+
#
|
10
|
+
class Target
|
11
|
+
#
|
12
|
+
# The identifying name of the queue
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
# The queue that the target sends responses to
|
16
|
+
attr_reader :send_queue
|
17
|
+
|
18
|
+
# The queue that the target listens for requests on
|
19
|
+
attr_reader :receive_queue
|
20
|
+
|
21
|
+
# The message timeout for the queue
|
22
|
+
attr_reader :message_timeout
|
23
|
+
|
24
|
+
VALID_KEYS = %i|sendQueue receiveQueue messageTimeout name|
|
25
|
+
|
26
|
+
##
|
27
|
+
# Create a target.
|
28
|
+
#
|
29
|
+
# Valid keys for the hash:
|
30
|
+
#
|
31
|
+
# * :sendQueue
|
32
|
+
# * :receiveQeue
|
33
|
+
# * :name
|
34
|
+
# * :messageTimeout (optional)
|
35
|
+
#
|
36
|
+
def initialize(hash)
|
37
|
+
fail ArgumentError, "Argument for Target.new must be a hash" unless hash.is_a? Hash
|
38
|
+
|
39
|
+
@send_queue = hash[:sendQueue] or fail ArgumentError, "Missing a sendQueue"
|
40
|
+
@receive_queue = hash[:receiveQueue] or fail ArgumentError, "Missing a receiveQueue"
|
41
|
+
@name = hash[:name] or fail ArgumentError, "Missing a name"
|
42
|
+
@message_timeout = hash[:messageTimeout]
|
43
|
+
|
44
|
+
bad_keys = hash.reject{|k, _| VALID_KEYS.include? k }.keys
|
45
|
+
fail ArgumentError, "Bad keys: #{bad_keys.join ' '}" unless bad_keys.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
52
|
+
|