rsmp 0.37.0 → 0.39.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 +69 -0
- data/.tool-versions +1 -1
- data/Gemfile +14 -1
- data/Gemfile.lock +64 -29
- data/Rakefile +3 -3
- data/lib/rsmp/cli.rb +148 -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 +6 -6
- data/lib/rsmp/collect/collector/logging.rb +18 -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 +9 -13
- data/lib/rsmp/collect/queue.rb +7 -7
- data/lib/rsmp/collect/receiver.rb +11 -15
- 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 +15 -4
- data/lib/rsmp/{alarm_state.rb → component/alarm_state.rb} +76 -38
- data/lib/rsmp/{component.rb → component/component.rb} +15 -15
- data/lib/rsmp/component/component_base.rb +88 -0
- data/lib/rsmp/component/component_proxy.rb +75 -0
- data/lib/rsmp/component/components.rb +62 -0
- data/lib/rsmp/convert/export/json_schema.rb +118 -110
- data/lib/rsmp/convert/import/yaml.rb +22 -18
- data/lib/rsmp/{rsmp.rb → helpers/clock.rb} +8 -11
- data/lib/rsmp/{deep_merge.rb → helpers/deep_merge.rb} +3 -1
- data/lib/rsmp/helpers/error.rb +72 -0
- data/lib/rsmp/helpers/inspect.rb +41 -0
- data/lib/rsmp/log/archive.rb +97 -0
- data/lib/rsmp/log/colorization.rb +41 -0
- data/lib/rsmp/log/filtering.rb +54 -0
- data/lib/rsmp/log/logger.rb +207 -0
- data/lib/rsmp/{logging.rb → log/logging.rb} +6 -7
- data/lib/rsmp/message.rb +185 -148
- data/lib/rsmp/{node.rb → node/node.rb} +20 -19
- data/lib/rsmp/{protocol.rb → node/protocol.rb} +6 -3
- data/lib/rsmp/node/site/site.rb +192 -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 +69 -0
- data/lib/rsmp/{task.rb → node/task.rb} +13 -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 +197 -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 +204 -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 +177 -0
- data/lib/rsmp/tlc/detector_logic.rb +19 -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 +38 -41
- data/lib/rsmp/tlc/signal_plan.rb +14 -11
- data/lib/rsmp/tlc/signal_priority.rb +40 -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/inspect.rb +0 -46
- 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
data/lib/rsmp/message.rb
CHANGED
|
@@ -2,72 +2,68 @@ require 'rsmp_schema'
|
|
|
2
2
|
|
|
3
3
|
# rsmp messages
|
|
4
4
|
module RSMP
|
|
5
|
+
# Base RSMP message class used to represent parsed and built messages.
|
|
5
6
|
class Message
|
|
6
7
|
include Inspect
|
|
7
8
|
|
|
8
|
-
attr_reader :now, :attributes, :out
|
|
9
|
-
attr_reader :timestamp # this is an internal timestamp recording when we receive/send
|
|
9
|
+
attr_reader :now, :attributes, :out, :timestamp # this is an internal timestamp recording when we receive/send
|
|
10
10
|
attr_accessor :json, :direction
|
|
11
11
|
|
|
12
12
|
def self.make_m_id
|
|
13
|
-
SecureRandom.uuid
|
|
13
|
+
SecureRandom.uuid
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def self.parse_attributes
|
|
16
|
+
def self.parse_attributes(json)
|
|
17
17
|
raise ArgumentError unless json
|
|
18
|
+
|
|
18
19
|
JSON.parse json
|
|
19
20
|
rescue JSON::ParserError
|
|
20
21
|
raise InvalidPacket, bin_to_chars(json)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
def self.build
|
|
24
|
+
def self.build(attributes, json)
|
|
24
25
|
validate_message_type attributes
|
|
25
|
-
|
|
26
|
-
when "MessageAck"
|
|
27
|
-
message = MessageAck.new attributes
|
|
28
|
-
when "MessageNotAck"
|
|
29
|
-
message = MessageNotAck.new attributes
|
|
30
|
-
when "Version"
|
|
31
|
-
message = Version.new attributes
|
|
32
|
-
when "AggregatedStatus"
|
|
33
|
-
message = AggregatedStatus.new attributes
|
|
34
|
-
when "AggregatedStatusRequest"
|
|
35
|
-
message = AggregatedStatusRequest.new attributes
|
|
36
|
-
when "Watchdog"
|
|
37
|
-
message = Watchdog.new attributes
|
|
38
|
-
when "Alarm"
|
|
39
|
-
message = self.build_alarm attributes
|
|
40
|
-
when "CommandRequest"
|
|
41
|
-
message = CommandRequest.new attributes
|
|
42
|
-
when "CommandResponse"
|
|
43
|
-
message = CommandResponse.new attributes
|
|
44
|
-
when "StatusRequest"
|
|
45
|
-
message = StatusRequest.new attributes
|
|
46
|
-
when "StatusResponse"
|
|
47
|
-
message = StatusResponse.new attributes
|
|
48
|
-
when "StatusSubscribe"
|
|
49
|
-
message = StatusSubscribe.new attributes
|
|
50
|
-
when "StatusUnsubscribe"
|
|
51
|
-
message = StatusUnsubscribe.new attributes
|
|
52
|
-
when "StatusUpdate"
|
|
53
|
-
message = StatusUpdate.new attributes
|
|
54
|
-
else
|
|
55
|
-
message = Unknown.new attributes
|
|
56
|
-
end
|
|
26
|
+
message = create_message_instance(attributes)
|
|
57
27
|
message.json = json
|
|
58
28
|
message.direction = :in
|
|
59
29
|
message
|
|
60
30
|
end
|
|
61
31
|
|
|
62
|
-
def self.
|
|
63
|
-
|
|
32
|
+
def self.message_types
|
|
33
|
+
{
|
|
34
|
+
'MessageAck' => MessageAck,
|
|
35
|
+
'MessageNotAck' => MessageNotAck,
|
|
36
|
+
'Version' => Version,
|
|
37
|
+
'AggregatedStatus' => AggregatedStatus,
|
|
38
|
+
'AggregatedStatusRequest' => AggregatedStatusRequest,
|
|
39
|
+
'Watchdog' => Watchdog,
|
|
40
|
+
'CommandRequest' => CommandRequest,
|
|
41
|
+
'CommandResponse' => CommandResponse,
|
|
42
|
+
'StatusRequest' => StatusRequest,
|
|
43
|
+
'StatusResponse' => StatusResponse,
|
|
44
|
+
'StatusSubscribe' => StatusSubscribe,
|
|
45
|
+
'StatusUnsubscribe' => StatusUnsubscribe,
|
|
46
|
+
'StatusUpdate' => StatusUpdate
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.create_message_instance(attributes)
|
|
51
|
+
type = attributes['type']
|
|
52
|
+
return build_alarm(attributes) if type == 'Alarm'
|
|
53
|
+
|
|
54
|
+
klass = message_types[type] || Unknown
|
|
55
|
+
klass.new(attributes)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.build_alarm(attributes)
|
|
59
|
+
case attributes['aSp']
|
|
64
60
|
when /^Issue$/i
|
|
65
61
|
AlarmIssue.new attributes
|
|
66
62
|
when /^Request$/i
|
|
67
63
|
AlarmRequest.new attributes
|
|
68
64
|
when /^Acknowledge$/i
|
|
69
65
|
if attributes['ack'] =~ /^acknowledged$/i
|
|
70
|
-
|
|
66
|
+
AlarmAcknowledged.new attributes
|
|
71
67
|
else
|
|
72
68
|
AlarmAcknowledge.new attributes
|
|
73
69
|
end
|
|
@@ -87,84 +83,97 @@ module RSMP
|
|
|
87
83
|
end
|
|
88
84
|
|
|
89
85
|
def type
|
|
90
|
-
@attributes[
|
|
86
|
+
@attributes['type']
|
|
91
87
|
end
|
|
92
88
|
|
|
93
89
|
def m_id
|
|
94
|
-
@attributes[
|
|
90
|
+
@attributes['mId']
|
|
95
91
|
end
|
|
96
92
|
|
|
97
|
-
def self.shorten_m_id
|
|
98
|
-
m_id[0..length-1]
|
|
93
|
+
def self.shorten_m_id(m_id, length = 4)
|
|
94
|
+
m_id[0..(length - 1)]
|
|
99
95
|
end
|
|
100
96
|
|
|
101
97
|
def m_id_short
|
|
102
|
-
Message.shorten_m_id @attributes[
|
|
98
|
+
Message.shorten_m_id @attributes['mId']
|
|
103
99
|
end
|
|
104
100
|
|
|
105
|
-
def attribute
|
|
106
|
-
unless @attributes.key? key #
|
|
107
|
-
maybe = @attributes.find { |k,
|
|
108
|
-
if maybe
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
end
|
|
101
|
+
def attribute(key)
|
|
102
|
+
unless @attributes.key? key # NOTE: that this is not the same as @attributes[key] when
|
|
103
|
+
maybe = @attributes.find { |k, _v| k.downcase == key.downcase }
|
|
104
|
+
raise MissingAttribute, "attribute '#{maybe.first}' should be named '#{key}'" if maybe
|
|
105
|
+
|
|
106
|
+
raise MissingAttribute, "missing attribute '#{key}'"
|
|
107
|
+
|
|
113
108
|
end
|
|
114
109
|
@attributes[key]
|
|
115
110
|
end
|
|
116
111
|
|
|
117
|
-
def self.bin_to_chars(
|
|
118
|
-
out =
|
|
112
|
+
def self.bin_to_chars(str)
|
|
113
|
+
out = str.gsub(/[^[:print:]]/i, '.')
|
|
119
114
|
max = 120
|
|
120
115
|
if out.size <= max
|
|
121
116
|
out
|
|
122
117
|
else
|
|
123
|
-
mid =
|
|
124
|
-
length = (max-mid.size)/2 - 1
|
|
125
|
-
"#{out[0..length]} ... #{out[-length-1
|
|
118
|
+
mid = ' ... '
|
|
119
|
+
length = ((max - mid.size) / 2) - 1
|
|
120
|
+
"#{out[0..length]} ... #{out[(-length - 1)..]}"
|
|
126
121
|
end
|
|
127
122
|
end
|
|
128
123
|
|
|
129
|
-
def self.validate_message_type
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
raise MalformedMessage.new("'mType' must be 'rSMsg', got '#{attributes["mType"]}'") unless attributes["mType"] == "rSMsg"
|
|
134
|
-
raise MalformedMessage.new("'type' is missing") unless attributes["type"]
|
|
135
|
-
raise MalformedMessage.new("'type' must be a String, got #{attributes["type"].class}") unless attributes["type"].is_a? String
|
|
124
|
+
def self.validate_message_type(attributes)
|
|
125
|
+
validate_attributes_structure(attributes)
|
|
126
|
+
validate_mtype_field(attributes)
|
|
127
|
+
validate_type_field(attributes)
|
|
136
128
|
end
|
|
137
129
|
|
|
138
|
-
def
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
def self.validate_attributes_structure(attributes)
|
|
131
|
+
raise MalformedMessage, "JSON must be a Hash, got #{attributes.class} " unless attributes.is_a?(Hash)
|
|
132
|
+
end
|
|
141
133
|
|
|
142
|
-
|
|
134
|
+
def self.validate_mtype_field(attributes)
|
|
135
|
+
mtype = attributes['mType']
|
|
136
|
+
raise MalformedMessage, "'mType' is missing" unless mtype
|
|
137
|
+
raise MalformedMessage, "'mType' must be a String, got #{mtype.class}" unless mtype.is_a?(String)
|
|
138
|
+
raise MalformedMessage, "'mType' must be 'rSMsg', got '#{mtype}'" unless mtype == 'rSMsg'
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def self.validate_type_field(attributes)
|
|
142
|
+
type = attributes['type']
|
|
143
|
+
raise MalformedMessage, "'type' is missing" unless type
|
|
144
|
+
raise MalformedMessage, "'type' must be a String, got #{type.class}" unless type.is_a?(String)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def initialize(attributes = {})
|
|
148
|
+
@timestamp = Time.now # this timestamp is for internal use, and does not use the clock
|
|
149
|
+
# in the node, which can be set by an rsmp supervisor
|
|
150
|
+
|
|
151
|
+
@attributes = { 'mType' => 'rSMsg' }.merge attributes
|
|
143
152
|
|
|
144
153
|
ensure_message_id
|
|
145
154
|
end
|
|
146
155
|
|
|
147
156
|
def ensure_message_id
|
|
148
157
|
# if message id is empty, generate a new one
|
|
149
|
-
@attributes[
|
|
158
|
+
@attributes['mId'] ||= Message.make_m_id
|
|
150
159
|
end
|
|
151
160
|
|
|
152
|
-
def validate
|
|
161
|
+
def validate(schemas)
|
|
153
162
|
errors = RSMP::Schema.validate attributes, schemas
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
return unless errors
|
|
164
|
+
|
|
165
|
+
error_string = errors.map { |item| item.reject { |e| e == '' } }.compact.join(', ').strip
|
|
166
|
+
err = SchemaError.new error_string.to_s
|
|
167
|
+
err.schemas = schemas
|
|
168
|
+
raise err
|
|
160
169
|
end
|
|
161
170
|
|
|
162
|
-
def validate_type
|
|
163
|
-
@attributes[
|
|
171
|
+
def validate_type?
|
|
172
|
+
@attributes['mType'] == 'rSMsg'
|
|
164
173
|
end
|
|
165
174
|
|
|
166
|
-
def validate_id
|
|
167
|
-
|
|
175
|
+
def validate_id?
|
|
176
|
+
!(@attributes['mId'] =~ /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}/i).nil?
|
|
168
177
|
end
|
|
169
178
|
|
|
170
179
|
def valid?
|
|
@@ -181,165 +190,186 @@ module RSMP
|
|
|
181
190
|
}
|
|
182
191
|
@json = JSON.generate @attributes, options
|
|
183
192
|
end
|
|
184
|
-
|
|
185
193
|
end
|
|
186
194
|
|
|
195
|
+
# Represents a malformed message with invalid attributes.
|
|
187
196
|
class Malformed < Message
|
|
188
|
-
|
|
197
|
+
# rubocop:disable Lint/MissingSuper
|
|
198
|
+
def initialize(attributes = {})
|
|
189
199
|
# don't call super, just copy (potentially invalid) attributes
|
|
190
200
|
@attributes = {}
|
|
191
201
|
@invalid_attributes = attributes
|
|
192
202
|
end
|
|
203
|
+
# rubocop:enable Lint/MissingSuper
|
|
193
204
|
end
|
|
194
205
|
|
|
206
|
+
# Version message, lists supported versions and SXL information.
|
|
195
207
|
class Version < Message
|
|
196
|
-
def initialize
|
|
208
|
+
def initialize(attributes = {})
|
|
197
209
|
super({
|
|
198
|
-
|
|
210
|
+
'type' => 'Version'
|
|
199
211
|
}.merge attributes)
|
|
200
212
|
end
|
|
201
213
|
|
|
202
214
|
def versions
|
|
203
|
-
attribute(
|
|
215
|
+
attribute('RSMP').map { |item| item['vers'] }
|
|
204
216
|
end
|
|
205
217
|
end
|
|
206
218
|
|
|
219
|
+
# Unknown message type wrapper.
|
|
207
220
|
class Unknown < Message
|
|
208
221
|
end
|
|
209
222
|
|
|
223
|
+
# AggregatedStatus message type.
|
|
210
224
|
class AggregatedStatus < Message
|
|
211
|
-
def initialize
|
|
225
|
+
def initialize(attributes = {})
|
|
212
226
|
super({
|
|
213
|
-
|
|
227
|
+
'type' => 'AggregatedStatus'
|
|
214
228
|
}.merge attributes)
|
|
215
229
|
end
|
|
216
230
|
end
|
|
217
231
|
|
|
232
|
+
# AggregatedStatusRequest message type.
|
|
218
233
|
class AggregatedStatusRequest < Message
|
|
219
|
-
def initialize
|
|
234
|
+
def initialize(attributes = {})
|
|
220
235
|
super({
|
|
221
|
-
|
|
236
|
+
'type' => 'AggregatedStatusRequest'
|
|
222
237
|
}.merge attributes)
|
|
223
238
|
end
|
|
224
239
|
end
|
|
225
240
|
|
|
241
|
+
# Alarm base message type.
|
|
226
242
|
class Alarm < Message
|
|
227
|
-
def initialize
|
|
243
|
+
def initialize(attributes = {})
|
|
228
244
|
super({
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
245
|
+
'type' => 'Alarm',
|
|
246
|
+
'ntsOId' => '',
|
|
247
|
+
'xNId' => '',
|
|
248
|
+
'xACId' => '',
|
|
249
|
+
'xNACId' => ''
|
|
234
250
|
}.merge attributes)
|
|
235
251
|
end
|
|
236
252
|
|
|
237
|
-
def differ?
|
|
238
|
-
%w
|
|
253
|
+
def differ?(from)
|
|
254
|
+
%w[aSp aCId ack aS sS aTs cat pri].each do |key|
|
|
239
255
|
return true if attribute(key).downcase != from.attribute(key).downcase
|
|
240
256
|
end
|
|
241
257
|
return true if attribute('rvs') != from.attribute('rvs')
|
|
258
|
+
|
|
242
259
|
false
|
|
243
260
|
end
|
|
244
261
|
end
|
|
245
262
|
|
|
263
|
+
# Alarm issue specialization.
|
|
246
264
|
class AlarmIssue < Alarm
|
|
247
|
-
def initialize
|
|
265
|
+
def initialize(attributes = {})
|
|
248
266
|
super({
|
|
249
|
-
|
|
267
|
+
'aSp' => 'Issue'
|
|
250
268
|
}.merge attributes)
|
|
251
269
|
end
|
|
252
270
|
end
|
|
253
271
|
|
|
272
|
+
# Alarm request specialization.
|
|
254
273
|
class AlarmRequest < Alarm
|
|
255
|
-
def initialize
|
|
274
|
+
def initialize(attributes = {})
|
|
256
275
|
super({
|
|
257
|
-
|
|
276
|
+
'aSp' => 'Request'
|
|
258
277
|
}.merge attributes)
|
|
259
278
|
end
|
|
260
279
|
end
|
|
261
280
|
|
|
281
|
+
# Alarm acknowledge message.
|
|
262
282
|
class AlarmAcknowledge < Alarm
|
|
263
|
-
def initialize
|
|
283
|
+
def initialize(attributes = {})
|
|
264
284
|
super({
|
|
265
|
-
|
|
285
|
+
'aSp' => 'Acknowledge'
|
|
266
286
|
}.merge attributes)
|
|
267
287
|
end
|
|
268
288
|
end
|
|
269
289
|
|
|
290
|
+
# Alarm acknowledged (acknowledged state) message.
|
|
270
291
|
class AlarmAcknowledged < Alarm
|
|
271
|
-
def initialize
|
|
292
|
+
def initialize(attributes = {})
|
|
272
293
|
super({
|
|
273
|
-
|
|
274
|
-
|
|
294
|
+
'aSp' => 'Acknowledge',
|
|
295
|
+
'ack' => 'acknowledged'
|
|
275
296
|
}.merge attributes)
|
|
276
297
|
end
|
|
277
298
|
end
|
|
299
|
+
|
|
300
|
+
# Alarm suspend message.
|
|
278
301
|
class AlarmSuspend < Alarm
|
|
279
|
-
def initialize
|
|
302
|
+
def initialize(attributes = {})
|
|
280
303
|
super({
|
|
281
|
-
|
|
304
|
+
'aSp' => 'Suspend'
|
|
282
305
|
}.merge attributes)
|
|
283
306
|
end
|
|
284
307
|
end
|
|
285
308
|
|
|
309
|
+
# Alarm suspended (suspended state) message.
|
|
286
310
|
class AlarmSuspended < Alarm
|
|
287
|
-
def initialize
|
|
311
|
+
def initialize(attributes = {})
|
|
288
312
|
super({
|
|
289
|
-
|
|
290
|
-
|
|
313
|
+
'aSp' => 'Suspend',
|
|
314
|
+
'sS' => 'Suspended'
|
|
291
315
|
}.merge attributes)
|
|
292
316
|
end
|
|
293
317
|
end
|
|
294
318
|
|
|
319
|
+
# Alarm resume message.
|
|
295
320
|
class AlarmResume < Alarm
|
|
296
|
-
def initialize
|
|
321
|
+
def initialize(attributes = {})
|
|
297
322
|
super({
|
|
298
|
-
|
|
323
|
+
'aSp' => 'Resume'
|
|
299
324
|
}.merge attributes)
|
|
300
325
|
end
|
|
301
326
|
end
|
|
302
327
|
|
|
328
|
+
# Alarm resumed (not suspended) message.
|
|
303
329
|
class AlarmResumed < Alarm
|
|
304
|
-
def initialize
|
|
330
|
+
def initialize(attributes = {})
|
|
305
331
|
super({
|
|
306
|
-
|
|
307
|
-
|
|
332
|
+
'aSp' => 'Suspend',
|
|
333
|
+
'sS' => 'notSuspended'
|
|
308
334
|
}.merge attributes)
|
|
309
335
|
end
|
|
310
336
|
end
|
|
311
337
|
|
|
338
|
+
# Watchdog message type.
|
|
312
339
|
class Watchdog < Message
|
|
313
|
-
def initialize
|
|
340
|
+
def initialize(attributes = {})
|
|
314
341
|
super({
|
|
315
|
-
|
|
342
|
+
'type' => 'Watchdog'
|
|
316
343
|
}.merge attributes)
|
|
317
344
|
end
|
|
318
345
|
end
|
|
319
346
|
|
|
347
|
+
# Base class for acking messages (MessageAck / MessageNotAck).
|
|
320
348
|
class MessageAcking < Message
|
|
321
349
|
attr_reader :original
|
|
322
350
|
|
|
323
|
-
def self.build_from
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
351
|
+
def self.build_from(message)
|
|
352
|
+
new({
|
|
353
|
+
'oMId' => message.attributes['mId']
|
|
354
|
+
})
|
|
327
355
|
end
|
|
328
356
|
|
|
329
|
-
def original=
|
|
357
|
+
def original=(message)
|
|
330
358
|
raise InvalidArgument unless message
|
|
359
|
+
|
|
331
360
|
@original = message
|
|
332
361
|
end
|
|
333
362
|
|
|
334
|
-
def validate_id
|
|
363
|
+
def validate_id?
|
|
335
364
|
true
|
|
336
365
|
end
|
|
337
366
|
end
|
|
338
367
|
|
|
368
|
+
# Acknowledgement for a received message.
|
|
339
369
|
class MessageAck < MessageAcking
|
|
340
|
-
def initialize
|
|
370
|
+
def initialize(attributes = {})
|
|
341
371
|
super({
|
|
342
|
-
|
|
372
|
+
'type' => 'MessageAck'
|
|
343
373
|
}.merge attributes)
|
|
344
374
|
end
|
|
345
375
|
|
|
@@ -348,70 +378,77 @@ module RSMP
|
|
|
348
378
|
end
|
|
349
379
|
end
|
|
350
380
|
|
|
381
|
+
# Negative acknowledgement for a received message.
|
|
351
382
|
class MessageNotAck < MessageAcking
|
|
352
|
-
def initialize
|
|
383
|
+
def initialize(attributes = {})
|
|
353
384
|
super({
|
|
354
|
-
|
|
355
|
-
|
|
385
|
+
'type' => 'MessageNotAck',
|
|
386
|
+
'rea' => 'Unknown reason'
|
|
356
387
|
}.merge attributes)
|
|
357
|
-
@attributes.delete
|
|
358
|
-
|
|
388
|
+
@attributes.delete 'mId'
|
|
389
|
+
end
|
|
359
390
|
end
|
|
360
391
|
|
|
392
|
+
# Command request message type.
|
|
361
393
|
class CommandRequest < Message
|
|
362
|
-
def initialize
|
|
394
|
+
def initialize(attributes = {})
|
|
363
395
|
super({
|
|
364
|
-
|
|
396
|
+
'type' => 'CommandRequest'
|
|
365
397
|
}.merge attributes)
|
|
366
398
|
end
|
|
367
399
|
end
|
|
368
400
|
|
|
401
|
+
# Command response message type.
|
|
369
402
|
class CommandResponse < Message
|
|
370
|
-
def initialize
|
|
403
|
+
def initialize(attributes = {})
|
|
371
404
|
super({
|
|
372
|
-
|
|
405
|
+
'type' => 'CommandResponse'
|
|
373
406
|
}.merge attributes)
|
|
374
407
|
end
|
|
375
408
|
end
|
|
376
409
|
|
|
410
|
+
# Status request message type.
|
|
377
411
|
class StatusRequest < Message
|
|
378
|
-
def initialize
|
|
412
|
+
def initialize(attributes = {})
|
|
379
413
|
super({
|
|
380
|
-
|
|
414
|
+
'type' => 'StatusRequest'
|
|
381
415
|
}.merge attributes)
|
|
382
416
|
end
|
|
383
417
|
end
|
|
384
418
|
|
|
419
|
+
# Status response message type.
|
|
385
420
|
class StatusResponse < Message
|
|
386
|
-
def initialize
|
|
421
|
+
def initialize(attributes = {})
|
|
387
422
|
super({
|
|
388
|
-
|
|
423
|
+
'type' => 'StatusResponse'
|
|
389
424
|
}.merge attributes)
|
|
390
425
|
end
|
|
391
426
|
end
|
|
392
427
|
|
|
428
|
+
# Status subscribe message type.
|
|
393
429
|
class StatusSubscribe < Message
|
|
394
|
-
def initialize
|
|
430
|
+
def initialize(attributes = {})
|
|
395
431
|
super({
|
|
396
|
-
|
|
432
|
+
'type' => 'StatusSubscribe'
|
|
397
433
|
}.merge attributes)
|
|
398
434
|
end
|
|
399
435
|
end
|
|
400
436
|
|
|
437
|
+
# Status unsubscribe message type.
|
|
401
438
|
class StatusUnsubscribe < Message
|
|
402
|
-
def initialize
|
|
439
|
+
def initialize(attributes = {})
|
|
403
440
|
super({
|
|
404
|
-
|
|
441
|
+
'type' => 'StatusUnsubscribe'
|
|
405
442
|
}.merge attributes)
|
|
406
443
|
end
|
|
407
444
|
end
|
|
408
445
|
|
|
446
|
+
# Status update message type.
|
|
409
447
|
class StatusUpdate < Message
|
|
410
|
-
def initialize
|
|
448
|
+
def initialize(attributes = {})
|
|
411
449
|
super({
|
|
412
|
-
|
|
450
|
+
'type' => 'StatusUpdate'
|
|
413
451
|
}.merge attributes)
|
|
414
452
|
end
|
|
415
453
|
end
|
|
416
|
-
|
|
417
|
-
end
|
|
454
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
# Base class for sites and supervisors
|
|
2
|
-
|
|
3
1
|
module RSMP
|
|
2
|
+
# Base class for sites and supervisors.
|
|
4
3
|
class Node
|
|
5
4
|
include Logging
|
|
6
5
|
include Inspect
|
|
@@ -8,7 +7,7 @@ module RSMP
|
|
|
8
7
|
|
|
9
8
|
attr_reader :archive, :logger, :task, :deferred, :error_queue, :clock, :collector
|
|
10
9
|
|
|
11
|
-
def initialize
|
|
10
|
+
def initialize(options = {})
|
|
12
11
|
initialize_logging options
|
|
13
12
|
initialize_task
|
|
14
13
|
@deferred = []
|
|
@@ -24,55 +23,57 @@ module RSMP
|
|
|
24
23
|
|
|
25
24
|
# stop proxies, then call super
|
|
26
25
|
def stop_subtasks
|
|
27
|
-
@proxies.each
|
|
26
|
+
@proxies.each(&:stop)
|
|
28
27
|
@proxies.clear
|
|
29
28
|
super
|
|
30
29
|
end
|
|
31
30
|
|
|
32
|
-
def ignore_errors
|
|
33
|
-
was
|
|
31
|
+
def ignore_errors(classes)
|
|
32
|
+
was = @ignore_errors
|
|
33
|
+
@ignore_errors = [classes].flatten
|
|
34
34
|
yield
|
|
35
35
|
ensure
|
|
36
36
|
@ignore_errors = was
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def distribute_error
|
|
40
|
-
return if @ignore_errors.find { |klass|
|
|
39
|
+
def distribute_error(error, options = {})
|
|
40
|
+
return if @ignore_errors.find { |klass| error.is_a? klass }
|
|
41
|
+
|
|
41
42
|
if options[:level] == :internal
|
|
42
|
-
log ["#{
|
|
43
|
+
log ["#{error} in task: #{Async::Task.current}", error.backtrace].flatten.join("\n"),
|
|
44
|
+
level: :error
|
|
43
45
|
end
|
|
44
|
-
@error_queue.enqueue
|
|
46
|
+
@error_queue.enqueue error
|
|
45
47
|
end
|
|
46
48
|
|
|
47
|
-
def defer
|
|
49
|
+
def defer(key, item = nil)
|
|
48
50
|
@deferred << [key, item]
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
def process_deferred
|
|
52
|
-
cloned = @deferred.clone
|
|
54
|
+
cloned = @deferred.clone # clone in case do_deferred restarts the current task
|
|
53
55
|
@deferred.clear
|
|
54
56
|
cloned.each do |pair|
|
|
55
57
|
do_deferred pair.first, pair.last
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
60
|
|
|
59
|
-
def do_deferred
|
|
60
|
-
end
|
|
61
|
+
def do_deferred(key, item = nil); end
|
|
61
62
|
|
|
62
63
|
def clear_deferred
|
|
63
64
|
@deferred.clear
|
|
64
65
|
end
|
|
65
66
|
|
|
66
|
-
def check_required_settings
|
|
67
|
-
raise ArgumentError
|
|
67
|
+
def check_required_settings(settings, required)
|
|
68
|
+
raise ArgumentError, 'Settings is empty' unless settings
|
|
69
|
+
|
|
68
70
|
required.each do |setting|
|
|
69
|
-
raise ArgumentError
|
|
71
|
+
raise ArgumentError, "Missing setting: #{setting}" unless settings.include? setting.to_s
|
|
70
72
|
end
|
|
71
73
|
end
|
|
72
74
|
|
|
73
75
|
def author
|
|
74
76
|
site_id
|
|
75
77
|
end
|
|
76
|
-
|
|
77
78
|
end
|
|
78
|
-
end
|
|
79
|
+
end
|