rsmp 0.8.0 → 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/config/tlc.yaml +8 -6
- data/documentation/classes_and_modules.md +1 -4
- data/documentation/collecting_message.md +196 -0
- data/lib/rsmp/collect/aggregated_status_collector.rb +9 -0
- data/lib/rsmp/collect/collector.rb +92 -59
- data/lib/rsmp/collect/command_query.rb +16 -0
- data/lib/rsmp/collect/command_response_collector.rb +20 -0
- data/lib/rsmp/collect/filter.rb +31 -0
- data/lib/rsmp/collect/listener.rb +0 -8
- data/lib/rsmp/collect/message_matchers.rb +0 -64
- data/lib/rsmp/collect/query.rb +16 -6
- data/lib/rsmp/collect/{matcher.rb → state_collector.rb} +19 -9
- data/lib/rsmp/collect/status_collector.rb +20 -0
- data/lib/rsmp/collect/{message_queries.rb → status_query.rb} +0 -15
- data/lib/rsmp/node.rb +0 -1
- data/lib/rsmp/proxy.rb +15 -19
- data/lib/rsmp/site.rb +3 -2
- data/lib/rsmp/site_proxy.rb +34 -46
- data/lib/rsmp/supervisor_proxy.rb +3 -11
- data/lib/rsmp/tlc/signal_group.rb +15 -7
- data/lib/rsmp/tlc/traffic_controller.rb +92 -28
- data/lib/rsmp/tlc/traffic_controller_site.rb +10 -1
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +7 -3
- metadata +10 -5
- data/lib/rsmp/collect/message_collector.rb +0 -209
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6e0bddb9443fd704586251f92785f5ec4d703431d587047f8a2e835fcb48b9f
|
4
|
+
data.tar.gz: 81b56b1687ad356177b6277d58f6db4ed4d3f8fa8e59aa0fc626a90fcc03bb86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8ba189a5602f9ec1bc7f09e821231c2f5135dd163da82ffae48b9a9f62ac79ec8d4beb114e6112d41902fc1ca06ccff2a208863d00f05e51c9a83cafb68e33c
|
7
|
+
data.tar.gz: 4fd8b04217edb49b3c1b929ac3d585c60194207cdb8380be7693ee00b448a28fce90cc6e55621b6cee601d773f80c6780c0d7a3a31ee8606f62f23cfce0718f8
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rsmp (0.8.
|
4
|
+
rsmp (0.8.4)
|
5
5
|
async (~> 1.29.1)
|
6
6
|
async-io (~> 1.32.1)
|
7
7
|
colorize (~> 0.8.1)
|
@@ -70,8 +70,8 @@ GEM
|
|
70
70
|
cucumber-cucumber-expressions (~> 12.1, >= 12.1.1)
|
71
71
|
cucumber-messages (~> 15.0, >= 15.0.0)
|
72
72
|
diff-lcs (1.4.4)
|
73
|
-
ecma-re-validator (0.
|
74
|
-
regexp_parser (~> 2.
|
73
|
+
ecma-re-validator (0.4.0)
|
74
|
+
regexp_parser (~> 2.2)
|
75
75
|
ffi (1.15.3)
|
76
76
|
fiber-local (1.0.0)
|
77
77
|
hana (1.3.7)
|
data/config/tlc.yaml
CHANGED
@@ -20,17 +20,18 @@ signal_plans:
|
|
20
20
|
dynamic_bands:
|
21
21
|
1: 0
|
22
22
|
2: 5
|
23
|
-
states:
|
24
|
-
A1: '11NBBB'
|
25
|
-
A2: '1NBBBB'
|
26
|
-
B1: 'BBB11N'
|
27
|
-
B2: 'BBB1NB'
|
28
|
-
2:
|
29
23
|
states:
|
30
24
|
A1: '111NBB'
|
31
25
|
A2: '11NBBB'
|
32
26
|
B1: 'BBB11N'
|
33
27
|
B2: 'BBB1NB'
|
28
|
+
2:
|
29
|
+
states:
|
30
|
+
A1: 'NNNNBB'
|
31
|
+
A2: 'NNNNBN'
|
32
|
+
B1: 'BBNNNN'
|
33
|
+
B2: 'BNNNNN'
|
34
|
+
startup_sequence: 'efg'
|
34
35
|
intervals:
|
35
36
|
timer: 0.1
|
36
37
|
watchdog: 0.1
|
@@ -48,3 +49,4 @@ log:
|
|
48
49
|
level: false
|
49
50
|
debug: true
|
50
51
|
json: true
|
52
|
+
live_output: tmp/tlc.state
|
@@ -19,9 +19,6 @@ Handle logging.
|
|
19
19
|
### Wait
|
20
20
|
Handles waiting for an async condition and block.
|
21
21
|
|
22
|
-
### SiteProxyWait
|
23
|
-
Handles waiting for different types of messages and responses from a remote site.
|
24
|
-
|
25
22
|
### Components
|
26
23
|
Component handling.
|
27
24
|
|
@@ -38,7 +35,7 @@ A Site has one or more SupervisorProxies (connections to supervisor).
|
|
38
35
|
|
39
36
|
A site has one of more components.
|
40
37
|
|
41
|
-
### Supervisor
|
38
|
+
### Supervisor
|
42
39
|
A Supervisor represents an RSMP supervisor, typically a central supervisor system. An RSMP supervisor can handle connections one or more sites.
|
43
40
|
|
44
41
|
A Supervisor has one or more SiteProxies (connections to sites).
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# Collection
|
2
|
+
You often need to collect messages or responses. The collector classes are used to collect message asyncronously. Other tasks continue until the collection completes, time outs or is cancelled.
|
3
|
+
|
4
|
+
A collector can collect ingoing and/or outgoing messages.
|
5
|
+
|
6
|
+
An object that includes the Notifier module (or implements the same functionality) must be provided when you construct a Collected. The collector will attach itself to this notifier when it starts collecting, to receive messages. The SiteProxy and SupervisorProxy classes both include the Notifier module, and can therefore be used as message sources.
|
7
|
+
|
8
|
+
Messages that match the relevant criteria are stored by the collector.
|
9
|
+
|
10
|
+
When the collection is done, the collector detaches from the notifier, and returns the status.
|
11
|
+
|
12
|
+
|
13
|
+
## Collector
|
14
|
+
Class uses for collecting messages filtered by message type, direction and/or component id. A block can be used for custom filtering.
|
15
|
+
|
16
|
+
You can choose to collect a specific number of message and/or for a specific duration.
|
17
|
+
|
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
|
+
|
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.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
collector = MessageCollector.new notifier, num: 10, ingoing: true, outgoing: true
|
26
|
+
```
|
27
|
+
|
28
|
+
num: The number of messages to collect. If not provided, a timeout must be set instead.
|
29
|
+
timeout: The number of seconds to collect
|
30
|
+
ingoing: Whether to collect ingoing messages. Defaults to true
|
31
|
+
outgoing: Whether to collect outgoing messages. Defaults to true
|
32
|
+
component: An RSMP component id.
|
33
|
+
|
34
|
+
### Collecting
|
35
|
+
Use collect() to start collecting and wait for completion or timeout. The status will be returned.
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
result = collector.collect # => :ok, :timeout or :cancelled
|
39
|
+
collector.messages # => collected messages
|
40
|
+
```
|
41
|
+
|
42
|
+
If you want start collection, but not wait for the result, use `start()`. You can then later use `wait()` if you want:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
result = collector.start # => nil
|
46
|
+
# do other stuff
|
47
|
+
result = collector.wait
|
48
|
+
```
|
49
|
+
|
50
|
+
### Custom filtering
|
51
|
+
You can use a block to do extra filtering. The block will be callled for each messages that fulfils the correct message type, direction and component id.
|
52
|
+
|
53
|
+
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
|
+
|
55
|
+
```ruby
|
56
|
+
result = collector.collect do |message|
|
57
|
+
:keep, :cancel # example of how to keep the message and cancel collection
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
`:keep` keeps (collect) this message
|
62
|
+
`:cancel` cancel collection
|
63
|
+
|
64
|
+
Note that you cannot use `return` in a block. You can either simply provide the values as the last expresssion in the block, or use next().
|
65
|
+
|
66
|
+
Exceptions in the block will cause the collector to abort. If the collect! or wait! variants are used, the exception is propagated to the caller.
|
67
|
+
|
68
|
+
### Bang version
|
69
|
+
The method collect!() will raise exceptions in case of errors, and will return the collect message directly.
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
message = collector.collect # => collected message.
|
73
|
+
```
|
74
|
+
|
75
|
+
Similar, `wait!()` will raise an exception in case of timeouts or errors:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
message = collector.wait! # => collected message.
|
79
|
+
```
|
80
|
+
|
81
|
+
|
82
|
+
### Schema Errors and Disconnects
|
83
|
+
The collector can optionally cancel collection in special cases, controlled by the `:cancel` option provided when contructing the collector.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
options = {
|
87
|
+
cancel: {
|
88
|
+
disconnect: true,
|
89
|
+
schema_error: true
|
90
|
+
}
|
91
|
+
}
|
92
|
+
result = collector.collect options
|
93
|
+
```
|
94
|
+
|
95
|
+
disconnect: If the proxy which provides messages experience a disconnect, the collector will cancel collection.
|
96
|
+
|
97
|
+
schema_error: If the proxy receives a message with a schema error, the collector will cancel collection, if the the invalid message has the correct message type.
|
98
|
+
|
99
|
+
### NotAck
|
100
|
+
A typical scenaria is that you send a command or status request, and want to collect the response. But if the original message is rejected by the site, you will received a NotAck instead of a reply. The collector classes can handle this, as long as you provide the message id of the original request in the `m_id` key of teh options when you construct the collector.
|
101
|
+
|
102
|
+
If a NotAck is received with a matching `oMId` (original message id), the collection is cancelled.
|
103
|
+
|
104
|
+
## StatusCollector
|
105
|
+
Waits for a set of status criteria to be met.
|
106
|
+
|
107
|
+
Note that a single RSMP status message can contain multiple status items. Unlike MessageCollector, a StatusCollector therefore operates on items, rather than messages, and you can't specify a number of messages to collect.
|
108
|
+
|
109
|
+
|
110
|
+
### Criteria
|
111
|
+
You construct a StatusCollector with set of criteria, specifying the status codes, names, and optionally values that must be met.
|
112
|
+
|
113
|
+
### Collecting
|
114
|
+
When you start collection, it will complete once all criteria are all fulfilled, the timeout is reached or a custom filtering block aborts the collection.
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
collector = StatusCollector.new(options)
|
118
|
+
result = matcher.collect(timeout: 5)
|
119
|
+
```
|
120
|
+
|
121
|
+
### Custom filtering
|
122
|
+
You can use a block to do extra filtering. The block will be called for each individual status item that fulfils all criteria, like status code and name, component, etc.
|
123
|
+
|
124
|
+
Like with MessageCollector, the block must return a hash specifing whether to keep the message and whether to continue collection.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
matcher = StatusCollector.new(options)
|
128
|
+
result = matcher.collect(options) do |message,item|
|
129
|
+
next(:keep) if good_item?(item) # keep item
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
## Subscribing to status updates
|
134
|
+
The method `subscribe_to_status` can be used to subscribe to one of more status messages.
|
135
|
+
|
136
|
+
### Without collection
|
137
|
+
The simple form sends an RSMP status subscription message to the site and then returns immediatly. To collect incoming status messages, you need to manually use e.g. a Collector.
|
138
|
+
|
139
|
+
A hash is returned, with `:sent` containing the send subscription messages.
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
options = {
|
143
|
+
list: [{'sCI'=>'S0001','n'=>'signalgroupstatus'}],
|
144
|
+
}
|
145
|
+
result = subscribe_to_status(options)
|
146
|
+
result.keys => # [:sent]
|
147
|
+
```
|
148
|
+
|
149
|
+
Note: If you want to use this simple form and manually collect responses, it's best to start collection in an asyncronous task _before_ you subscribe, to make sure you don't miss early responses:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
task = async do
|
153
|
+
MessageCollector.new(options).collect(num: 5, timeout:10) # start listening for status messages
|
154
|
+
end
|
155
|
+
result = subscribe_to_status(options) # subscribe
|
156
|
+
task.wait # wait for collection task to complete (or time out)
|
157
|
+
```
|
158
|
+
|
159
|
+
### With collection
|
160
|
+
If you provide `:collect` options, it will be used to construct a StatusCollector for collecting the relevant status messages. When collection completes the collector is returned in the `:collector` key:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
options = {
|
164
|
+
list: [{'sCI'=>'S0001','n'=>'signalgroupstatus'}],
|
165
|
+
collect: {timeout: 5}
|
166
|
+
}
|
167
|
+
result = subscribe_to_status(options)
|
168
|
+
result.keys => # [:sent, :collector]
|
169
|
+
result[:collector].messages # => list of collected messages
|
170
|
+
```
|
171
|
+
|
172
|
+
You can pass you own collector which will give you more control of how to collect the incoming status messages:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
collector = Collector.new(options)
|
176
|
+
options = {collect: collector}
|
177
|
+
result = subscribe_to_status(options)
|
178
|
+
result.keys => # [:sent, :collector]
|
179
|
+
result[:collector].messages # => list of collected messages
|
180
|
+
```
|
181
|
+
|
182
|
+
### Processing responses
|
183
|
+
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.
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
options = {
|
188
|
+
list: [{'sCI'=>'S0001','n'=>'signalgroupstatus'}]
|
189
|
+
}
|
190
|
+
result = subscribe_to_status(options) do |message|
|
191
|
+
# do something with message
|
192
|
+
:keep # or not
|
193
|
+
end
|
194
|
+
result.keys => # [:sent, :collector]
|
195
|
+
```
|
196
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module RSMP
|
2
|
+
# Class for waiting for an aggregated status response
|
3
|
+
class AggregatedStatusCollector < Collector
|
4
|
+
def initialize proxy, options={}
|
5
|
+
required = { type: ['AggregatedStatus','MessageNotAck'], title: 'aggregated status' }
|
6
|
+
super proxy, options.merge(required)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module RSMP
|
2
2
|
|
3
|
-
# Collects
|
4
|
-
# Can filter by message type and
|
3
|
+
# Collects messages from a notifier.
|
4
|
+
# Can filter by message type, componet and direction.
|
5
|
+
# Wakes up the once the desired number of messages has been collected.
|
5
6
|
class Collector < Listener
|
6
|
-
attr_reader :condition, :messages, :status, :error
|
7
|
+
attr_reader :condition, :messages, :status, :error, :task
|
7
8
|
|
8
|
-
def initialize
|
9
|
-
super
|
9
|
+
def initialize notifier, options={}
|
10
|
+
super notifier, options
|
10
11
|
@options = {
|
11
12
|
cancel: {
|
12
13
|
schema_error: true,
|
@@ -17,15 +18,27 @@ module RSMP
|
|
17
18
|
@outgoing = options[:outgoing] == nil ? false : options[:outgoing]
|
18
19
|
@condition = Async::Notification.new
|
19
20
|
@title = options[:title] || [@options[:type]].flatten.join('/')
|
21
|
+
if options[:task]
|
22
|
+
@task = options[:task]
|
23
|
+
else
|
24
|
+
# if notifier is a Proxy, or some other object that implements task(),
|
25
|
+
# then try to get the task that way
|
26
|
+
if notifier.respond_to? 'task'
|
27
|
+
@task = notifier.task
|
28
|
+
end
|
29
|
+
end
|
20
30
|
reset
|
21
31
|
end
|
22
32
|
|
33
|
+
def use_task task
|
34
|
+
@task = task
|
35
|
+
end
|
36
|
+
|
23
37
|
# Clear all query results
|
24
38
|
def reset
|
25
39
|
@messages = []
|
26
40
|
@error = nil
|
27
41
|
@status = :ready
|
28
|
-
@why = nil
|
29
42
|
end
|
30
43
|
|
31
44
|
# Inspect formatter that shows the message we have collected
|
@@ -33,6 +46,31 @@ module RSMP
|
|
33
46
|
"#<#{self.class.name}:#{self.object_id}, #{inspector(:@messages)}>"
|
34
47
|
end
|
35
48
|
|
49
|
+
# Is collection active?
|
50
|
+
def collecting?
|
51
|
+
@status == :collecting
|
52
|
+
end
|
53
|
+
|
54
|
+
# Is collection active?
|
55
|
+
def ok?
|
56
|
+
@status == :ok
|
57
|
+
end
|
58
|
+
|
59
|
+
# Has collection time out?
|
60
|
+
def timeout?
|
61
|
+
@status == :timeout
|
62
|
+
end
|
63
|
+
|
64
|
+
# Is collection ready to start?
|
65
|
+
def ready?
|
66
|
+
@status == :ready
|
67
|
+
end
|
68
|
+
|
69
|
+
# Has collection been cancelled?
|
70
|
+
def cancelled?
|
71
|
+
@status == :cancelled
|
72
|
+
end
|
73
|
+
|
36
74
|
# Want ingoing messages?
|
37
75
|
def ingoing?
|
38
76
|
@ingoing == true
|
@@ -43,35 +81,53 @@ module RSMP
|
|
43
81
|
@outgoing == true
|
44
82
|
end
|
45
83
|
|
46
|
-
#
|
47
|
-
#
|
48
|
-
def
|
49
|
-
|
50
|
-
|
84
|
+
# Collect message
|
85
|
+
# Will return once all messages have been collected, or timeout is reached
|
86
|
+
def collect &block
|
87
|
+
start &block
|
88
|
+
wait
|
51
89
|
@status
|
90
|
+
ensure
|
91
|
+
@notifier.remove_listener self if @notifier
|
52
92
|
end
|
53
93
|
|
54
|
-
#
|
55
|
-
# the
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
94
|
+
# Collect message
|
95
|
+
# Returns the collected messages, or raise an exception in case of a time out.
|
96
|
+
def collect! &block
|
97
|
+
if collect(&block) == :timeout
|
98
|
+
raise RSMP::TimeoutError.new describe_progress
|
99
|
+
end
|
100
|
+
@messages
|
101
|
+
end
|
102
|
+
|
103
|
+
# If collection is not active, return status immeditatly. Otherwise wait until
|
104
|
+
# the desired messages have been collected, or timeout is reached.
|
105
|
+
def wait
|
106
|
+
if collecting?
|
107
|
+
if @options[:timeout]
|
108
|
+
@task.with_timeout(@options[:timeout]) { @condition.wait }
|
109
|
+
else
|
110
|
+
@condition.wait
|
111
|
+
end
|
63
112
|
end
|
64
113
|
@status
|
65
114
|
rescue Async::TimeoutError
|
66
115
|
@status = :timeout
|
67
|
-
|
116
|
+
end
|
117
|
+
|
118
|
+
# If collection is not active, raise an error. Otherwise wait until
|
119
|
+
# the desired messages have been collected.
|
120
|
+
# If timeout is reached, an exceptioin is raised.
|
121
|
+
def wait!
|
122
|
+
wait
|
123
|
+
raise RSMP::TimeoutError.new(describe_progress) if timeout?
|
124
|
+
@messages
|
68
125
|
end
|
69
126
|
|
70
127
|
# Start collection and return immediately
|
71
128
|
# You can later use wait() to wait for completion
|
72
|
-
def start
|
73
|
-
raise RuntimeError.new("Can't begin unless ready (currenty #{@status})") unless
|
74
|
-
@options.merge! options
|
129
|
+
def start &block
|
130
|
+
raise RuntimeError.new("Can't begin unless ready (currenty #{@status})") unless ready?
|
75
131
|
@block = block
|
76
132
|
raise ArgumentError.new("Num, timeout or block must be provided") unless @options[:num] || @options[:timeout] || @block
|
77
133
|
reset
|
@@ -79,16 +135,6 @@ module RSMP
|
|
79
135
|
@notifier.add_listener self if @notifier
|
80
136
|
end
|
81
137
|
|
82
|
-
# Collect message
|
83
|
-
# Will return once all messages have been collected, or timeout is reached
|
84
|
-
def collect task, options={}, &block
|
85
|
-
start options, &block
|
86
|
-
wait task
|
87
|
-
@status
|
88
|
-
ensure
|
89
|
-
@notifier.remove_listener self
|
90
|
-
end
|
91
|
-
|
92
138
|
# Build a string describing how how progress reached before timeout
|
93
139
|
def describe_progress
|
94
140
|
str = "#{@title.capitalize} collection "
|
@@ -98,17 +144,6 @@ module RSMP
|
|
98
144
|
str
|
99
145
|
end
|
100
146
|
|
101
|
-
# Collect message
|
102
|
-
# Returns the collected messages, or raise an exception in case of a time out.
|
103
|
-
def collect! task, options={}, &block
|
104
|
-
case collect(task, options, &block)
|
105
|
-
when :timeout
|
106
|
-
raise RSMP::TimeoutError.new @why
|
107
|
-
else
|
108
|
-
@messages
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
147
|
# Check if we receive a NotAck related to initiating request, identified by @m_id.
|
113
148
|
def reject_not_ack message
|
114
149
|
return unless @options[:m_id]
|
@@ -124,28 +159,26 @@ module RSMP
|
|
124
159
|
# Handle message. and return true when we're done collecting
|
125
160
|
def notify message
|
126
161
|
raise ArgumentError unless message
|
127
|
-
raise RuntimeError.new("can't process message when
|
128
|
-
|
129
|
-
perform_match message
|
130
|
-
end
|
162
|
+
raise RuntimeError.new("can't process message when status is :#{@status}, title: #{@title}, desc: #{describe}") unless ready? || collecting?
|
163
|
+
perform_match message
|
131
164
|
@status
|
132
165
|
end
|
133
166
|
|
167
|
+
def describe
|
168
|
+
end
|
169
|
+
|
134
170
|
# Match message against our collection criteria
|
135
171
|
def perform_match message
|
136
|
-
return
|
172
|
+
return false if reject_not_ack(message)
|
173
|
+
return false unless type_match?(message)
|
137
174
|
if @block
|
138
175
|
status = [@block.call(message)].flatten
|
176
|
+
return unless collecting?
|
139
177
|
keep message if status.include?(:keep)
|
140
|
-
if status.include?(:cancel)
|
141
|
-
cancel('Cancelled by block')
|
142
|
-
else
|
143
|
-
complete if done?
|
144
|
-
end
|
145
178
|
else
|
146
179
|
keep message
|
147
|
-
complete if done?
|
148
180
|
end
|
181
|
+
complete if done?
|
149
182
|
end
|
150
183
|
|
151
184
|
# Have we collected the required number of messages?
|
@@ -167,8 +200,8 @@ module RSMP
|
|
167
200
|
@condition.signal
|
168
201
|
end
|
169
202
|
|
170
|
-
#
|
171
|
-
# Check if
|
203
|
+
# An error occured upstream.
|
204
|
+
# Check if we should cancel.
|
172
205
|
def notify_error error, options={}
|
173
206
|
case error
|
174
207
|
when RSMP::SchemaError
|
@@ -197,7 +230,7 @@ module RSMP
|
|
197
230
|
end
|
198
231
|
|
199
232
|
# Abort collection
|
200
|
-
def cancel error
|
233
|
+
def cancel error=nil
|
201
234
|
@error = error
|
202
235
|
@status = :cancelled
|
203
236
|
do_stop
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RSMP
|
2
|
+
# Match a specific command responses
|
3
|
+
class CommandQuery < Query
|
4
|
+
# Match a return value item against a query
|
5
|
+
def match? item
|
6
|
+
return nil if @want['cCI'] && @want['cCI'] != item['cCI']
|
7
|
+
return nil if @want['n'] && @want['n'] != item['n']
|
8
|
+
if @want['v'].is_a? Regexp
|
9
|
+
return false if @want['v'] && item['v'] !~ @want['v']
|
10
|
+
else
|
11
|
+
return false if @want['v'] && item['v'] != @want['v']
|
12
|
+
end
|
13
|
+
true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RSMP
|
2
|
+
# Class for waiting for specific command responses
|
3
|
+
class CommandResponseCollector < StateCollector
|
4
|
+
def initialize proxy, want, options={}
|
5
|
+
super proxy, want, options.merge(
|
6
|
+
type: ['CommandResponse','MessageNotAck'],
|
7
|
+
title:'command response'
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def build_query want
|
12
|
+
CommandQuery.new want
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get items, in our case the return values
|
16
|
+
def get_items message
|
17
|
+
message.attributes['rvs'] || []
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RSMP
|
2
|
+
|
3
|
+
# Filter messages based on type, direction and component id.
|
4
|
+
# Used by Collectors.
|
5
|
+
class Filter
|
6
|
+
def initialize ingoing:true, outgoing:true, type:, component:nil
|
7
|
+
@ingoing = ingoing
|
8
|
+
@outgoing = outgoing
|
9
|
+
@type = type
|
10
|
+
@component = component
|
11
|
+
end
|
12
|
+
|
13
|
+
# Check a message against our match criteria
|
14
|
+
# Return true if there's a match, false if not
|
15
|
+
def accept? message
|
16
|
+
return false if message.direction == :in && @ingoing == false
|
17
|
+
return false if message.direction == :out && @outgoing == false
|
18
|
+
if @type
|
19
|
+
if @type.is_a? Array
|
20
|
+
return false unless @type.include? message.type
|
21
|
+
else
|
22
|
+
return false unless message.type == @type
|
23
|
+
end
|
24
|
+
end
|
25
|
+
if @component
|
26
|
+
return false if message.attributes['cId'] && message.attributes['cId'] != @component
|
27
|
+
end
|
28
|
+
true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
module RSMP
|
2
|
-
# Class for waiting for specific command responses
|
3
|
-
class CommandResponseMatcher < Matcher
|
4
|
-
def initialize proxy, want, options={}
|
5
|
-
super proxy, want, options.merge(
|
6
|
-
type: ['CommandResponse','MessageNotAck'],
|
7
|
-
title:'command response'
|
8
|
-
)
|
9
|
-
end
|
10
|
-
|
11
|
-
def build_query want
|
12
|
-
CommandQuery.new want
|
13
|
-
end
|
14
|
-
|
15
|
-
# Get items, in our case the return values
|
16
|
-
def get_items message
|
17
|
-
message.attributes['rvs']
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Base class for waiting for status updates or responses
|
22
|
-
class StatusUpdateOrResponseMatcher < Matcher
|
23
|
-
def initialize proxy, want, options={}
|
24
|
-
super proxy, want, options.merge
|
25
|
-
end
|
26
|
-
|
27
|
-
def build_query want
|
28
|
-
StatusQuery.new want
|
29
|
-
end
|
30
|
-
|
31
|
-
# Get items, in our case status values
|
32
|
-
def get_items message
|
33
|
-
message.attributes['sS']
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Class for waiting for specific status responses
|
38
|
-
class StatusResponseMatcher < StatusUpdateOrResponseMatcher
|
39
|
-
def initialize proxy, want, options={}
|
40
|
-
super proxy, want, options.merge(
|
41
|
-
type: ['StatusResponse','MessageNotAck'],
|
42
|
-
title: 'status response'
|
43
|
-
)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Class for waiting for specific status responses
|
48
|
-
class StatusUpdateMatcher < StatusUpdateOrResponseMatcher
|
49
|
-
def initialize proxy, want, options={}
|
50
|
-
super proxy, want, options.merge(
|
51
|
-
type: ['StatusUpdate','MessageNotAck'],
|
52
|
-
title:'status update'
|
53
|
-
)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# Class for waiting for an aggregated status response
|
58
|
-
class AggregatedStatusMatcher < Collector
|
59
|
-
def initialize proxy, options={}
|
60
|
-
required = { type: ['AggregatedStatus','MessageNotAck'], title: 'aggregated status' }
|
61
|
-
super proxy, options.merge(required)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|