rsmp 0.29.0 → 0.31.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -6
- data/documentation/collecting_message.md +25 -10
- data/documentation/message_distribution.md +8 -8
- data/lib/rsmp/collect/ack_collector.rb +7 -5
- data/lib/rsmp/collect/aggregated_status_collector.rb +4 -2
- data/lib/rsmp/collect/alarm_collector.rb +10 -10
- data/lib/rsmp/collect/{alarm_query.rb → alarm_matcher.rb} +2 -2
- data/lib/rsmp/collect/collector.rb +69 -66
- data/lib/rsmp/collect/{command_query.rb → command_matcher.rb} +2 -2
- data/lib/rsmp/collect/command_response_collector.rb +3 -3
- data/lib/rsmp/collect/distributor.rb +65 -0
- data/lib/rsmp/collect/filter.rb +10 -5
- data/lib/rsmp/collect/{query.rb → matcher.rb} +1 -1
- data/lib/rsmp/collect/queue.rb +39 -0
- data/lib/rsmp/collect/receiver.rb +40 -0
- data/lib/rsmp/collect/state_collector.rb +57 -57
- data/lib/rsmp/collect/status_collector.rb +9 -6
- data/lib/rsmp/collect/{status_query.rb → status_matcher.rb} +2 -2
- data/lib/rsmp/component.rb +4 -0
- data/lib/rsmp/node.rb +1 -1
- data/lib/rsmp/proxy.rb +17 -17
- data/lib/rsmp/site_proxy.rb +4 -4
- data/lib/rsmp/supervisor.rb +4 -4
- data/lib/rsmp/supervisor_proxy.rb +2 -1
- data/lib/rsmp/tlc/signal_priority.rb +19 -3
- data/lib/rsmp/tlc/traffic_controller.rb +28 -14
- data/lib/rsmp/tlc/traffic_controller_site.rb +1 -1
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +7 -6
- metadata +9 -8
- data/lib/rsmp/collect/listener.rb +0 -23
- data/lib/rsmp/collect/notifier.rb +0 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd4daeeb9fb712ab275d4b0711a6ea69e766124a2fcd55ea955eeb1c46f05ed3
|
4
|
+
data.tar.gz: a47c38c49b46fb2ad412ced388f6e654653292dd439ea31d2bbaf33988f024f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec4a4057b53a27d12e1c81af4623b03bcd7cf93b39bad72f1d228c1a0dfd74495541abae496a3fa783c159a16df2e161eb0f5fbaa13d96daa8d8c99a847a0f9f
|
7
|
+
data.tar.gz: 704c11a6d854a0fb48f9cb6d84514ac40791bb85fe56186b9ff217e876458be6a214fbb69b8c3aaf09db35bd334345f7ca6ee31da8f9fbf717a3ae790e77252a
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rsmp (0.
|
4
|
+
rsmp (0.31.0)
|
5
5
|
async (~> 2.12.0)
|
6
6
|
async-io (~> 1.43.0)
|
7
7
|
colorize (~> 1.1)
|
@@ -16,16 +16,16 @@ GEM
|
|
16
16
|
cucumber (>= 8.0, < 10.0)
|
17
17
|
rspec-expectations (~> 3.4)
|
18
18
|
thor (~> 1.0)
|
19
|
-
async (2.12.
|
19
|
+
async (2.12.1)
|
20
20
|
console (~> 1.25, >= 1.25.2)
|
21
21
|
fiber-annotation
|
22
|
-
io-event (~> 1.6)
|
22
|
+
io-event (~> 1.6, >= 1.6.5)
|
23
23
|
async-io (1.43.2)
|
24
24
|
async
|
25
25
|
bigdecimal (3.1.8)
|
26
26
|
builder (3.3.0)
|
27
27
|
colorize (1.1.0)
|
28
|
-
console (1.
|
28
|
+
console (1.27.0)
|
29
29
|
fiber-annotation
|
30
30
|
fiber-local (~> 1.1)
|
31
31
|
json
|
@@ -64,9 +64,9 @@ GEM
|
|
64
64
|
fiber-annotation (0.2.0)
|
65
65
|
fiber-local (1.1.0)
|
66
66
|
fiber-storage
|
67
|
-
fiber-storage (0.
|
67
|
+
fiber-storage (1.0.0)
|
68
68
|
hana (1.3.7)
|
69
|
-
io-event (1.6.
|
69
|
+
io-event (1.6.5)
|
70
70
|
json (2.7.2)
|
71
71
|
json_schemer (2.3.0)
|
72
72
|
bigdecimal
|
@@ -3,30 +3,45 @@ You often need to collect messages or responses. The collector classes are used
|
|
3
3
|
|
4
4
|
A collector can collect ingoing and/or outgoing messages.
|
5
5
|
|
6
|
-
An object that includes the
|
6
|
+
An object that includes the Distributor module (or implements the same functionality) must be provided when you construct a Collected. The collector will attach itself to this distributor when it starts collecting, to receive messages. The SiteProxy and SupervisorProxy classes both include the Distributor module, and can therefore be used as message sources.
|
7
7
|
|
8
8
|
Messages that match the relevant criteria are stored by the collector.
|
9
9
|
|
10
|
-
When the collection is done, the collector detaches from the
|
10
|
+
When the collection is done, the collector detaches from the distributor, and returns the status.
|
11
11
|
|
12
12
|
|
13
13
|
## Collector
|
14
|
-
Class
|
14
|
+
Class used for collecting messages filtered by message type, direction and/or component id. A block can be used for custom filtering.
|
15
15
|
|
16
16
|
You can choose to collect a specific number of message and/or for a specific duration.
|
17
17
|
|
18
18
|
A collector has a status, which is `:ready` initialialy. When you start collecting, it changes to `:collecting`. It will be `:ok` once collection completes successfully, or `:cancel` if it was cancelled to to some error or by a filter block.
|
19
19
|
|
20
20
|
### Initialization
|
21
|
-
When you create a collector, you specify the messages types you want to collect.
|
22
|
-
You can also specify ingoing and/or outgoing direction and the RSMP component.
|
21
|
+
When you create a collector, you provide a Filter to specify the messages types you want to collect. You can also specify ingoing and/or outgoing direction and the RSMP component.
|
23
22
|
|
24
23
|
```ruby
|
25
|
-
collector = MessageCollector.new
|
24
|
+
collector = MessageCollector.new(distributor,
|
25
|
+
num: 10,
|
26
|
+
filter: Filter.new(ingoing: true, outgoing: true)
|
26
27
|
```
|
27
28
|
|
28
29
|
num: The number of messages to collect. If not provided, a timeout must be set instead.
|
29
|
-
|
30
|
+
filter: filter to identify the types of messages to look for.
|
31
|
+
|
32
|
+
### Filter
|
33
|
+
The Filter class is used to filter messages according to message type, direction and component.
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
filter = Filter.new(
|
37
|
+
type: 'Alarm',
|
38
|
+
ingoing: true,
|
39
|
+
outgoing: false,
|
40
|
+
component: 'DL1'
|
41
|
+
)
|
42
|
+
```
|
43
|
+
|
44
|
+
type: a string, or an array of string, specifiying one or more RSMP message types.
|
30
45
|
ingoing: Whether to collect ingoing messages. Defaults to true
|
31
46
|
outgoing: Whether to collect outgoing messages. Defaults to true
|
32
47
|
component: An RSMP component id.
|
@@ -48,7 +63,7 @@ result = collector.wait
|
|
48
63
|
```
|
49
64
|
|
50
65
|
### Custom filtering
|
51
|
-
You can use a block to do extra filtering. The block will be callled for each messages that
|
66
|
+
You can use a block to do extra filtering. The block will be callled for each messages that passes the Filter provided when initializing the collector.
|
52
67
|
|
53
68
|
The block must return nil or a list of symbols to indicate whether the message should be kept, and whether collection should be cancelled.
|
54
69
|
|
@@ -69,7 +84,7 @@ Exceptions in the block will cause the collector to abort. If the collect! or wa
|
|
69
84
|
The method collect!() will raise exceptions in case of errors, and will return the collect message directly.
|
70
85
|
|
71
86
|
```ruby
|
72
|
-
message = collector.collect # => collected message.
|
87
|
+
message = collector.collect! # => collected message.
|
73
88
|
```
|
74
89
|
|
75
90
|
Similar, `wait!()` will raise an exception in case of timeouts or errors:
|
@@ -181,7 +196,7 @@ result[:collector].messages # => list of collected messages
|
|
181
196
|
|
182
197
|
### Processing responses
|
183
198
|
If you pass a block, the block will be used to construct a collector. The block will be called for each matching status item received.
|
184
|
-
Collection will continue until the block returns :cancel, or it times.
|
199
|
+
Collection will continue until the block returns :cancel, or it times out.
|
185
200
|
|
186
201
|
```ruby
|
187
202
|
options = {
|
@@ -1,23 +1,23 @@
|
|
1
1
|
# Message distribution
|
2
2
|
|
3
|
-
Proxy - -
|
3
|
+
Proxy - - Distributor --> Receivers
|
4
4
|
|
5
|
-
A proxy distributes messages to
|
5
|
+
A proxy distributes messages to receivers, when they are installed.
|
6
6
|
|
7
|
-
Collectors are special
|
7
|
+
Collectors are special receiverws that waits for specific message, and are used to implement methods for waiting for RMSP responses, statuses, alarms, etc.
|
8
8
|
|
9
|
-
Note that Archive is not a
|
9
|
+
Note that Archive is not a receiver, and does not receive messages via the Distributor. Instead the Archive gets and stores messages via the log() interface in the Logging module. The reason is that the items that the Archive and the Logger contain other data as well as the message, like error messages, warnings, text descriptions, colors codes, etc. The Distributor and Receiver handles only Message objects.
|
10
10
|
|
11
|
-
##
|
11
|
+
## Distributor
|
12
12
|
A module that handles distributing messages to receivers.
|
13
13
|
|
14
|
-
##
|
14
|
+
## Receiver
|
15
15
|
Receives messages as long as it's installed into a distributor.
|
16
16
|
|
17
17
|
## Collector
|
18
|
-
|
18
|
+
Includes the Receiver module to wait for specific messages. Once received
|
19
19
|
the client receives the collection.
|
20
20
|
|
21
21
|
## Proxy
|
22
|
-
A proxy includes the
|
22
|
+
A proxy includes the Distributor module and distributes each message to receivers after processing it.
|
23
23
|
|
@@ -3,14 +3,16 @@ module RSMP
|
|
3
3
|
class AckCollector < Collector
|
4
4
|
def initialize proxy, options={}
|
5
5
|
raise ArgumentError.new("m_id must be provided") unless options[:m_id]
|
6
|
-
|
7
|
-
|
6
|
+
super proxy, options.merge(
|
7
|
+
filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: 'MessageAck'),
|
8
|
+
num: 1,
|
9
|
+
title: 'message acknowledgement'
|
10
|
+
)
|
8
11
|
end
|
9
12
|
|
10
13
|
# Check if we the MessageAck related to initiating request, identified by @m_id.
|
11
|
-
def
|
12
|
-
|
13
|
-
return message.attribute('oMId') == @options[:m_id]
|
14
|
+
def acceptable? message
|
15
|
+
super(message) && message.attribute('oMId') == @m_id
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -2,8 +2,10 @@ module RSMP
|
|
2
2
|
# Class for waiting for an aggregated status response
|
3
3
|
class AggregatedStatusCollector < Collector
|
4
4
|
def initialize proxy, options={}
|
5
|
-
|
6
|
-
|
5
|
+
super proxy, options.merge(
|
6
|
+
filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: 'AggregatedStatus'),
|
7
|
+
title: 'aggregated status'
|
8
|
+
)
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
@@ -2,20 +2,20 @@ module RSMP
|
|
2
2
|
# Class for waiting for specific command responses
|
3
3
|
class AlarmCollector < Collector
|
4
4
|
def initialize proxy,options={}
|
5
|
-
@
|
5
|
+
@matcher = options[:matcher] || {}
|
6
6
|
super proxy, options.merge(
|
7
|
-
type: 'Alarm',
|
7
|
+
filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: 'Alarm'),
|
8
8
|
title:'alarm'
|
9
9
|
)
|
10
10
|
end
|
11
11
|
|
12
12
|
# match alarm attributes
|
13
|
-
def
|
13
|
+
def acceptable? message
|
14
14
|
return false if super(message) == false
|
15
15
|
|
16
16
|
# match fixed attributes
|
17
17
|
%w{cId aCId aSp ack aS sS cat pri}.each do |key|
|
18
|
-
want = @
|
18
|
+
want = @matcher[key]
|
19
19
|
got = message.attribute(key)
|
20
20
|
case want
|
21
21
|
when Regexp
|
@@ -26,13 +26,13 @@ module RSMP
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# match rvs items
|
29
|
-
if @
|
30
|
-
|
29
|
+
if @matcher['rvs']
|
30
|
+
matcher_rvs = @matcher['rvs']
|
31
31
|
message_rvs = message.attributes['rvs']
|
32
32
|
return false unless message_rvs
|
33
|
-
return false unless
|
33
|
+
return false unless matcher_rvs.all? do |matcher_item|
|
34
34
|
return false unless message_rvs.any? do |message_item|
|
35
|
-
next message_item['n'] ==
|
35
|
+
next message_item['n'] == matcher_item['n'] && message_item['v'] == matcher_item['v']
|
36
36
|
end
|
37
37
|
next true
|
38
38
|
end
|
@@ -41,8 +41,8 @@ module RSMP
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# return a string that describes what we're collecting
|
44
|
-
def
|
45
|
-
"#{describe_num_and_type} #{ {component: @options[:component]}.merge(@
|
44
|
+
def describe_matcher
|
45
|
+
"#{describe_num_and_type} #{ {component: @options[:component]}.merge(@matcher).compact }"
|
46
46
|
end
|
47
47
|
|
48
48
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RSMP
|
2
2
|
# Match a specific alarm
|
3
|
-
class
|
4
|
-
# Match an alarm value against a
|
3
|
+
class AlarmMatcher < Matcher
|
4
|
+
# Match an alarm value against a matcher
|
5
5
|
def match? item
|
6
6
|
return false if @want['n'] && @want['n'] != item['n']
|
7
7
|
if @want['v'].is_a? Regexp
|
@@ -1,40 +1,53 @@
|
|
1
1
|
module RSMP
|
2
2
|
|
3
|
-
# Collects messages from a
|
3
|
+
# Collects messages from a distributor.
|
4
4
|
# Can filter by message type, componet and direction.
|
5
5
|
# Wakes up the once the desired number of messages has been collected.
|
6
|
-
class Collector
|
7
|
-
|
6
|
+
class Collector
|
7
|
+
include Receiver
|
8
|
+
attr_reader :condition, :messages, :status, :error, :task, :m_id
|
8
9
|
|
9
|
-
def initialize
|
10
|
-
|
10
|
+
def initialize distributor, options={}
|
11
|
+
initialize_receiver distributor, filter: options[:filter]
|
11
12
|
@options = {
|
12
13
|
cancel: {
|
13
14
|
schema_error: true,
|
14
15
|
disconnect: false,
|
15
16
|
}
|
16
17
|
}.deep_merge options
|
17
|
-
@
|
18
|
-
@
|
18
|
+
@timeout = options[:timeout]
|
19
|
+
@num = options[:num]
|
20
|
+
@m_id = options[:m_id]
|
19
21
|
@condition = Async::Notification.new
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
make_title options[:title]
|
23
|
+
|
24
|
+
if task
|
25
|
+
@task = task
|
23
26
|
else
|
24
|
-
# if
|
27
|
+
# if distributor is a Proxy, or some other object that implements task(),
|
25
28
|
# then try to get the task that way
|
26
|
-
if
|
27
|
-
@task =
|
29
|
+
if distributor.respond_to? 'task'
|
30
|
+
@task = distributor.task
|
28
31
|
end
|
29
32
|
end
|
30
33
|
reset
|
31
34
|
end
|
32
35
|
|
36
|
+
def make_title title
|
37
|
+
if title
|
38
|
+
@title = title
|
39
|
+
elsif @filter
|
40
|
+
@title = [@filter.type].flatten.join('/')
|
41
|
+
else
|
42
|
+
@title = ""
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
33
46
|
def use_task task
|
34
47
|
@task = task
|
35
48
|
end
|
36
49
|
|
37
|
-
# Clear all
|
50
|
+
# Clear all matcher results
|
38
51
|
def reset
|
39
52
|
@messages = []
|
40
53
|
@error = nil
|
@@ -95,7 +108,7 @@ module RSMP
|
|
95
108
|
wait
|
96
109
|
@status
|
97
110
|
ensure
|
98
|
-
@
|
111
|
+
@distributor.remove_receiver self if @distributor
|
99
112
|
end
|
100
113
|
|
101
114
|
# Collect message
|
@@ -110,8 +123,8 @@ module RSMP
|
|
110
123
|
# the desired messages have been collected, or timeout is reached.
|
111
124
|
def wait
|
112
125
|
if collecting?
|
113
|
-
if @
|
114
|
-
@task.with_timeout(@
|
126
|
+
if @timeout
|
127
|
+
@task.with_timeout(@timeout) { @condition.wait }
|
115
128
|
else
|
116
129
|
@condition.wait
|
117
130
|
end
|
@@ -136,39 +149,41 @@ module RSMP
|
|
136
149
|
def start &block
|
137
150
|
raise RuntimeError.new("Can't start collectimng unless ready (currently #{@status})") unless ready?
|
138
151
|
@block = block
|
139
|
-
raise ArgumentError.new("Num, timeout or block must be provided") unless @
|
152
|
+
raise ArgumentError.new("Num, timeout or block must be provided") unless @num || @timeout || @block
|
140
153
|
reset
|
141
154
|
@status = :collecting
|
142
155
|
log_start
|
143
|
-
@
|
156
|
+
@distributor.add_receiver self if @distributor
|
144
157
|
end
|
145
158
|
|
146
159
|
# Build a string describing how how progress reached before timeout
|
147
160
|
def describe_progress
|
148
161
|
str = "#{identifier}: #{@title.capitalize} collection "
|
149
|
-
str << "in response to #{@
|
150
|
-
str << "didn't complete within #{@
|
151
|
-
str << "reached #{@messages.size}/#{@
|
162
|
+
str << "in response to #{@m_id} " if @m_id
|
163
|
+
str << "didn't complete within #{@timeout}s, "
|
164
|
+
str << "reached #{@messages.size}/#{@num}"
|
152
165
|
str
|
153
166
|
end
|
154
167
|
|
155
168
|
# Check if we receive a NotAck related to initiating request, identified by @m_id.
|
156
169
|
def reject_not_ack message
|
157
|
-
return unless @
|
170
|
+
return unless @m_id
|
158
171
|
if message.is_a?(MessageNotAck)
|
159
|
-
if message.attribute('oMId') == @
|
160
|
-
m_id_short = RSMP::Message.shorten_m_id @
|
172
|
+
if message.attribute('oMId') == @m_id
|
173
|
+
m_id_short = RSMP::Message.shorten_m_id @m_id, 8
|
161
174
|
cancel RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected with '#{message.attribute('rea')}'")
|
162
|
-
@
|
175
|
+
@distributor.log "#{identifier}: cancelled due to a NotAck", level: :debug
|
163
176
|
true
|
164
177
|
end
|
165
178
|
end
|
166
179
|
end
|
167
180
|
|
168
181
|
# Handle message. and return true when we're done collecting
|
169
|
-
def
|
182
|
+
def receive message
|
170
183
|
raise ArgumentError unless message
|
171
|
-
|
184
|
+
unless ready? || collecting?
|
185
|
+
raise RuntimeError.new("can't process message when status is :#{@status}, title: #{@title}, desc: #{describe}")
|
186
|
+
end
|
172
187
|
if perform_match message
|
173
188
|
if done?
|
174
189
|
complete
|
@@ -185,8 +200,8 @@ module RSMP
|
|
185
200
|
# Match message against our collection criteria
|
186
201
|
def perform_match message
|
187
202
|
return false if reject_not_ack(message)
|
188
|
-
return false unless
|
189
|
-
#@
|
203
|
+
return false unless acceptable?(message)
|
204
|
+
#@distributor.log "#{identifier}: Looking at #{message.type} #{message.m_id_short}", level: :collect
|
190
205
|
if @block
|
191
206
|
status = [@block.call(message)].flatten
|
192
207
|
return unless collecting?
|
@@ -198,10 +213,10 @@ module RSMP
|
|
198
213
|
|
199
214
|
# Have we collected the required number of messages?
|
200
215
|
def done?
|
201
|
-
@
|
216
|
+
@num && @messages.size >= @num
|
202
217
|
end
|
203
218
|
|
204
|
-
# Called when we're done collecting. Remove ourself as a
|
219
|
+
# Called when we're done collecting. Remove ourself as a receiver,
|
205
220
|
# se we don't receive message notifications anymore
|
206
221
|
def complete
|
207
222
|
@status = :ok
|
@@ -214,39 +229,39 @@ module RSMP
|
|
214
229
|
log_incomplete
|
215
230
|
end
|
216
231
|
|
217
|
-
# Remove ourself as a
|
232
|
+
# Remove ourself as a receiver, so we don't receive message notifications anymore,
|
218
233
|
# and wake up the async condition
|
219
234
|
def do_stop
|
220
|
-
@
|
235
|
+
@distributor.remove_receiver self
|
221
236
|
@condition.signal
|
222
237
|
end
|
223
238
|
|
224
239
|
# An error occured upstream.
|
225
240
|
# Check if we should cancel.
|
226
|
-
def
|
241
|
+
def receive_error error, options={}
|
227
242
|
case error
|
228
243
|
when RSMP::SchemaError
|
229
|
-
|
244
|
+
receive_schema_error error, options
|
230
245
|
when RSMP::DisconnectError
|
231
|
-
|
246
|
+
receive_disconnect error, options
|
232
247
|
end
|
233
248
|
end
|
234
249
|
|
235
250
|
# Cancel if we received e schema error for a message type we're collecting
|
236
|
-
def
|
251
|
+
def receive_schema_error error, options
|
237
252
|
return unless @options.dig(:cancel,:schema_error)
|
238
253
|
message = options[:message]
|
239
254
|
return unless message
|
240
255
|
klass = message.class.name.split('::').last
|
241
|
-
return unless @
|
242
|
-
@
|
256
|
+
return unless @filter&.type == nil || [@filter&.type].flatten.include?(klass)
|
257
|
+
@distributor.log "#{identifier}: cancelled due to schema error in #{klass} #{message.m_id_short}", level: :debug
|
243
258
|
cancel error
|
244
259
|
end
|
245
260
|
|
246
261
|
# Cancel if we received e notificaiton about a disconnect
|
247
|
-
def
|
262
|
+
def receive_disconnect error, options
|
248
263
|
return unless @options.dig(:cancel,:disconnect)
|
249
|
-
@
|
264
|
+
@distributor.log "#{identifier}: cancelled due to a connection error: #{error.to_s}", level: :debug
|
250
265
|
cancel error
|
251
266
|
end
|
252
267
|
|
@@ -264,39 +279,27 @@ module RSMP
|
|
264
279
|
|
265
280
|
# Check a message against our match criteria
|
266
281
|
# Return true if there's a match, false if not
|
267
|
-
def
|
268
|
-
|
269
|
-
return false if message.direction == :out && @outgoing == false
|
270
|
-
if @options[:type]
|
271
|
-
if @options[:type].is_a? Array
|
272
|
-
return false unless @options[:type].include? message.type
|
273
|
-
else
|
274
|
-
return false unless message.type == @options[:type]
|
275
|
-
end
|
276
|
-
end
|
277
|
-
if @options[:component]
|
278
|
-
return false if message.attributes['cId'] && message.attributes['cId'] != @options[:component]
|
279
|
-
end
|
280
|
-
true
|
282
|
+
def acceptable? message
|
283
|
+
@filter == nil || @filter.accept?(message)
|
281
284
|
end
|
282
285
|
|
283
286
|
# return a string describing the types of messages we're collecting
|
284
287
|
def describe_types
|
285
|
-
[@
|
288
|
+
[@filter&.type].flatten.join('/')
|
286
289
|
end
|
287
290
|
|
288
291
|
# return a string that describes whe number of messages, and type of message we're collecting
|
289
292
|
def describe_num_and_type
|
290
|
-
if @
|
291
|
-
"#{@
|
293
|
+
if @num && @num > 1
|
294
|
+
"#{@num} #{describe_types}s"
|
292
295
|
else
|
293
296
|
describe_types
|
294
297
|
end
|
295
298
|
end
|
296
299
|
|
297
300
|
# return a string that describes the attributes that we're looking for
|
298
|
-
def
|
299
|
-
h = {component: @
|
301
|
+
def describe_matcher
|
302
|
+
h = {component: @filter&.component}.compact
|
300
303
|
if h.empty?
|
301
304
|
describe_num_and_type
|
302
305
|
else
|
@@ -306,8 +309,8 @@ module RSMP
|
|
306
309
|
|
307
310
|
# return a string that describe how many many messages have been collected
|
308
311
|
def describe_progress
|
309
|
-
if @
|
310
|
-
"#{@messages.size} of #{@
|
312
|
+
if @num
|
313
|
+
"#{@messages.size} of #{@num} message#{'s' if @messages.size!=1} collected"
|
311
314
|
else
|
312
315
|
"#{@messages.size} message#{'s' if @messages.size!=1} collected"
|
313
316
|
end
|
@@ -315,17 +318,17 @@ module RSMP
|
|
315
318
|
|
316
319
|
# log when we start collecting
|
317
320
|
def log_start
|
318
|
-
@
|
321
|
+
@distributor.log "#{identifier}: Waiting for #{describe_matcher}".strip, level: :collect
|
319
322
|
end
|
320
323
|
|
321
324
|
# log current progress
|
322
325
|
def log_incomplete
|
323
|
-
@
|
326
|
+
@distributor.log "#{identifier}: #{describe_progress}", level: :collect
|
324
327
|
end
|
325
328
|
|
326
329
|
# log when we end collecting
|
327
330
|
def log_complete
|
328
|
-
@
|
331
|
+
@distributor.log "#{identifier}: Done", level: :collect
|
329
332
|
end
|
330
333
|
|
331
334
|
# get a short id in hex format, identifying ourself
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RSMP
|
2
2
|
# Match a specific command responses
|
3
|
-
class
|
4
|
-
# Match a return value item against a
|
3
|
+
class CommandMatcher < Matcher
|
4
|
+
# Match a return value item against a matcher
|
5
5
|
def match? item
|
6
6
|
return nil if @want['cCI'] && @want['cCI'] != item['cCI']
|
7
7
|
return nil if @want['n'] && @want['n'] != item['n']
|
@@ -3,13 +3,13 @@ module RSMP
|
|
3
3
|
class CommandResponseCollector < StateCollector
|
4
4
|
def initialize proxy, want, options={}
|
5
5
|
super proxy, want, options.merge(
|
6
|
-
type: 'CommandResponse',
|
6
|
+
filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: 'CommandResponse'),
|
7
7
|
title:'command response'
|
8
8
|
)
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
11
|
+
def build_matcher want
|
12
|
+
CommandMatcher.new want
|
13
13
|
end
|
14
14
|
|
15
15
|
# Get items, in our case the return values
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Distributes messages to receivers
|
2
|
+
|
3
|
+
module RSMP
|
4
|
+
module Distributor
|
5
|
+
attr_reader :receivers
|
6
|
+
|
7
|
+
include Inspect
|
8
|
+
|
9
|
+
def inspect
|
10
|
+
"#<#{self.class.name}:#{self.object_id}, #{inspector(:@receivers)}>"
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize_distributor
|
14
|
+
@receivers = []
|
15
|
+
@defer_distribution = false
|
16
|
+
@deferred_messages = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear_deferred_distribution &block
|
20
|
+
@deferred_messages = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def with_deferred_distribution &block
|
24
|
+
was, @defer_distribution = @defer_distribution, true
|
25
|
+
yield
|
26
|
+
distribute_queued
|
27
|
+
ensure
|
28
|
+
@defer_distribution = was
|
29
|
+
@deferred_messages = []
|
30
|
+
end
|
31
|
+
|
32
|
+
def distribute_queued
|
33
|
+
@deferred_messages.each { |message| distribute_immediately message }
|
34
|
+
ensure
|
35
|
+
@deferred_messages = []
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_receiver receiver
|
39
|
+
raise ArgumentError unless receiver
|
40
|
+
@receivers << receiver unless @receivers.include? receiver
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove_receiver receiver
|
44
|
+
raise ArgumentError unless receiver
|
45
|
+
@receivers.delete receiver
|
46
|
+
end
|
47
|
+
|
48
|
+
def distribute message
|
49
|
+
raise ArgumentError unless message
|
50
|
+
if @defer_distribution
|
51
|
+
@deferred_messages << message
|
52
|
+
else
|
53
|
+
distribute_immediately message
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def distribute_immediately message
|
58
|
+
@receivers.each { |receiver| receiver.receive message }
|
59
|
+
end
|
60
|
+
|
61
|
+
def distribute_error error, options={}
|
62
|
+
@receivers.each { |receiver| receiver.receive_error error, options }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|