rsmp 0.38.0 → 0.40.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/.rubocop.yml +5 -16
- data/.tool-versions +1 -1
- data/Gemfile +2 -1
- data/Gemfile.lock +40 -38
- data/README.md +4 -3
- data/documentation/configuration.md +76 -0
- data/lib/rsmp/cli.rb +15 -12
- data/lib/rsmp/collect/alarm_matcher.rb +4 -4
- data/lib/rsmp/collect/collector/logging.rb +1 -0
- data/lib/rsmp/collect/command_matcher.rb +3 -3
- data/lib/rsmp/collect/matcher.rb +3 -3
- data/lib/rsmp/collect/queue.rb +3 -3
- data/lib/rsmp/collect/receiver.rb +2 -4
- data/lib/rsmp/collect/status_matcher.rb +7 -6
- data/lib/rsmp/component/alarm_state.rb +3 -4
- data/lib/rsmp/component/component_base.rb +0 -1
- data/lib/rsmp/component/components.rb +1 -2
- data/lib/rsmp/convert/export/json_schema.rb +2 -0
- data/lib/rsmp/convert/import/yaml.rb +1 -0
- data/lib/rsmp/helpers/clock.rb +3 -5
- data/lib/rsmp/helpers/deep_merge.rb +1 -0
- data/lib/rsmp/helpers/error.rb +1 -0
- data/lib/rsmp/helpers/inspect.rb +11 -12
- data/lib/rsmp/log/archive.rb +2 -3
- data/lib/rsmp/log/logger.rb +1 -0
- data/lib/rsmp/log/logging.rb +1 -0
- data/lib/rsmp/message.rb +26 -0
- data/lib/rsmp/node/node.rb +1 -2
- data/lib/rsmp/node/protocol.rb +1 -0
- data/lib/rsmp/node/site/site.rb +9 -36
- data/lib/rsmp/node/supervisor/modules/configuration.rb +3 -19
- data/lib/rsmp/node/supervisor/supervisor.rb +1 -4
- data/lib/rsmp/node/task.rb +1 -0
- data/lib/rsmp/options/options.rb +185 -0
- data/lib/rsmp/options/schemas/site.json +49 -0
- data/lib/rsmp/options/schemas/supervisor.json +43 -0
- data/lib/rsmp/options/schemas/traffic_controller_site.json +18 -0
- data/lib/rsmp/options/site_options.rb +44 -0
- data/lib/rsmp/options/supervisor_options.rb +28 -0
- data/lib/rsmp/options/traffic_controller_site_options.rb +12 -0
- data/lib/rsmp/proxy/proxy.rb +2 -4
- data/lib/rsmp/proxy/site/site_proxy.rb +1 -2
- data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +1 -2
- data/lib/rsmp/tlc/detector_logic.rb +1 -0
- data/lib/rsmp/tlc/signal_group.rb +1 -0
- data/lib/rsmp/tlc/signal_priority.rb +1 -0
- data/lib/rsmp/tlc/traffic_controller_site.rb +4 -0
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +4 -0
- metadata +10 -2
data/lib/rsmp/log/logger.rb
CHANGED
data/lib/rsmp/log/logging.rb
CHANGED
data/lib/rsmp/message.rb
CHANGED
|
@@ -2,6 +2,7 @@ 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
|
|
|
@@ -191,6 +192,7 @@ module RSMP
|
|
|
191
192
|
end
|
|
192
193
|
end
|
|
193
194
|
|
|
195
|
+
# Represents a malformed message with invalid attributes.
|
|
194
196
|
class Malformed < Message
|
|
195
197
|
# rubocop:disable Lint/MissingSuper
|
|
196
198
|
def initialize(attributes = {})
|
|
@@ -201,6 +203,7 @@ module RSMP
|
|
|
201
203
|
# rubocop:enable Lint/MissingSuper
|
|
202
204
|
end
|
|
203
205
|
|
|
206
|
+
# Version message, lists supported versions and SXL information.
|
|
204
207
|
class Version < Message
|
|
205
208
|
def initialize(attributes = {})
|
|
206
209
|
super({
|
|
@@ -213,9 +216,11 @@ module RSMP
|
|
|
213
216
|
end
|
|
214
217
|
end
|
|
215
218
|
|
|
219
|
+
# Unknown message type wrapper.
|
|
216
220
|
class Unknown < Message
|
|
217
221
|
end
|
|
218
222
|
|
|
223
|
+
# AggregatedStatus message type.
|
|
219
224
|
class AggregatedStatus < Message
|
|
220
225
|
def initialize(attributes = {})
|
|
221
226
|
super({
|
|
@@ -224,6 +229,7 @@ module RSMP
|
|
|
224
229
|
end
|
|
225
230
|
end
|
|
226
231
|
|
|
232
|
+
# AggregatedStatusRequest message type.
|
|
227
233
|
class AggregatedStatusRequest < Message
|
|
228
234
|
def initialize(attributes = {})
|
|
229
235
|
super({
|
|
@@ -232,6 +238,7 @@ module RSMP
|
|
|
232
238
|
end
|
|
233
239
|
end
|
|
234
240
|
|
|
241
|
+
# Alarm base message type.
|
|
235
242
|
class Alarm < Message
|
|
236
243
|
def initialize(attributes = {})
|
|
237
244
|
super({
|
|
@@ -253,6 +260,7 @@ module RSMP
|
|
|
253
260
|
end
|
|
254
261
|
end
|
|
255
262
|
|
|
263
|
+
# Alarm issue specialization.
|
|
256
264
|
class AlarmIssue < Alarm
|
|
257
265
|
def initialize(attributes = {})
|
|
258
266
|
super({
|
|
@@ -261,6 +269,7 @@ module RSMP
|
|
|
261
269
|
end
|
|
262
270
|
end
|
|
263
271
|
|
|
272
|
+
# Alarm request specialization.
|
|
264
273
|
class AlarmRequest < Alarm
|
|
265
274
|
def initialize(attributes = {})
|
|
266
275
|
super({
|
|
@@ -269,6 +278,7 @@ module RSMP
|
|
|
269
278
|
end
|
|
270
279
|
end
|
|
271
280
|
|
|
281
|
+
# Alarm acknowledge message.
|
|
272
282
|
class AlarmAcknowledge < Alarm
|
|
273
283
|
def initialize(attributes = {})
|
|
274
284
|
super({
|
|
@@ -277,6 +287,7 @@ module RSMP
|
|
|
277
287
|
end
|
|
278
288
|
end
|
|
279
289
|
|
|
290
|
+
# Alarm acknowledged (acknowledged state) message.
|
|
280
291
|
class AlarmAcknowledged < Alarm
|
|
281
292
|
def initialize(attributes = {})
|
|
282
293
|
super({
|
|
@@ -286,6 +297,7 @@ module RSMP
|
|
|
286
297
|
end
|
|
287
298
|
end
|
|
288
299
|
|
|
300
|
+
# Alarm suspend message.
|
|
289
301
|
class AlarmSuspend < Alarm
|
|
290
302
|
def initialize(attributes = {})
|
|
291
303
|
super({
|
|
@@ -294,6 +306,7 @@ module RSMP
|
|
|
294
306
|
end
|
|
295
307
|
end
|
|
296
308
|
|
|
309
|
+
# Alarm suspended (suspended state) message.
|
|
297
310
|
class AlarmSuspended < Alarm
|
|
298
311
|
def initialize(attributes = {})
|
|
299
312
|
super({
|
|
@@ -303,6 +316,7 @@ module RSMP
|
|
|
303
316
|
end
|
|
304
317
|
end
|
|
305
318
|
|
|
319
|
+
# Alarm resume message.
|
|
306
320
|
class AlarmResume < Alarm
|
|
307
321
|
def initialize(attributes = {})
|
|
308
322
|
super({
|
|
@@ -311,6 +325,7 @@ module RSMP
|
|
|
311
325
|
end
|
|
312
326
|
end
|
|
313
327
|
|
|
328
|
+
# Alarm resumed (not suspended) message.
|
|
314
329
|
class AlarmResumed < Alarm
|
|
315
330
|
def initialize(attributes = {})
|
|
316
331
|
super({
|
|
@@ -320,6 +335,7 @@ module RSMP
|
|
|
320
335
|
end
|
|
321
336
|
end
|
|
322
337
|
|
|
338
|
+
# Watchdog message type.
|
|
323
339
|
class Watchdog < Message
|
|
324
340
|
def initialize(attributes = {})
|
|
325
341
|
super({
|
|
@@ -328,6 +344,7 @@ module RSMP
|
|
|
328
344
|
end
|
|
329
345
|
end
|
|
330
346
|
|
|
347
|
+
# Base class for acking messages (MessageAck / MessageNotAck).
|
|
331
348
|
class MessageAcking < Message
|
|
332
349
|
attr_reader :original
|
|
333
350
|
|
|
@@ -348,6 +365,7 @@ module RSMP
|
|
|
348
365
|
end
|
|
349
366
|
end
|
|
350
367
|
|
|
368
|
+
# Acknowledgement for a received message.
|
|
351
369
|
class MessageAck < MessageAcking
|
|
352
370
|
def initialize(attributes = {})
|
|
353
371
|
super({
|
|
@@ -360,6 +378,7 @@ module RSMP
|
|
|
360
378
|
end
|
|
361
379
|
end
|
|
362
380
|
|
|
381
|
+
# Negative acknowledgement for a received message.
|
|
363
382
|
class MessageNotAck < MessageAcking
|
|
364
383
|
def initialize(attributes = {})
|
|
365
384
|
super({
|
|
@@ -370,6 +389,7 @@ module RSMP
|
|
|
370
389
|
end
|
|
371
390
|
end
|
|
372
391
|
|
|
392
|
+
# Command request message type.
|
|
373
393
|
class CommandRequest < Message
|
|
374
394
|
def initialize(attributes = {})
|
|
375
395
|
super({
|
|
@@ -378,6 +398,7 @@ module RSMP
|
|
|
378
398
|
end
|
|
379
399
|
end
|
|
380
400
|
|
|
401
|
+
# Command response message type.
|
|
381
402
|
class CommandResponse < Message
|
|
382
403
|
def initialize(attributes = {})
|
|
383
404
|
super({
|
|
@@ -386,6 +407,7 @@ module RSMP
|
|
|
386
407
|
end
|
|
387
408
|
end
|
|
388
409
|
|
|
410
|
+
# Status request message type.
|
|
389
411
|
class StatusRequest < Message
|
|
390
412
|
def initialize(attributes = {})
|
|
391
413
|
super({
|
|
@@ -394,6 +416,7 @@ module RSMP
|
|
|
394
416
|
end
|
|
395
417
|
end
|
|
396
418
|
|
|
419
|
+
# Status response message type.
|
|
397
420
|
class StatusResponse < Message
|
|
398
421
|
def initialize(attributes = {})
|
|
399
422
|
super({
|
|
@@ -402,6 +425,7 @@ module RSMP
|
|
|
402
425
|
end
|
|
403
426
|
end
|
|
404
427
|
|
|
428
|
+
# Status subscribe message type.
|
|
405
429
|
class StatusSubscribe < Message
|
|
406
430
|
def initialize(attributes = {})
|
|
407
431
|
super({
|
|
@@ -410,6 +434,7 @@ module RSMP
|
|
|
410
434
|
end
|
|
411
435
|
end
|
|
412
436
|
|
|
437
|
+
# Status unsubscribe message type.
|
|
413
438
|
class StatusUnsubscribe < Message
|
|
414
439
|
def initialize(attributes = {})
|
|
415
440
|
super({
|
|
@@ -418,6 +443,7 @@ module RSMP
|
|
|
418
443
|
end
|
|
419
444
|
end
|
|
420
445
|
|
|
446
|
+
# Status update message type.
|
|
421
447
|
class StatusUpdate < Message
|
|
422
448
|
def initialize(attributes = {})
|
|
423
449
|
super({
|
data/lib/rsmp/node/node.rb
CHANGED
data/lib/rsmp/node/protocol.rb
CHANGED
data/lib/rsmp/node/site/site.rb
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
# RSMP site
|
|
2
|
-
# The site initializes the connection to the supervisor.
|
|
3
|
-
# Connections to supervisors are handles via supervisor proxies.
|
|
4
|
-
|
|
5
1
|
module RSMP
|
|
2
|
+
# RSMP site implementation that manages proxies and components.
|
|
6
3
|
class Site < Node
|
|
7
4
|
include Components
|
|
8
5
|
|
|
9
6
|
attr_reader :core_version, :site_settings, :logger, :proxies
|
|
10
7
|
|
|
8
|
+
def self.options_class
|
|
9
|
+
RSMP::Site::Options
|
|
10
|
+
end
|
|
11
|
+
|
|
11
12
|
def initialize(options = {})
|
|
12
13
|
super
|
|
13
14
|
initialize_components
|
|
@@ -26,39 +27,11 @@ module RSMP
|
|
|
26
27
|
@site_settings['site_id']
|
|
27
28
|
end
|
|
28
29
|
|
|
29
|
-
def default_site_settings
|
|
30
|
-
{
|
|
31
|
-
'site_id' => 'RN+SI0001',
|
|
32
|
-
'supervisors' => [
|
|
33
|
-
{ 'ip' => '127.0.0.1', 'port' => 12_111 }
|
|
34
|
-
],
|
|
35
|
-
'sxl' => 'tlc',
|
|
36
|
-
'sxl_version' => RSMP::Schema.latest_version(:tlc),
|
|
37
|
-
'intervals' => {
|
|
38
|
-
'timer' => 0.1,
|
|
39
|
-
'watchdog' => 1,
|
|
40
|
-
'reconnect' => 0.1
|
|
41
|
-
},
|
|
42
|
-
'timeouts' => {
|
|
43
|
-
'watchdog' => 2,
|
|
44
|
-
'acknowledgement' => 2
|
|
45
|
-
},
|
|
46
|
-
'send_after_connect' => true,
|
|
47
|
-
'components' => {
|
|
48
|
-
'main' => {
|
|
49
|
-
'C1' => {}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
end
|
|
54
|
-
|
|
55
30
|
def handle_site_settings(options = {})
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
@site_settings = defaults.deep_merge options[:site_settings]
|
|
31
|
+
options_class = self.class.options_class
|
|
32
|
+
settings = options[:site_settings] || {}
|
|
33
|
+
@site_options = options_class.new(settings)
|
|
34
|
+
@site_settings = @site_options.to_h
|
|
62
35
|
|
|
63
36
|
check_sxl_version
|
|
64
37
|
check_core_versions
|
|
@@ -4,25 +4,9 @@ module RSMP
|
|
|
4
4
|
# Handles supervisor configuration and site settings
|
|
5
5
|
module Configuration
|
|
6
6
|
def handle_supervisor_settings(supervisor_settings)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'guest' => {
|
|
11
|
-
'sxl' => 'tlc',
|
|
12
|
-
'intervals' => {
|
|
13
|
-
'timer' => 1,
|
|
14
|
-
'watchdog' => 1
|
|
15
|
-
},
|
|
16
|
-
'timeouts' => {
|
|
17
|
-
'watchdog' => 2,
|
|
18
|
-
'acknowledgement' => 2
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
# merge options into defaults
|
|
24
|
-
@supervisor_settings = defaults.deep_merge(supervisor_settings)
|
|
25
|
-
@core_version = @supervisor_settings['guest']['core_version']
|
|
7
|
+
options = RSMP::Supervisor::Options.new(supervisor_settings || {})
|
|
8
|
+
@supervisor_settings = options.to_h
|
|
9
|
+
@core_version = @supervisor_settings.dig('guest', 'core_version')
|
|
26
10
|
check_site_sxl_types
|
|
27
11
|
end
|
|
28
12
|
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
# RSMP supervisor (server)
|
|
2
|
-
# The supervisor waits for sites to connect.
|
|
3
|
-
# Connections to sites are handles via site proxies.
|
|
4
|
-
|
|
5
1
|
module RSMP
|
|
2
|
+
# RSMP supervisor (server) that accepts site connections.
|
|
6
3
|
class Supervisor < Node
|
|
7
4
|
include Modules::Configuration
|
|
8
5
|
include Modules::Connection
|
data/lib/rsmp/node/task.rb
CHANGED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'pathname'
|
|
3
|
+
|
|
4
|
+
module RSMP
|
|
5
|
+
# Base class for configuration options.
|
|
6
|
+
class Options
|
|
7
|
+
SCHEMAS_PATH = File.expand_path('schemas', __dir__)
|
|
8
|
+
|
|
9
|
+
attr_reader :data, :log_settings, :source
|
|
10
|
+
|
|
11
|
+
def self.load_file(path, validate: true)
|
|
12
|
+
raise RSMP::ConfigurationError, "Config #{path} not found" unless File.exist?(path)
|
|
13
|
+
|
|
14
|
+
raw = YAML.load_file(path)
|
|
15
|
+
raise RSMP::ConfigurationError, "Config #{path} must be a hash" unless raw.is_a?(Hash) || raw.nil?
|
|
16
|
+
|
|
17
|
+
raw ||= {}
|
|
18
|
+
log_settings = raw.delete('log') || {}
|
|
19
|
+
new(raw, source: path, log_settings: log_settings, validate: validate)
|
|
20
|
+
rescue Psych::SyntaxError => e
|
|
21
|
+
raise RSMP::ConfigurationError, "Cannot read config file #{path}: #{e}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize(options = nil, source: nil, log_settings: nil, validate: true, **extra)
|
|
25
|
+
options = extra if options.nil? && extra.any?
|
|
26
|
+
@source = source
|
|
27
|
+
@log_settings = normalize(log_settings || {})
|
|
28
|
+
normalized = normalize(options || {})
|
|
29
|
+
@data = apply_defaults(normalized)
|
|
30
|
+
validate! if validate
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def defaults
|
|
34
|
+
{}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def schema_file
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def schema_path
|
|
42
|
+
return unless schema_file
|
|
43
|
+
|
|
44
|
+
File.join(SCHEMAS_PATH, schema_file)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def validate!
|
|
48
|
+
return unless schema_path && File.exist?(schema_path)
|
|
49
|
+
|
|
50
|
+
schemer = JSONSchemer.schema(Pathname.new(schema_path))
|
|
51
|
+
errors = schemer.validate(@data).to_a
|
|
52
|
+
return if errors.empty?
|
|
53
|
+
|
|
54
|
+
message = errors.map { |error| format_error(error) }.join("\n")
|
|
55
|
+
raise RSMP::ConfigurationError, "Invalid configuration#{source_suffix}:\n#{message}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def dig(*path, default: nil, assume: nil)
|
|
59
|
+
value = @data.dig(*path)
|
|
60
|
+
return value unless value.nil?
|
|
61
|
+
return default unless default.nil?
|
|
62
|
+
return assume unless assume.nil?
|
|
63
|
+
|
|
64
|
+
raise RSMP::ConfigurationError, "Config #{path.inspect} is missing"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def [](key)
|
|
68
|
+
@data[key]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def to_h
|
|
72
|
+
@data
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def apply_defaults(options)
|
|
78
|
+
defaults.deep_merge(options)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def normalize(value)
|
|
82
|
+
case value
|
|
83
|
+
when Hash
|
|
84
|
+
value.each_with_object({}) do |(key, val), memo|
|
|
85
|
+
memo[key.to_s] = normalize(val)
|
|
86
|
+
end
|
|
87
|
+
when Array
|
|
88
|
+
value.map { |item| normalize(item) }
|
|
89
|
+
else
|
|
90
|
+
value
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def format_error(error)
|
|
95
|
+
pointer = error_pointer(error)
|
|
96
|
+
details = error_details(error)
|
|
97
|
+
type_hint = error_type_hint(error)
|
|
98
|
+
schema_suffix = schema_pointer_suffix(error)
|
|
99
|
+
|
|
100
|
+
"#{pointer}: #{details}#{type_hint}#{schema_suffix}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def error_pointer(error)
|
|
104
|
+
pointer = error['data_pointer'] || error['instanceLocation'] || error['dataPath']
|
|
105
|
+
pointer = pointer.to_s
|
|
106
|
+
pointer.empty? ? '/' : pointer
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def error_details(error)
|
|
110
|
+
details = error['message'] || error['error']
|
|
111
|
+
details ||= begin
|
|
112
|
+
type = error['type'] || error['keyword']
|
|
113
|
+
extra = error['details']
|
|
114
|
+
[type, extra].compact.join(' ')
|
|
115
|
+
end
|
|
116
|
+
details.to_s
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def error_type_hint(error)
|
|
120
|
+
expected = expected_type(error['schema'])
|
|
121
|
+
actual = describe_type(error['data'])
|
|
122
|
+
return '' unless expected && actual
|
|
123
|
+
|
|
124
|
+
" (expected #{expected}, got #{actual})"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def schema_pointer_suffix(error)
|
|
128
|
+
schema_pointer = error['schema_pointer'] || error['schemaLocation'] || error['keywordLocation']
|
|
129
|
+
schema_pointer = schema_pointer.to_s
|
|
130
|
+
schema_pointer.empty? ? '' : " (schema #{schema_pointer})"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def expected_type(schema)
|
|
134
|
+
return unless schema.is_a?(Hash)
|
|
135
|
+
|
|
136
|
+
type = schema['type']
|
|
137
|
+
return format_type(type) if type
|
|
138
|
+
|
|
139
|
+
types = []
|
|
140
|
+
%w[oneOf anyOf].each do |key|
|
|
141
|
+
next unless schema[key].is_a?(Array)
|
|
142
|
+
|
|
143
|
+
types.concat(schema[key].map { |item| item['type'] }.compact)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
format_type(types) if types.any?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def format_type(type)
|
|
150
|
+
case type
|
|
151
|
+
when Array
|
|
152
|
+
type.join(' or ')
|
|
153
|
+
when nil
|
|
154
|
+
nil
|
|
155
|
+
else
|
|
156
|
+
type.to_s
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def describe_type(value)
|
|
161
|
+
case value
|
|
162
|
+
when NilClass
|
|
163
|
+
'null'
|
|
164
|
+
when String
|
|
165
|
+
'string'
|
|
166
|
+
when Integer
|
|
167
|
+
'integer'
|
|
168
|
+
when Float
|
|
169
|
+
'number'
|
|
170
|
+
when TrueClass, FalseClass
|
|
171
|
+
'boolean'
|
|
172
|
+
when Array
|
|
173
|
+
'array'
|
|
174
|
+
when Hash
|
|
175
|
+
'object'
|
|
176
|
+
else
|
|
177
|
+
value.class.name
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def source_suffix
|
|
182
|
+
source ? " (#{source})" : ''
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "site.json",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"site_id": { "type": "string" },
|
|
7
|
+
"type": { "type": "string" },
|
|
8
|
+
"supervisors": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"ip": { "type": "string" },
|
|
14
|
+
"port": { "type": ["integer", "string"] }
|
|
15
|
+
},
|
|
16
|
+
"required": ["ip", "port"],
|
|
17
|
+
"additionalProperties": true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"sxl": { "type": "string" },
|
|
21
|
+
"sxl_version": { "type": "string" },
|
|
22
|
+
"core_version": { "type": "string" },
|
|
23
|
+
"intervals": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"properties": {
|
|
26
|
+
"timer": { "type": "number" },
|
|
27
|
+
"watchdog": { "type": "number" },
|
|
28
|
+
"reconnect": { "type": "number" }
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": true
|
|
31
|
+
},
|
|
32
|
+
"timeouts": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"watchdog": { "type": "number" },
|
|
36
|
+
"acknowledgement": { "type": "number" }
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": true
|
|
39
|
+
},
|
|
40
|
+
"send_after_connect": { "type": "boolean" },
|
|
41
|
+
"components": { "type": "object" },
|
|
42
|
+
"security_codes": { "type": "object" },
|
|
43
|
+
"startup_sequence": { "type": "string" },
|
|
44
|
+
"signal_plans": { "type": "object" },
|
|
45
|
+
"inputs": { "type": "object" },
|
|
46
|
+
"live_output": { "type": ["string", "null"] }
|
|
47
|
+
},
|
|
48
|
+
"additionalProperties": true
|
|
49
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"port": { "type": ["integer", "string"] },
|
|
6
|
+
"ip": { "type": "string" },
|
|
7
|
+
"ips": {
|
|
8
|
+
"oneOf": [
|
|
9
|
+
{ "type": "string" },
|
|
10
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"site_id": { "type": "string" },
|
|
14
|
+
"max_sites": { "type": "integer" },
|
|
15
|
+
"guest": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"properties": {
|
|
18
|
+
"sxl": { "type": "string" },
|
|
19
|
+
"sxl_version": { "type": "string" },
|
|
20
|
+
"core_version": { "type": "string" },
|
|
21
|
+
"intervals": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"properties": {
|
|
24
|
+
"timer": { "type": "number" },
|
|
25
|
+
"watchdog": { "type": "number" }
|
|
26
|
+
},
|
|
27
|
+
"additionalProperties": true
|
|
28
|
+
},
|
|
29
|
+
"timeouts": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"properties": {
|
|
32
|
+
"watchdog": { "type": "number" },
|
|
33
|
+
"acknowledgement": { "type": "number" }
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": true
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": true
|
|
39
|
+
},
|
|
40
|
+
"sites": { "type": "object" }
|
|
41
|
+
},
|
|
42
|
+
"additionalProperties": true
|
|
43
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "traffic_controller_site.json",
|
|
4
|
+
"allOf": [
|
|
5
|
+
{ "$ref": "site.json" },
|
|
6
|
+
{
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"security_codes": { "type": "object" },
|
|
10
|
+
"startup_sequence": { "type": "string" },
|
|
11
|
+
"signal_plans": { "type": "object" },
|
|
12
|
+
"inputs": { "type": "object" },
|
|
13
|
+
"live_output": { "type": ["string", "null"] }
|
|
14
|
+
},
|
|
15
|
+
"additionalProperties": true
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
class Site < Node
|
|
3
|
+
# Configuration options for sites.
|
|
4
|
+
class Options < RSMP::Options
|
|
5
|
+
def defaults
|
|
6
|
+
{
|
|
7
|
+
'site_id' => 'RN+SI0001',
|
|
8
|
+
'supervisors' => [
|
|
9
|
+
{ 'ip' => '127.0.0.1', 'port' => 12_111 }
|
|
10
|
+
],
|
|
11
|
+
'sxl' => 'tlc',
|
|
12
|
+
'sxl_version' => RSMP::Schema.latest_version(:tlc),
|
|
13
|
+
'intervals' => {
|
|
14
|
+
'timer' => 0.1,
|
|
15
|
+
'watchdog' => 1,
|
|
16
|
+
'reconnect' => 0.1
|
|
17
|
+
},
|
|
18
|
+
'timeouts' => {
|
|
19
|
+
'watchdog' => 2,
|
|
20
|
+
'acknowledgement' => 2
|
|
21
|
+
},
|
|
22
|
+
'send_after_connect' => true,
|
|
23
|
+
'components' => {
|
|
24
|
+
'main' => {
|
|
25
|
+
'C1' => {}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def schema_file
|
|
32
|
+
'site.json'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def apply_defaults(options)
|
|
38
|
+
defaults = defaults()
|
|
39
|
+
defaults['components']['main'] = options['components']['main'] if options.dig('components', 'main')
|
|
40
|
+
defaults.deep_merge(options)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|