rsmp 0.37.0 → 0.38.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/.devcontainer/devcontainer.json +22 -0
- data/.github/workflows/rubocop.yaml +17 -0
- data/.gitignore +5 -6
- data/.rubocop.yml +80 -0
- data/Gemfile +13 -1
- data/Gemfile.lock +34 -1
- data/Rakefile +3 -3
- data/lib/rsmp/cli.rb +147 -124
- data/lib/rsmp/collect/ack_collector.rb +8 -7
- data/lib/rsmp/collect/aggregated_status_collector.rb +4 -4
- data/lib/rsmp/collect/alarm_collector.rb +31 -23
- data/lib/rsmp/collect/alarm_matcher.rb +3 -3
- data/lib/rsmp/collect/collector/logging.rb +17 -0
- data/lib/rsmp/collect/collector/reporting.rb +44 -0
- data/lib/rsmp/collect/collector/status.rb +34 -0
- data/lib/rsmp/collect/collector.rb +69 -150
- data/lib/rsmp/collect/command_matcher.rb +19 -6
- data/lib/rsmp/collect/command_response_collector.rb +7 -7
- data/lib/rsmp/collect/distributor.rb +14 -11
- data/lib/rsmp/collect/filter.rb +31 -15
- data/lib/rsmp/collect/matcher.rb +7 -11
- data/lib/rsmp/collect/queue.rb +4 -4
- data/lib/rsmp/collect/receiver.rb +10 -12
- data/lib/rsmp/collect/state_collector.rb +116 -77
- data/lib/rsmp/collect/status_collector.rb +6 -6
- data/lib/rsmp/collect/status_matcher.rb +17 -7
- data/lib/rsmp/{alarm_state.rb → component/alarm_state.rb} +76 -37
- data/lib/rsmp/{component.rb → component/component.rb} +15 -15
- data/lib/rsmp/component/component_base.rb +89 -0
- data/lib/rsmp/component/component_proxy.rb +75 -0
- data/lib/rsmp/component/components.rb +63 -0
- data/lib/rsmp/convert/export/json_schema.rb +116 -110
- data/lib/rsmp/convert/import/yaml.rb +21 -18
- data/lib/rsmp/{rsmp.rb → helpers/clock.rb} +5 -6
- data/lib/rsmp/{deep_merge.rb → helpers/deep_merge.rb} +2 -1
- data/lib/rsmp/helpers/error.rb +71 -0
- data/lib/rsmp/{inspect.rb → helpers/inspect.rb} +6 -10
- data/lib/rsmp/log/archive.rb +98 -0
- data/lib/rsmp/log/colorization.rb +41 -0
- data/lib/rsmp/log/filtering.rb +54 -0
- data/lib/rsmp/log/logger.rb +206 -0
- data/lib/rsmp/{logging.rb → log/logging.rb} +5 -7
- data/lib/rsmp/message.rb +159 -148
- data/lib/rsmp/{node.rb → node/node.rb} +19 -17
- data/lib/rsmp/{protocol.rb → node/protocol.rb} +5 -3
- data/lib/rsmp/node/site/site.rb +195 -0
- data/lib/rsmp/node/supervisor/modules/configuration.rb +59 -0
- data/lib/rsmp/node/supervisor/modules/connection.rb +140 -0
- data/lib/rsmp/node/supervisor/modules/sites.rb +64 -0
- data/lib/rsmp/node/supervisor/supervisor.rb +72 -0
- data/lib/rsmp/{task.rb → node/task.rb} +12 -14
- data/lib/rsmp/proxy/modules/acknowledgements.rb +144 -0
- data/lib/rsmp/proxy/modules/receive.rb +119 -0
- data/lib/rsmp/proxy/modules/send.rb +76 -0
- data/lib/rsmp/proxy/modules/state.rb +25 -0
- data/lib/rsmp/proxy/modules/tasks.rb +105 -0
- data/lib/rsmp/proxy/modules/versions.rb +69 -0
- data/lib/rsmp/proxy/modules/watchdogs.rb +66 -0
- data/lib/rsmp/proxy/proxy.rb +199 -0
- data/lib/rsmp/proxy/site/modules/aggregated_status.rb +52 -0
- data/lib/rsmp/proxy/site/modules/alarms.rb +27 -0
- data/lib/rsmp/proxy/site/modules/commands.rb +31 -0
- data/lib/rsmp/proxy/site/modules/status.rb +110 -0
- data/lib/rsmp/proxy/site/site_proxy.rb +205 -0
- data/lib/rsmp/proxy/supervisor/modules/aggregated_status.rb +47 -0
- data/lib/rsmp/proxy/supervisor/modules/alarms.rb +73 -0
- data/lib/rsmp/proxy/supervisor/modules/commands.rb +53 -0
- data/lib/rsmp/proxy/supervisor/modules/status.rb +204 -0
- data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +178 -0
- data/lib/rsmp/tlc/detector_logic.rb +18 -34
- data/lib/rsmp/tlc/input_states.rb +126 -0
- data/lib/rsmp/tlc/modules/detector_logics.rb +50 -0
- data/lib/rsmp/tlc/modules/display.rb +78 -0
- data/lib/rsmp/tlc/modules/helpers.rb +41 -0
- data/lib/rsmp/tlc/modules/inputs.rb +173 -0
- data/lib/rsmp/tlc/modules/modes.rb +253 -0
- data/lib/rsmp/tlc/modules/outputs.rb +30 -0
- data/lib/rsmp/tlc/modules/plans.rb +218 -0
- data/lib/rsmp/tlc/modules/signal_groups.rb +109 -0
- data/lib/rsmp/tlc/modules/startup_sequence.rb +22 -0
- data/lib/rsmp/tlc/modules/system.rb +140 -0
- data/lib/rsmp/tlc/modules/traffic_data.rb +49 -0
- data/lib/rsmp/tlc/signal_group.rb +37 -41
- data/lib/rsmp/tlc/signal_plan.rb +14 -11
- data/lib/rsmp/tlc/signal_priority.rb +39 -35
- data/lib/rsmp/tlc/startup_sequence.rb +59 -0
- data/lib/rsmp/tlc/traffic_controller.rb +38 -1010
- data/lib/rsmp/tlc/traffic_controller_site.rb +58 -57
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +82 -48
- data/rsmp.gemspec +24 -31
- metadata +79 -139
- data/lib/rsmp/archive.rb +0 -76
- data/lib/rsmp/collect/message_matchers.rb +0 -0
- data/lib/rsmp/component_base.rb +0 -87
- data/lib/rsmp/component_proxy.rb +0 -57
- data/lib/rsmp/components.rb +0 -65
- data/lib/rsmp/error.rb +0 -71
- data/lib/rsmp/logger.rb +0 -216
- data/lib/rsmp/proxy.rb +0 -693
- data/lib/rsmp/site.rb +0 -188
- data/lib/rsmp/site_proxy.rb +0 -389
- data/lib/rsmp/supervisor.rb +0 -302
- data/lib/rsmp/supervisor_proxy.rb +0 -510
- data/lib/rsmp/tlc/inputs.rb +0 -134
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
module RSMP
|
|
2
2
|
# Class for waiting for specific command responses
|
|
3
3
|
class AlarmCollector < Collector
|
|
4
|
-
def initialize
|
|
4
|
+
def initialize(proxy, options = {})
|
|
5
5
|
@matcher = options[:matcher] || {}
|
|
6
|
-
super
|
|
6
|
+
super(proxy, options.merge(
|
|
7
7
|
filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: 'Alarm'),
|
|
8
|
-
title:'alarm'
|
|
9
|
-
)
|
|
8
|
+
title: 'alarm'
|
|
9
|
+
))
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return false
|
|
12
|
+
def acceptable?(message)
|
|
13
|
+
return false if super == false
|
|
14
|
+
return false unless fixed_attributes_match?(message)
|
|
15
|
+
return false unless rvs_attributes_match?(message)
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def fixed_attributes_match?(message)
|
|
23
|
+
%w[cId aCId aSp ack aS sS cat pri].each do |key|
|
|
18
24
|
want = @matcher[key]
|
|
19
25
|
got = message.attribute(key)
|
|
20
26
|
case want
|
|
@@ -24,26 +30,28 @@ module RSMP
|
|
|
24
30
|
return false if got != want
|
|
25
31
|
end
|
|
26
32
|
end
|
|
33
|
+
true
|
|
34
|
+
end
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
def rvs_attributes_match?(message)
|
|
37
|
+
return true unless @matcher['rvs']
|
|
38
|
+
|
|
39
|
+
matcher_rvs = @matcher['rvs']
|
|
40
|
+
message_rvs = message.attributes['rvs']
|
|
41
|
+
return false unless message_rvs
|
|
42
|
+
|
|
43
|
+
matcher_rvs.all? do |matcher_item|
|
|
44
|
+
message_rvs.any? do |message_item|
|
|
45
|
+
message_item['n'] == matcher_item['n'] && message_item['v'] == matcher_item['v']
|
|
38
46
|
end
|
|
39
47
|
end
|
|
40
|
-
true
|
|
41
48
|
end
|
|
42
49
|
|
|
50
|
+
public
|
|
51
|
+
|
|
43
52
|
# return a string that describes what we're collecting
|
|
44
53
|
def describe_matcher
|
|
45
|
-
"#{describe_num_and_type} #{
|
|
54
|
+
"#{describe_num_and_type} #{{ component: @options[:component] }.merge(@matcher).compact}"
|
|
46
55
|
end
|
|
47
|
-
|
|
48
56
|
end
|
|
49
|
-
end
|
|
57
|
+
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module RSMP
|
|
2
2
|
# Match a specific alarm
|
|
3
3
|
class AlarmMatcher < Matcher
|
|
4
|
-
|
|
5
|
-
def match? item
|
|
4
|
+
def match?(item)
|
|
6
5
|
return false if @want['n'] && @want['n'] != item['n']
|
|
6
|
+
|
|
7
7
|
if @want['v'].is_a? Regexp
|
|
8
8
|
return false if item['v'] !~ @want['v']
|
|
9
9
|
elsif @want['v']
|
|
@@ -12,4 +12,4 @@ module RSMP
|
|
|
12
12
|
true
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
|
-
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
class Collector
|
|
3
|
+
module Logging
|
|
4
|
+
def log_start
|
|
5
|
+
@distributor.log "#{identifier}: Waiting for #{describe_matcher}".strip, level: :collect
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def log_incomplete
|
|
9
|
+
@distributor.log "#{identifier}: #{describe_progress}", level: :collect
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def log_complete
|
|
13
|
+
@distributor.log "#{identifier}: Done", level: :collect
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
class Collector
|
|
3
|
+
# Progress reporting and description methods for collectors
|
|
4
|
+
module Reporting
|
|
5
|
+
# return a string describing the types of messages we're collecting
|
|
6
|
+
def describe_types
|
|
7
|
+
[@filter&.type].flatten.join('/')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# return a string that describes whe number of messages, and type of message we're collecting
|
|
11
|
+
def describe_num_and_type
|
|
12
|
+
if @num && @num > 1
|
|
13
|
+
"#{@num} #{describe_types}s"
|
|
14
|
+
else
|
|
15
|
+
describe_types
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# return a string that describes the attributes that we're looking for
|
|
20
|
+
def describe_matcher
|
|
21
|
+
h = { component: @filter&.component }.compact
|
|
22
|
+
if h.empty?
|
|
23
|
+
describe_num_and_type
|
|
24
|
+
else
|
|
25
|
+
"#{describe_num_and_type} #{h}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Build a string describing how far progress reached before timeout
|
|
30
|
+
def describe_progress
|
|
31
|
+
str = "#{@title.capitalize} #{identifier} "
|
|
32
|
+
str << "in response to #{@m_id} " if @m_id
|
|
33
|
+
str << "timed out after #{@timeout}s, "
|
|
34
|
+
str << "reaching #{@messages.size}/#{@num}"
|
|
35
|
+
str
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# get a short id in hex format, identifying ourself
|
|
39
|
+
def identifier
|
|
40
|
+
"Collect #{object_id.to_s(16)}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
class Collector
|
|
3
|
+
# Status predicate methods for collectors
|
|
4
|
+
module Status
|
|
5
|
+
def collecting?
|
|
6
|
+
@status == :collecting
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def ok?
|
|
10
|
+
@status == :ok
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def timeout?
|
|
14
|
+
@status == :timeout
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ready?
|
|
18
|
+
@status == :ready
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def cancelled?
|
|
22
|
+
@status == :cancelled
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ingoing?
|
|
26
|
+
@ingoing == true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def outgoing?
|
|
30
|
+
@outgoing == true
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
module RSMP
|
|
2
|
-
|
|
3
2
|
# Collects messages from a distributor.
|
|
4
3
|
# Can filter by message type, componet and direction.
|
|
5
4
|
# Wakes up the once the desired number of messages has been collected.
|
|
6
5
|
class Collector
|
|
7
6
|
include Receiver
|
|
7
|
+
include Status
|
|
8
|
+
include Reporting
|
|
9
|
+
include Logging
|
|
10
|
+
|
|
8
11
|
attr_reader :condition, :messages, :status, :error, :task, :m_id
|
|
9
12
|
|
|
10
|
-
def initialize
|
|
13
|
+
def initialize(distributor, options = {})
|
|
11
14
|
initialize_receiver distributor, filter: options[:filter]
|
|
12
15
|
@options = {
|
|
13
16
|
cancel: {
|
|
14
17
|
schema_error: true,
|
|
15
|
-
disconnect: false
|
|
18
|
+
disconnect: false
|
|
16
19
|
}
|
|
17
20
|
}.deep_merge options
|
|
18
21
|
@timeout = options[:timeout]
|
|
@@ -20,34 +23,31 @@ module RSMP
|
|
|
20
23
|
@m_id = options[:m_id]
|
|
21
24
|
@condition = Async::Notification.new
|
|
22
25
|
make_title options[:title]
|
|
23
|
-
|
|
26
|
+
|
|
24
27
|
if task
|
|
25
28
|
@task = task
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@task = distributor.task
|
|
31
|
-
end
|
|
29
|
+
elsif distributor.respond_to? 'task'
|
|
30
|
+
# if distributor is a Proxy, or some other object that implements task(),
|
|
31
|
+
# then try to get the task that way
|
|
32
|
+
@task = distributor.task
|
|
32
33
|
end
|
|
33
34
|
reset
|
|
34
35
|
end
|
|
35
36
|
|
|
36
|
-
def make_title
|
|
37
|
-
if title
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
def make_title(title)
|
|
38
|
+
@title = if title
|
|
39
|
+
title
|
|
40
|
+
elsif @filter
|
|
41
|
+
[@filter.type].flatten.join('/')
|
|
42
|
+
else
|
|
43
|
+
''
|
|
44
|
+
end
|
|
44
45
|
end
|
|
45
46
|
|
|
46
|
-
def use_task
|
|
47
|
+
def use_task(task)
|
|
47
48
|
@task = task
|
|
48
49
|
end
|
|
49
50
|
|
|
50
|
-
# Clear all matcher results
|
|
51
51
|
def reset
|
|
52
52
|
@messages = []
|
|
53
53
|
@error = nil
|
|
@@ -56,65 +56,31 @@ module RSMP
|
|
|
56
56
|
|
|
57
57
|
# Inspect formatter that shows the message we have collected
|
|
58
58
|
def inspect
|
|
59
|
-
"#<#{self.class.name}:#{
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# Is collection active?
|
|
63
|
-
def collecting?
|
|
64
|
-
@status == :collecting
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Is collection complete?
|
|
68
|
-
def ok?
|
|
69
|
-
@status == :ok
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Has collection timed out?
|
|
73
|
-
def timeout?
|
|
74
|
-
@status == :timeout
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Is collection ready to start?
|
|
78
|
-
def ready?
|
|
79
|
-
@status == :ready
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Has collection been cancelled?
|
|
83
|
-
def cancelled?
|
|
84
|
-
@status == :cancelled
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Want ingoing messages?
|
|
88
|
-
def ingoing?
|
|
89
|
-
@ingoing == true
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Want outgoing messages?
|
|
93
|
-
def outgoing?
|
|
94
|
-
@outgoing == true
|
|
59
|
+
"#<#{self.class.name}:#{object_id}, #{inspector(:@messages)}>"
|
|
95
60
|
end
|
|
96
61
|
|
|
97
62
|
# if an errors caused collection to abort, then raise it
|
|
98
63
|
# return self, so this can be tucked on to calls that return a collector
|
|
99
64
|
def ok!
|
|
100
65
|
raise @error if @error
|
|
66
|
+
|
|
101
67
|
self
|
|
102
68
|
end
|
|
103
69
|
|
|
104
70
|
# Collect message
|
|
105
71
|
# Will return once all messages have been collected, or timeout is reached
|
|
106
|
-
def collect
|
|
107
|
-
start
|
|
72
|
+
def collect(&)
|
|
73
|
+
start(&)
|
|
108
74
|
wait
|
|
109
75
|
@status
|
|
110
76
|
ensure
|
|
111
|
-
@distributor
|
|
77
|
+
@distributor&.remove_receiver self
|
|
112
78
|
end
|
|
113
79
|
|
|
114
80
|
# Collect message
|
|
115
81
|
# Returns the collected messages, or raise an exception in case of a time out.
|
|
116
|
-
def collect!
|
|
117
|
-
collect(&
|
|
82
|
+
def collect!(&)
|
|
83
|
+
collect(&)
|
|
118
84
|
ok!
|
|
119
85
|
@messages
|
|
120
86
|
end
|
|
@@ -141,40 +107,44 @@ module RSMP
|
|
|
141
107
|
def wait!
|
|
142
108
|
wait
|
|
143
109
|
raise @error if timeout?
|
|
110
|
+
|
|
144
111
|
@messages
|
|
145
112
|
end
|
|
146
113
|
|
|
147
114
|
# Start collection and return immediately
|
|
148
115
|
# You can later use wait() to wait for completion
|
|
149
|
-
def start
|
|
150
|
-
raise
|
|
116
|
+
def start(&block)
|
|
117
|
+
raise "Can't start collectimng unless ready (currently #{@status})" unless ready?
|
|
118
|
+
|
|
151
119
|
@block = block
|
|
152
|
-
raise ArgumentError
|
|
120
|
+
raise ArgumentError, 'Num, timeout or block must be provided' unless @num || @timeout || @block
|
|
121
|
+
|
|
153
122
|
reset
|
|
154
123
|
@status = :collecting
|
|
155
124
|
log_start
|
|
156
|
-
@distributor
|
|
125
|
+
@distributor&.add_receiver self
|
|
157
126
|
end
|
|
158
127
|
|
|
159
128
|
# Check if we receive a NotAck related to initiating request, identified by @m_id.
|
|
160
|
-
def reject_not_ack
|
|
129
|
+
def reject_not_ack(message)
|
|
161
130
|
return unless @m_id
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
131
|
+
|
|
132
|
+
return unless message.is_a?(MessageNotAck)
|
|
133
|
+
return unless message.attribute('oMId') == @m_id
|
|
134
|
+
|
|
135
|
+
m_id_short = RSMP::Message.shorten_m_id @m_id, 8
|
|
136
|
+
cancel RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected with '#{message.attribute('rea')}'")
|
|
137
|
+
@distributor.log "#{identifier}: cancelled due to a NotAck", level: :debug
|
|
138
|
+
true
|
|
170
139
|
end
|
|
171
140
|
|
|
172
|
-
# Handle message
|
|
173
|
-
def receive
|
|
141
|
+
# Handle message and return true if we're done collecting
|
|
142
|
+
def receive(message)
|
|
174
143
|
raise ArgumentError unless message
|
|
175
144
|
unless ready? || collecting?
|
|
176
|
-
raise
|
|
145
|
+
raise "can't process message when status is :#{@status}, title: #{@title}, desc: #{describe}"
|
|
177
146
|
end
|
|
147
|
+
|
|
178
148
|
if perform_match message
|
|
179
149
|
if done?
|
|
180
150
|
complete
|
|
@@ -185,17 +155,17 @@ module RSMP
|
|
|
185
155
|
@status
|
|
186
156
|
end
|
|
187
157
|
|
|
188
|
-
def describe
|
|
189
|
-
end
|
|
158
|
+
def describe; end
|
|
190
159
|
|
|
191
160
|
# Match message against our collection criteria
|
|
192
|
-
def perform_match
|
|
161
|
+
def perform_match(message)
|
|
193
162
|
return false if reject_not_ack(message)
|
|
194
163
|
return false unless acceptable?(message)
|
|
195
|
-
|
|
164
|
+
|
|
196
165
|
if @block
|
|
197
166
|
status = [@block.call(message)].flatten
|
|
198
167
|
return unless collecting?
|
|
168
|
+
|
|
199
169
|
keep message if status.include?(:keep)
|
|
200
170
|
else
|
|
201
171
|
keep message
|
|
@@ -227,9 +197,8 @@ module RSMP
|
|
|
227
197
|
@condition.signal
|
|
228
198
|
end
|
|
229
199
|
|
|
230
|
-
#
|
|
231
|
-
|
|
232
|
-
def receive_error error, options={}
|
|
200
|
+
# Handle upstream error
|
|
201
|
+
def receive_error(error, options = {})
|
|
233
202
|
case error
|
|
234
203
|
when RSMP::SchemaError
|
|
235
204
|
receive_schema_error error, options
|
|
@@ -239,93 +208,43 @@ module RSMP
|
|
|
239
208
|
end
|
|
240
209
|
|
|
241
210
|
# Cancel if we received e schema error for a message type we're collecting
|
|
242
|
-
def receive_schema_error
|
|
243
|
-
return unless @options.dig(:cancel
|
|
211
|
+
def receive_schema_error(error, options)
|
|
212
|
+
return unless @options.dig(:cancel, :schema_error)
|
|
213
|
+
|
|
244
214
|
message = options[:message]
|
|
245
215
|
return unless message
|
|
216
|
+
|
|
246
217
|
klass = message.class.name.split('::').last
|
|
247
|
-
return unless @filter&.type
|
|
218
|
+
return unless @filter&.type.nil? || [@filter&.type].flatten.include?(klass)
|
|
219
|
+
|
|
248
220
|
@distributor.log "#{identifier}: cancelled due to schema error in #{klass} #{message.m_id_short}", level: :debug
|
|
249
221
|
cancel error
|
|
250
222
|
end
|
|
251
223
|
|
|
252
|
-
# Cancel if we received e
|
|
253
|
-
def receive_disconnect
|
|
254
|
-
return unless @options.dig(:cancel
|
|
255
|
-
|
|
224
|
+
# Cancel if we received e notifiction about a disconnect
|
|
225
|
+
def receive_disconnect(error, _options)
|
|
226
|
+
return unless @options.dig(:cancel, :disconnect)
|
|
227
|
+
|
|
228
|
+
@distributor.log "#{identifier}: cancelled due to a connection error: #{error}", level: :debug
|
|
256
229
|
cancel error
|
|
257
230
|
end
|
|
258
231
|
|
|
259
232
|
# Abort collection
|
|
260
|
-
def cancel
|
|
233
|
+
def cancel(error = nil)
|
|
261
234
|
@error = error
|
|
262
235
|
@status = :cancelled
|
|
263
236
|
do_stop
|
|
264
237
|
end
|
|
265
238
|
|
|
266
239
|
# Store a message in the result array
|
|
267
|
-
def keep
|
|
240
|
+
def keep(message)
|
|
268
241
|
@messages << message
|
|
269
242
|
end
|
|
270
243
|
|
|
271
244
|
# Check a message against our match criteria
|
|
272
245
|
# Return true if there's a match, false if not
|
|
273
|
-
def acceptable?
|
|
274
|
-
@filter
|
|
246
|
+
def acceptable?(message)
|
|
247
|
+
@filter.nil? || @filter.accept?(message)
|
|
275
248
|
end
|
|
276
|
-
|
|
277
|
-
# return a string describing the types of messages we're collecting
|
|
278
|
-
def describe_types
|
|
279
|
-
[@filter&.type].flatten.join('/')
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
# return a string that describes whe number of messages, and type of message we're collecting
|
|
283
|
-
def describe_num_and_type
|
|
284
|
-
if @num && @num > 1
|
|
285
|
-
"#{@num} #{describe_types}s"
|
|
286
|
-
else
|
|
287
|
-
describe_types
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
# return a string that describes the attributes that we're looking for
|
|
292
|
-
def describe_matcher
|
|
293
|
-
h = {component: @filter&.component}.compact
|
|
294
|
-
if h.empty?
|
|
295
|
-
describe_num_and_type
|
|
296
|
-
else
|
|
297
|
-
"#{describe_num_and_type} #{h}"
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
# Build a string describing how how progress reached before timeout
|
|
302
|
-
def describe_progress
|
|
303
|
-
str = "#{@title.capitalize} #{identifier} "
|
|
304
|
-
str << "in response to #{@m_id} " if @m_id
|
|
305
|
-
str << "timed out after #{@timeout}s, "
|
|
306
|
-
str << "reaching #{@messages.size}/#{@num}"
|
|
307
|
-
str
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
# log when we start collecting
|
|
311
|
-
def log_start
|
|
312
|
-
@distributor.log "#{identifier}: Waiting for #{describe_matcher}".strip, level: :collect
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
# log current progress
|
|
316
|
-
def log_incomplete
|
|
317
|
-
@distributor.log "#{identifier}: #{describe_progress}", level: :collect
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
# log when we end collecting
|
|
321
|
-
def log_complete
|
|
322
|
-
@distributor.log "#{identifier}: Done", level: :collect
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
# get a short id in hex format, identifying ourself
|
|
326
|
-
def identifier
|
|
327
|
-
"Collect #{self.object_id.to_s(16)}"
|
|
328
|
-
end
|
|
329
|
-
|
|
330
249
|
end
|
|
331
|
-
end
|
|
250
|
+
end
|
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
module RSMP
|
|
2
|
-
#
|
|
2
|
+
# Class for matching a command
|
|
3
3
|
class CommandMatcher < Matcher
|
|
4
|
-
|
|
5
|
-
def match? item
|
|
4
|
+
def match_code?(item)
|
|
6
5
|
return nil if @want['cCI'] && @want['cCI'] != item['cCI']
|
|
7
6
|
return nil if @want['n'] && @want['n'] != item['n']
|
|
7
|
+
|
|
8
|
+
true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def match_value?(item)
|
|
12
|
+
return true unless @want['v']
|
|
13
|
+
|
|
8
14
|
if @want['v'].is_a? Regexp
|
|
9
|
-
return false if
|
|
10
|
-
|
|
11
|
-
return false
|
|
15
|
+
return false if item['v'] !~ @want['v']
|
|
16
|
+
elsif item['v'] != @want['v']
|
|
17
|
+
return false
|
|
12
18
|
end
|
|
13
19
|
true
|
|
14
20
|
end
|
|
21
|
+
|
|
22
|
+
def match?(item)
|
|
23
|
+
code_match = match_code?(item)
|
|
24
|
+
return code_match if code_match.nil?
|
|
25
|
+
|
|
26
|
+
match_value?(item)
|
|
27
|
+
end
|
|
15
28
|
end
|
|
16
29
|
end
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
module RSMP
|
|
2
2
|
# Class for waiting for specific command responses
|
|
3
3
|
class CommandResponseCollector < StateCollector
|
|
4
|
-
def initialize
|
|
5
|
-
super
|
|
4
|
+
def initialize(proxy, want, options = {})
|
|
5
|
+
super(proxy, want, options.merge(
|
|
6
6
|
filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: 'CommandResponse'),
|
|
7
|
-
title:'command response'
|
|
8
|
-
)
|
|
7
|
+
title: 'command response'
|
|
8
|
+
))
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def build_matcher
|
|
11
|
+
def build_matcher(want)
|
|
12
12
|
CommandMatcher.new want
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# Get items, in our case the return values
|
|
16
|
-
def get_items
|
|
16
|
+
def get_items(message)
|
|
17
17
|
message.attributes['rvs'] || []
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
|
-
end
|
|
20
|
+
end
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
# Distributes messages to receivers
|
|
2
|
-
|
|
3
1
|
module RSMP
|
|
2
|
+
# Class which distributes messages to receivers
|
|
4
3
|
module Distributor
|
|
5
4
|
attr_reader :receivers
|
|
6
5
|
|
|
7
6
|
include Inspect
|
|
8
7
|
|
|
9
8
|
def inspect
|
|
10
|
-
"#<#{self.class.name}:#{
|
|
9
|
+
"#<#{self.class.name}:#{object_id}, #{inspector(:@receivers)}>"
|
|
11
10
|
end
|
|
12
11
|
|
|
13
12
|
def initialize_distributor
|
|
@@ -16,12 +15,13 @@ module RSMP
|
|
|
16
15
|
@deferred_messages = []
|
|
17
16
|
end
|
|
18
17
|
|
|
19
|
-
def clear_deferred_distribution
|
|
18
|
+
def clear_deferred_distribution
|
|
20
19
|
@deferred_messages = []
|
|
21
20
|
end
|
|
22
21
|
|
|
23
|
-
def with_deferred_distribution
|
|
24
|
-
was
|
|
22
|
+
def with_deferred_distribution
|
|
23
|
+
was = @defer_distribution
|
|
24
|
+
@defer_distribution = true
|
|
25
25
|
yield
|
|
26
26
|
distribute_queued
|
|
27
27
|
ensure
|
|
@@ -35,18 +35,21 @@ module RSMP
|
|
|
35
35
|
@deferred_messages = []
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def add_receiver
|
|
38
|
+
def add_receiver(receiver)
|
|
39
39
|
raise ArgumentError unless receiver
|
|
40
|
+
|
|
40
41
|
@receivers << receiver unless @receivers.include? receiver
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
def remove_receiver
|
|
44
|
+
def remove_receiver(receiver)
|
|
44
45
|
raise ArgumentError unless receiver
|
|
46
|
+
|
|
45
47
|
@receivers.delete receiver
|
|
46
48
|
end
|
|
47
49
|
|
|
48
|
-
def distribute
|
|
50
|
+
def distribute(message)
|
|
49
51
|
raise ArgumentError unless message
|
|
52
|
+
|
|
50
53
|
if @defer_distribution
|
|
51
54
|
@deferred_messages << message
|
|
52
55
|
else
|
|
@@ -54,11 +57,11 @@ module RSMP
|
|
|
54
57
|
end
|
|
55
58
|
end
|
|
56
59
|
|
|
57
|
-
def distribute_immediately
|
|
60
|
+
def distribute_immediately(message)
|
|
58
61
|
@receivers.each { |receiver| receiver.receive message }
|
|
59
62
|
end
|
|
60
63
|
|
|
61
|
-
def distribute_error
|
|
64
|
+
def distribute_error(error, options = {})
|
|
62
65
|
@receivers.each { |receiver| receiver.receive_error error, options }
|
|
63
66
|
end
|
|
64
67
|
end
|