rsmp 0.2.3 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a57d963e9f3f6f4dccdfbfaf7bc2d4c09fcbae56d1ec886ed699faa373e054ed
4
- data.tar.gz: 4035d49f738d335f94d4df8c9dd33a3744d258740e51df55be9da5998ce3e538
3
+ metadata.gz: 9a3b1b8a67bdc7a3c8887ea606d3539d934121d99597f1a77f697d8259daba97
4
+ data.tar.gz: 03f420b48a4eff2f3b6978eed5053a838a87da4f507eb2ddb2f0c15cb0e3e7b4
5
5
  SHA512:
6
- metadata.gz: 94e7df5ad072745c960726053e0630b8b9efefc87c746a0f96afb53c32c4ff7450a553d3576a9ad9cd430640355e8ff329862cb4fd24da8338780e500f3c0245
7
- data.tar.gz: 70b0a93eb41dca5cfabe62cacfb08f675fe2f359886bc4038aa647a95d873553b04056277ee08bac16476c441c7b6f646300179567fe2b33f58aa83121456b37
6
+ metadata.gz: 9fef0b5ea4b2e5481d3be7992e76c7cddb1d20db49df06c86d9b90faa37b56d458fde9cba36e14ea085e96e67f61dbe67f1a82a49401d360cb48900c6138b27d
7
+ data.tar.gz: a14a735fccf39e8584e3d9ab43a1fdb727c279f395c138d9c7c50f7a8d491265c0aeb3aa67ee071642195bd7a15e0339de4785b5230bbed624965ef3619a231e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.2.3)
4
+ rsmp (0.3.0)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.1)
7
7
  colorize (~> 0.8.1)
@@ -1,21 +1,19 @@
1
- # Collects matching ingoing and/or outgoing messages and
2
- # wakes up the client once the desired amount has been collected.
3
- # Can listen for ingoing and/or outgoing messages.
4
-
5
1
  module RSMP
6
- class Collector < Listener
7
2
 
3
+ # Collects ingoing and/or outgoing messages.
4
+ # Can filter by message type and wakes up the client once the desired number of messages has been collected.
5
+ class Collector < Listener
8
6
  attr_reader :condition, :messages, :done
9
7
 
10
8
  def initialize proxy, options={}
11
9
  super proxy, options
10
+ @options = options.clone
12
11
  @ingoing = options[:ingoing] == nil ? true : options[:ingoing]
13
12
  @outgoing = options[:outgoing] == nil ? false : options[:outgoing]
14
- @messages = []
15
13
  @condition = Async::Notification.new
16
- @done = false
17
- @options = options
18
- @num = options[:num]
14
+ @title = options[:title] || [@options[:type]].flatten.join('/')
15
+ @options[:timeout] ||= 1
16
+ reset
19
17
  end
20
18
 
21
19
  def inspect
@@ -34,17 +32,9 @@ module RSMP
34
32
  @condition.wait
35
33
  end
36
34
 
37
- def collect_for task, duration
38
- siphon do
39
- task.sleep duration
40
- end
41
- end
42
-
43
35
  def collect task, options={}, &block
44
- @num = options[:num] if options[:num]
45
- @options[:timeout] = options[:timeout] if options[:timeout]
36
+ @options.merge! options
46
37
  @block = block
47
-
48
38
  unless @done
49
39
  listen do
50
40
  task.with_timeout(@options[:timeout]) do
@@ -52,51 +42,97 @@ module RSMP
52
42
  end
53
43
  end
54
44
  end
45
+ return @error if @error
46
+ self
47
+ rescue Async::TimeoutError
48
+ str = "Did not receive #{@title}"
49
+ str << " in response to #{options[:m_id]}" if options[:m_id]
50
+ str << " within #{@options[:timeout]}s"
51
+ raise RSMP::TimeoutError.new str
52
+ end
55
53
 
56
- if @num == 1
57
- @messages = @messages.first # if one message was requested, return it instead of array
58
- else
59
- @messages = @messages.first @num # return array, but ensure we never return more than requested
60
- end
61
- @messages
54
+ def result
55
+ return @messages.first if @options[:num] == 1 # if one message was requested, return it instead of array
56
+ @messages.first @options[:num] # return array, but ensure we never return more than requested
62
57
  end
63
58
 
64
59
  def reset
65
- @message.clear
60
+ @messages = []
61
+ @error = nil
66
62
  @done = false
67
63
  end
68
64
 
65
+ # Check for MessageNotAck
66
+ # If the original request identified by @m_id is rejected, set the result to an exception,
67
+ # which will be returned by the async task and stored as the task result.
68
+ # When the parent task call wait() on the task, the exception will be raised in the parent task.
69
+ def check_not_ack message
70
+ return unless @options[:m_id]
71
+ if message.is_a?(MessageNotAck)
72
+ if message.attribute('oMId') == @options[:m_id]
73
+ m_id_short = RSMP::Message.shorten_m_id @options[:m_id], 8
74
+ @error = RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected: #{message.attribute('rea')}")
75
+ complete
76
+ end
77
+ false
78
+ end
79
+ end
80
+
81
+ # Handle message. and return true when we're done collecting
69
82
  def notify message
70
83
  raise ArgumentError unless message
84
+ check_not_ack(message)
71
85
  return true if @done
72
- return if message.direction == :in && @ingoing == false
73
- return if message.direction == :out && @outgoing == false
74
- if matches? message
75
- @messages << message
76
- if @num && @messages.size >= @num
77
- @done = true
78
- @proxy.remove_listener self
79
- @condition.signal
80
- end
86
+ check_match message
87
+ complete if done?
88
+ @done
89
+ end
90
+
91
+ # Match message against our collection criteria
92
+ def check_match message
93
+ matched = match? message
94
+ if matched == true
95
+ keep message
96
+ elsif matched == false
97
+ forget message
81
98
  end
82
99
  end
83
100
 
84
- def matches? message
85
- raise ArgumentError unless message
101
+ def done?
102
+ @options[:num] && @messages.size >= @options[:num]
103
+ end
104
+
105
+ def complete
106
+ @done = true
107
+ @proxy.remove_listener self
108
+ @condition.signal
109
+ end
110
+
111
+ def keep message
112
+ @messages << message
113
+ end
114
+
115
+ def forget message
116
+ @messages.delete message
117
+ end
86
118
 
119
+ def match? message
120
+ raise ArgumentError unless message
121
+ return if message.direction == :in && @ingoing == false
122
+ return if message.direction == :out && @outgoing == false
87
123
  if @options[:type]
88
- return false if message == nil
124
+ return if message == nil
89
125
  if @options[:type].is_a? Array
90
- return false unless @options[:type].include? message.type
126
+ return unless @options[:type].include? message.type
91
127
  else
92
- return false unless message.type == @options[:type]
128
+ return unless message.type == @options[:type]
93
129
  end
94
130
  end
95
131
  if @options[:component]
96
- return false if message.attributes['cId'] && message.attributes['cId'] != @options[:component]
132
+ return if message.attributes['cId'] && message.attributes['cId'] != @options[:component]
97
133
  end
98
134
  if @block
99
- return false if @block.call(message) == false
135
+ return if @block.call(message) == false
100
136
  end
101
137
  true
102
138
  end
@@ -0,0 +1,183 @@
1
+ module RSMP
2
+
3
+ # Base class for waiting for specific status or command responses, specified by
4
+ # a list of queries. Queries are defined as an array of hashes, e.g
5
+ # [
6
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"securityCode", "v"=>"1111"},
7
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"year", "v"=>"2020"},
8
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/}
9
+ # ]
10
+ #
11
+ # Note that queries can contain regex patterns for values, like /\d+/ in the example above.
12
+ #
13
+ # When an input messages is received it typically contains several items, eg:
14
+ # [
15
+ # {"cCI"=>"M0104", "n"=>"month", "v"=>"9", "age"=>"recent"},
16
+ # {"cCI"=>"M0104", "n"=>"day", "v"=>"29", "age"=>"recent"},
17
+ # {"cCI"=>"M0104", "n"=>"hour", "v"=>"17", "age"=>"recent"}
18
+ # ]
19
+ #
20
+ # Each input item is matched against each of the queries.
21
+ # If a match is found, it's stored in the @results hash, with the query as the key,
22
+ # and a mesage and status as the key. In the example above, this query:
23
+ #
24
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/}
25
+ #
26
+ # matches this input:
27
+ #
28
+ # {"cCI"=>"M0104", "n"=>"month", "v"=>"9", "age"=>"recent"}
29
+ #
30
+ # And the result is stored as:
31
+ # {
32
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/} =>
33
+ # { <StatusResponse message>, {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>"9"} }
34
+ # }
35
+ #
36
+ #
37
+ class Matcher < Collector
38
+
39
+ # Initialize with a list a wanted statuses
40
+ def initialize proxy, want, options={}
41
+ super proxy, options.merge( ingoing: true, outgoing: false)
42
+ @queries = {}
43
+ want.each do |query|
44
+ @queries[query] = nil
45
+ end
46
+ end
47
+
48
+ # Get the results, as a hash of queries => results
49
+ def result
50
+ @queries
51
+ end
52
+
53
+ # Get messages from results
54
+ def messages
55
+ @queries.map { |query,result| result[:message] }.uniq
56
+ end
57
+
58
+ # get items from results
59
+ def items
60
+ @queries.map { |query,result| result[:item] }.uniq
61
+ end
62
+
63
+ # Queries left to match?
64
+ def done?
65
+ @queries.values.all? { |result| result != nil }
66
+ end
67
+
68
+ # Mark a query as matched, by linking it to the matched item and message
69
+ def keep query, message, item
70
+ @queries[query] = { message:message, item:item }
71
+ end
72
+
73
+ # Mark a query as not matched
74
+ def forget query
75
+ @queries[query] = nil
76
+ end
77
+
78
+ # Check if a messages is wanted.
79
+ # Returns true when we found all that we want.
80
+ def check_match message
81
+ return unless match?(message)
82
+ @queries.keys.each do |query| # look through queries
83
+ get_items(message).each do |item| # look through status items in message
84
+ break if check_item_match message, query, item
85
+ end
86
+ end
87
+ end
88
+
89
+ # Check if an item matches, and mark query as matched/unmatched accordingly.
90
+ def check_item_match message, query, item
91
+ matched = match_item? query, item
92
+ if matched == true
93
+ keep query, message, item
94
+ true
95
+ elsif matched == false
96
+ forget query
97
+ true
98
+ end
99
+ end
100
+ end
101
+
102
+ # Class for waiting for specific command responses
103
+ class CommandResponseMatcher < Matcher
104
+ def initialize proxy, want, options={}
105
+ super proxy, want, options.merge(
106
+ type: ['CommandResponse','MessageNotAck'],
107
+ title:'command request'
108
+ )
109
+ end
110
+
111
+ def get_items message
112
+ message.attributes['rvs']
113
+ end
114
+
115
+ # Match an item against a query
116
+ def match_item? query, item
117
+ return nil if query['cCI'] && query['cCI'] != item['cCI']
118
+ return nil if query['n'] && query['n'] != item['n']
119
+ if query['v'].is_a? Regexp
120
+ return false if query['v'] && item['v'] !~ query['v']
121
+ else
122
+ return false if query['v'] && item['v'] != query['v']
123
+ end
124
+ true
125
+ end
126
+ end
127
+
128
+ # Base class for waiting for status updates or responses
129
+ class StatusUpdateOrResponseMatcher < Matcher
130
+ def initialize proxy, want, options={}
131
+ super proxy, want, options.merge
132
+ end
133
+
134
+ def get_items message
135
+ message.attributes['sS']
136
+ end
137
+
138
+ # Match an item against a query
139
+ def match_item? query, item
140
+ return nil if query['sCI'] && query['sCI'] != item['sCI']
141
+ return nil if query['cO'] && query['cO'] != item['cO']
142
+ return nil if query['n'] && query['n'] != item['n']
143
+ return false if query['q'] && query['q'] != item['q']
144
+ if query['s'].is_a? Regexp
145
+ return false if query['s'] && item['s'] !~ query['s']
146
+ else
147
+ return false if query['s'] && item['s'] != query['s']
148
+ end
149
+ true
150
+ end
151
+ end
152
+
153
+ # Class for waiting for specific status responses
154
+ class StatusResponseMatcher < StatusUpdateOrResponseMatcher
155
+ def initialize proxy, want, options={}
156
+ super proxy, want, options.merge(
157
+ type: ['StatusResponse','MessageNotAck'],
158
+ title: 'status request'
159
+ )
160
+ end
161
+ end
162
+
163
+ # Class for waiting for specific status responses
164
+ class StatusUpdateMatcher < StatusUpdateOrResponseMatcher
165
+ def initialize proxy, want, options={}
166
+ super proxy, want, options.merge(
167
+ type: ['StatusUpdate','MessageNotAck'],
168
+ title:'status subscription'
169
+ )
170
+ end
171
+ end
172
+
173
+ # Class for waiting for an aggregated status response
174
+ class AggregatedStatusMatcher < Collector
175
+ def initialize proxy, options={}
176
+ super proxy, options.merge(
177
+ num: 1,
178
+ type: ['AggregatedStatus','MessageNotAck'],
179
+ title: 'aggregated status request'
180
+ )
181
+ end
182
+ end
183
+ end
data/lib/rsmp/proxy.rb CHANGED
@@ -59,6 +59,7 @@ module RSMP
59
59
  def collect task, options, &block
60
60
  collector = RSMP::Collector.new self, options
61
61
  collector.collect task, &block
62
+ collector
62
63
  end
63
64
 
64
65
  def run
@@ -3,7 +3,6 @@
3
3
  module RSMP
4
4
  class SiteProxy < Proxy
5
5
  include Components
6
- include SiteProxyWait
7
6
 
8
7
  attr_reader :supervisor, :site_id
9
8
 
@@ -43,7 +42,7 @@ module RSMP
43
42
 
44
43
  def connection_complete
45
44
  super
46
- sanitized_sxl_version = RSMP::Schemer.sanitize_version(@site_sxl_version)
45
+ sanitized_sxl_version = RSMP::Schemer.sanitize_version(@site_sxl_version)
47
46
  log "Connection to site #{@site_id} established, using core #{@rsmp_version}, #{@sxl} #{sanitized_sxl_version}", level: :info
48
47
  end
49
48
 
@@ -86,7 +85,6 @@ module RSMP
86
85
  acknowledge message
87
86
  send_version @site_id, rsmp_versions
88
87
  @version_determined = true
89
-
90
88
  end
91
89
 
92
90
  def validate_ready action
@@ -104,9 +102,8 @@ module RSMP
104
102
  "mId" => m_id
105
103
  })
106
104
  if options[:collect]
107
- result = nil
108
105
  task = @task.async do |task|
109
- wait_for_aggregated_status task, options[:collect], m_id
106
+ wait_for_aggregated_status task, options[:collect].merge(m_id: m_id)
110
107
  end
111
108
  send_message message, validate: options[:validate]
112
109
  return message, task.wait
@@ -178,7 +175,7 @@ module RSMP
178
175
  m_id = options[:m_id] || RSMP::Message.make_m_id
179
176
 
180
177
  # additional items can be used when verifying the response,
181
- # but must to remove from the request
178
+ # but must be removed from the request
182
179
  request_list = status_list.map { |item| item.slice('sCI','n') }
183
180
 
184
181
  message = RSMP::StatusRequest.new({
@@ -188,23 +185,8 @@ module RSMP
188
185
  "sS" => request_list,
189
186
  "mId" => m_id
190
187
  })
191
- if options[:collect]
192
- result = nil
193
- task = @task.async do |task|
194
- collect_options = options[:collect].merge status_list: status_list
195
- collect_status_responses task, collect_options, m_id
196
- end
197
- send_message message, validate: options[:validate]
198
-
199
- # task.wait return the result of the task. if the task raised an exception
200
- # it will be reraised. but that mechanish does not work if multiple values
201
- # are returned. so manually raise if first element is an exception
202
- result = task.wait
203
- raise result.first if result.first.is_a? Exception
204
- return message, *result
205
- else
206
- send_message message, validate: options[:validate]
207
- message
188
+ send_while_collecting message, options do |task|
189
+ collect_status_responses task, status_list, options[:collect].merge(m_id: m_id)
208
190
  end
209
191
  end
210
192
 
@@ -213,6 +195,13 @@ module RSMP
213
195
  acknowledge message
214
196
  end
215
197
 
198
+ def send_while_collecting message, options, &block
199
+ task = @task.async { |task| yield task } if options[:collect]
200
+ send_message message, validate: options[:validate]
201
+ return message, task.wait if task
202
+ message
203
+ end
204
+
216
205
  def subscribe_to_status component, status_list, options={}
217
206
  validate_ready 'subscribe to status'
218
207
  m_id = options[:m_id] || RSMP::Message.make_m_id
@@ -228,23 +217,8 @@ module RSMP
228
217
  "sS" => subscribe_list,
229
218
  'mId' => m_id
230
219
  })
231
- if options[:collect]
232
- result = nil
233
- task = @task.async do |task|
234
- collect_options = options[:collect].merge status_list: status_list
235
- collect_status_updates task, collect_options, m_id
236
- end
237
- send_message message, validate: options[:validate]
238
-
239
- # task.wait return the result of the task. if the task raised an exception
240
- # it will be reraised. but that mechanish does not work if multiple values
241
- # are returned. so manually raise if first element is an exception
242
- result = task.wait
243
- raise result.first if result.first.is_a? Exception
244
- return message, *result
245
- else
246
- send_message message, validate: options[:validate]
247
- message
220
+ send_while_collecting message, options do |task|
221
+ collect_status_updates task, status_list, options[:collect].merge(m_id: m_id)
248
222
  end
249
223
  end
250
224
 
@@ -289,23 +263,8 @@ module RSMP
289
263
  "arg" => command_list,
290
264
  "mId" => m_id
291
265
  })
292
- if options[:collect]
293
- result = nil
294
- task = @task.async do |task|
295
- collect_options = options[:collect].merge command_list: command_list
296
- collect_command_responses task, collect_options, m_id
297
- end
298
- send_message message, validate: options[:validate]
299
-
300
- # task.wait return the result of the task. if the task raised an exception
301
- # it will be reraised. but that mechanish does not work if multiple values
302
- # are returned. so manually raise if first element is an exception
303
- result = task.wait
304
- raise result.first if result.first.is_a? Exception
305
- return message, *result
306
- else
307
- send_message message, validate: options[:validate]
308
- message
266
+ send_while_collecting message, options do |task|
267
+ collect_command_responses task, command_list, options[:collect].merge(m_id: m_id)
309
268
  end
310
269
  end
311
270
 
@@ -381,5 +340,37 @@ module RSMP
381
340
  @supervisor.notify_error e, options if @supervisor
382
341
  end
383
342
 
343
+ def wait_for_alarm parent_task, options={}
344
+ matching_alarm = nil
345
+ message = collect(parent_task,options.merge(type: "Alarm", with_message: true, num: 1)) do |message|
346
+ # TODO check components
347
+ matching_alarm = nil
348
+ alarm = message
349
+ next if options[:aCId] && options[:aCId] != alarm.attribute("aCId")
350
+ next if options[:aSp] && options[:aSp] != alarm.attribute("aSp")
351
+ next if options[:aS] && options[:aS] != alarm.attribute("aS")
352
+ matching_alarm = alarm
353
+ break
354
+ end
355
+ if item
356
+ { message: message, status: matching_alarm }
357
+ end
358
+ end
359
+
360
+ def collect_status_updates task, status_list, options
361
+ StatusUpdateMatcher.new(self, status_list, options).collect task
362
+ end
363
+
364
+ def collect_status_responses task, status_list, options
365
+ StatusResponseMatcher.new(self, status_list, options).collect task
366
+ end
367
+
368
+ def collect_command_responses task, command_list, options
369
+ CommandResponseMatcher.new(self, command_list, options).collect task
370
+ end
371
+
372
+ def wait_for_aggregated_status task, options
373
+ AggregatedStatusMatcher.new(self, options).collect task
374
+ end
384
375
  end
385
376
  end
@@ -1,184 +0,0 @@
1
- # waiting for various types of messages and reponses from remote sites
2
- module RSMP
3
- module SiteProxyWait
4
-
5
- class Matcher
6
- attr_reader :result, :messages
7
-
8
- # Initialize with a list a wanted statuses
9
- def initialize want, options={}
10
- @want = want.clone
11
- @result = {}
12
- @messages = []
13
- @m_id = options[:m_id]
14
- end
15
-
16
- # Check if a messages is wanted.
17
- # Returns true when we found all that we want.
18
- def process message
19
- ack_status = check_not_ack message
20
- return ack_status if ack_status != nil
21
-
22
- add = false
23
- @want.each_with_index do |query,i| # look through wanted
24
- get_items(message).each do |input| # look through status items in message
25
- matching = match? query, input
26
- if matching == true
27
- @result[query] = input
28
- add = true
29
- elsif matching == false
30
- @result.delete query
31
- end
32
- end
33
- end
34
- @messages << message if add
35
- @result.size == @want.size # queries left to match?
36
- end
37
-
38
- # Check for MessageNotAck
39
- # If the original request identified by @m_id is rejected, we abort
40
- def check_not_ack message
41
- if message.is_a?(MessageNotAck)
42
- if message.attribute('oMId') == @m_id
43
- # Set result to an exception, but don't raise it.
44
- # This will be returned by the async task and stored as the task result
45
- # When the parent task call wait() on the task, the exception
46
- # will be raised in the parent task, and caught by RSpec.
47
- # RSpec will then show the error and record the test as failed
48
- m_id_short = RSMP::Message.shorten_m_id @m_id, 8
49
- @result = RSMP::MessageRejected.new("#{type_str} #{m_id_short} was rejected: #{message.attribute('rea')}")
50
- @messages = [message]
51
- return true
52
- end
53
- return false
54
- end
55
- end
56
- end
57
-
58
- class CommandResponseMatcher < RSMP::SiteProxyWait::Matcher
59
- def initialize want, options={}
60
- super
61
- end
62
-
63
- def type_str
64
- "Command request"
65
- end
66
-
67
- def get_items message
68
- message.attributes['rvs']
69
- end
70
-
71
- def match? query, item
72
- return nil if query['cCI'] && query['cCI'] != item['cCI']
73
- return nil if query['n'] && query['n'] != item['n']
74
- if query['v'].is_a? Regexp
75
- return false if query['v'] && item['v'] !~ query['v']
76
- else
77
- return false if query['v'] && item['v'] != query['v']
78
- end
79
- true
80
- end
81
- end
82
-
83
- # Class for matching incoming messaging against a list of wanted statuses,
84
- # and flagging when everything has been matched.
85
- class StatusResponseMatcher < RSMP::SiteProxyWait::Matcher
86
- def initialize want, options={}
87
- super
88
- end
89
-
90
- def type_str
91
- "Status request"
92
- end
93
-
94
- def get_items message
95
- message.attributes['sS']
96
- end
97
-
98
- # Match an item against a query
99
- def match? query, item
100
- return nil if query['sCI'] && query['sCI'] != item['sCI']
101
- return nil if query['n'] && query['n'] != item['n']
102
- return false if query['q'] && query['q'] != item['q']
103
- if query['s'].is_a? Regexp
104
- return false if query['s'] && item['s'] !~ query['s']
105
- else
106
- return false if query['s'] && item['s'] != query['s']
107
- end
108
- true
109
- end
110
- end
111
-
112
- def wait_for_alarm parent_task, options={}
113
- matching_alarm = nil
114
- message = collect(parent_task,options.merge(type: "Alarm", with_message: true, num: 1)) do |message|
115
- # TODO check components
116
- matching_alarm = nil
117
- alarm = message
118
- next if options[:aCId] && options[:aCId] != alarm.attribute("aCId")
119
- next if options[:aSp] && options[:aSp] != alarm.attribute("aSp")
120
- next if options[:aS] && options[:aS] != alarm.attribute("aS")
121
- matching_alarm = alarm
122
- break
123
- end
124
- if item
125
- { message: message, status: matching_alarm }
126
- end
127
- end
128
-
129
- def collect_status_updates task, options, m_id
130
- collect_status_updates_or_responses task, 'StatusUpdate', options, m_id
131
- end
132
-
133
- def collect_status_responses task, options, m_id
134
- collect_status_updates_or_responses task, 'StatusResponse', options, m_id
135
- end
136
-
137
- def collect_command_responses parent_task, options, m_id
138
- task.annotate "wait for command response"
139
- matcher = CommandResponseMatcher.new options[:command_list], m_id: m_id
140
- collect(parent_task,options.merge(type: ['CommandResponse','MessageNotAck'], num: 1)) do |message|
141
- matcher.process message # returns true when done (all queries matched)
142
- end
143
- return matcher.result, matcher.messages
144
- rescue Async::TimeoutError
145
- raise RSMP::TimeoutError.new "Did not receive correct command response to #{m_id} within #{options[:timeout]}s"
146
- end
147
-
148
- def collect_status_updates_or_responses task, type, options, m_id
149
- matcher = StatusResponseMatcher.new options[:status_list], m_id: m_id
150
- collect(task,options.merge( type: [type,'MessageNotAck'], num: 1 )) do |message|
151
- matcher.process message # returns true when done (all queries matched)
152
- end
153
- return matcher.result, matcher.messages
154
- rescue Async::TimeoutError
155
- type_str = {'StatusUpdate'=>'update', 'StatusResponse'=>'response'}[type]
156
- raise RSMP::TimeoutError.new "Did not received correct status #{type_str} in reply to #{m_id} within #{options[:timeout]}s"
157
- end
158
-
159
- def wait_for_aggregated_status parent_task, options, m_id
160
- collect(parent_task,options.merge({
161
- type: ['AggregatedStatus','MessageNotAck'],
162
- num: 1
163
- })) do |message|
164
- if message.is_a?(MessageNotAck)
165
- if message.attribute('oMId') == m_id
166
- # set result to an exception, but don't raise it.
167
- # this will be returned by the task and stored as the task result
168
- # when the parent task call wait() on the task, the exception
169
- # will be raised in the parent task, and caught by rspec.
170
- # rspec will then show the error and record the test as failed
171
- m_id_short = RSMP::Message.shorten_m_id m_id, 8
172
- result = RSMP::MessageRejected.new "Aggregated status request #{m_id_short} was rejected: #{message.attribute('rea')}"
173
- next true # done, no more messages wanted
174
- else
175
- false
176
- end
177
- else
178
- true
179
- end
180
- end
181
- end
182
-
183
- end
184
- end
@@ -225,7 +225,12 @@ module RSMP
225
225
  return site if site
226
226
  wait_for(@site_id_condition,timeout) { find_site site_id }
227
227
  rescue Async::TimeoutError
228
- raise RSMP::TimeoutError.new "Site '#{site_id}' did not connect within #{timeout}s"
228
+ if site_id == :any
229
+ str = "No site connected"
230
+ else
231
+ str = "Site '#{site_id}' did not connect"
232
+ end
233
+ raise RSMP::TimeoutError.new "#{str} within #{timeout}s"
229
234
  end
230
235
 
231
236
  def wait_for_site_disconnect site_id, timeout
@@ -129,7 +129,7 @@ module RSMP
129
129
  message = AggregatedStatus.new({
130
130
  "aSTS" => clock.to_s,
131
131
  "cId" => component.c_id,
132
- "fP" => 'NormalControl',
132
+ "fP" => nil,
133
133
  "fS" => nil,
134
134
  "se" => component.aggregated_status_bools,
135
135
  "mId" => m_id,
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/rsmp.rb CHANGED
@@ -21,11 +21,11 @@ require 'rsmp/notifier'
21
21
 
22
22
  require 'rsmp/listener'
23
23
  require 'rsmp/collector'
24
+ require 'rsmp/matcher'
24
25
  require 'rsmp/component'
25
26
  require 'rsmp/site'
26
27
  require 'rsmp/proxy'
27
28
  require 'rsmp/supervisor_proxy'
28
- require 'rsmp/site_proxy_wait'
29
29
  require 'rsmp/site_proxy'
30
30
  require 'rsmp/error'
31
31
  require 'rsmp/message'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsmp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Tin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-08 00:00:00.000000000 Z
11
+ date: 2021-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -217,6 +217,7 @@ files:
217
217
  - lib/rsmp/listener.rb
218
218
  - lib/rsmp/logger.rb
219
219
  - lib/rsmp/logging.rb
220
+ - lib/rsmp/matcher.rb
220
221
  - lib/rsmp/message.rb
221
222
  - lib/rsmp/node.rb
222
223
  - lib/rsmp/notifier.rb