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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/devcontainer.json +22 -0
  3. data/.github/workflows/rubocop.yaml +17 -0
  4. data/.gitignore +5 -6
  5. data/.rubocop.yml +69 -0
  6. data/.tool-versions +1 -1
  7. data/Gemfile +14 -1
  8. data/Gemfile.lock +64 -29
  9. data/Rakefile +3 -3
  10. data/lib/rsmp/cli.rb +148 -124
  11. data/lib/rsmp/collect/ack_collector.rb +8 -7
  12. data/lib/rsmp/collect/aggregated_status_collector.rb +4 -4
  13. data/lib/rsmp/collect/alarm_collector.rb +31 -23
  14. data/lib/rsmp/collect/alarm_matcher.rb +6 -6
  15. data/lib/rsmp/collect/collector/logging.rb +18 -0
  16. data/lib/rsmp/collect/collector/reporting.rb +44 -0
  17. data/lib/rsmp/collect/collector/status.rb +34 -0
  18. data/lib/rsmp/collect/collector.rb +69 -150
  19. data/lib/rsmp/collect/command_matcher.rb +19 -6
  20. data/lib/rsmp/collect/command_response_collector.rb +7 -7
  21. data/lib/rsmp/collect/distributor.rb +14 -11
  22. data/lib/rsmp/collect/filter.rb +31 -15
  23. data/lib/rsmp/collect/matcher.rb +9 -13
  24. data/lib/rsmp/collect/queue.rb +7 -7
  25. data/lib/rsmp/collect/receiver.rb +11 -15
  26. data/lib/rsmp/collect/state_collector.rb +116 -77
  27. data/lib/rsmp/collect/status_collector.rb +6 -6
  28. data/lib/rsmp/collect/status_matcher.rb +15 -4
  29. data/lib/rsmp/{alarm_state.rb → component/alarm_state.rb} +76 -38
  30. data/lib/rsmp/{component.rb → component/component.rb} +15 -15
  31. data/lib/rsmp/component/component_base.rb +88 -0
  32. data/lib/rsmp/component/component_proxy.rb +75 -0
  33. data/lib/rsmp/component/components.rb +62 -0
  34. data/lib/rsmp/convert/export/json_schema.rb +118 -110
  35. data/lib/rsmp/convert/import/yaml.rb +22 -18
  36. data/lib/rsmp/{rsmp.rb → helpers/clock.rb} +8 -11
  37. data/lib/rsmp/{deep_merge.rb → helpers/deep_merge.rb} +3 -1
  38. data/lib/rsmp/helpers/error.rb +72 -0
  39. data/lib/rsmp/helpers/inspect.rb +41 -0
  40. data/lib/rsmp/log/archive.rb +97 -0
  41. data/lib/rsmp/log/colorization.rb +41 -0
  42. data/lib/rsmp/log/filtering.rb +54 -0
  43. data/lib/rsmp/log/logger.rb +207 -0
  44. data/lib/rsmp/{logging.rb → log/logging.rb} +6 -7
  45. data/lib/rsmp/message.rb +185 -148
  46. data/lib/rsmp/{node.rb → node/node.rb} +20 -19
  47. data/lib/rsmp/{protocol.rb → node/protocol.rb} +6 -3
  48. data/lib/rsmp/node/site/site.rb +192 -0
  49. data/lib/rsmp/node/supervisor/modules/configuration.rb +59 -0
  50. data/lib/rsmp/node/supervisor/modules/connection.rb +140 -0
  51. data/lib/rsmp/node/supervisor/modules/sites.rb +64 -0
  52. data/lib/rsmp/node/supervisor/supervisor.rb +69 -0
  53. data/lib/rsmp/{task.rb → node/task.rb} +13 -14
  54. data/lib/rsmp/proxy/modules/acknowledgements.rb +144 -0
  55. data/lib/rsmp/proxy/modules/receive.rb +119 -0
  56. data/lib/rsmp/proxy/modules/send.rb +76 -0
  57. data/lib/rsmp/proxy/modules/state.rb +25 -0
  58. data/lib/rsmp/proxy/modules/tasks.rb +105 -0
  59. data/lib/rsmp/proxy/modules/versions.rb +69 -0
  60. data/lib/rsmp/proxy/modules/watchdogs.rb +66 -0
  61. data/lib/rsmp/proxy/proxy.rb +197 -0
  62. data/lib/rsmp/proxy/site/modules/aggregated_status.rb +52 -0
  63. data/lib/rsmp/proxy/site/modules/alarms.rb +27 -0
  64. data/lib/rsmp/proxy/site/modules/commands.rb +31 -0
  65. data/lib/rsmp/proxy/site/modules/status.rb +110 -0
  66. data/lib/rsmp/proxy/site/site_proxy.rb +204 -0
  67. data/lib/rsmp/proxy/supervisor/modules/aggregated_status.rb +47 -0
  68. data/lib/rsmp/proxy/supervisor/modules/alarms.rb +73 -0
  69. data/lib/rsmp/proxy/supervisor/modules/commands.rb +53 -0
  70. data/lib/rsmp/proxy/supervisor/modules/status.rb +204 -0
  71. data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +177 -0
  72. data/lib/rsmp/tlc/detector_logic.rb +19 -34
  73. data/lib/rsmp/tlc/input_states.rb +126 -0
  74. data/lib/rsmp/tlc/modules/detector_logics.rb +50 -0
  75. data/lib/rsmp/tlc/modules/display.rb +78 -0
  76. data/lib/rsmp/tlc/modules/helpers.rb +41 -0
  77. data/lib/rsmp/tlc/modules/inputs.rb +173 -0
  78. data/lib/rsmp/tlc/modules/modes.rb +253 -0
  79. data/lib/rsmp/tlc/modules/outputs.rb +30 -0
  80. data/lib/rsmp/tlc/modules/plans.rb +218 -0
  81. data/lib/rsmp/tlc/modules/signal_groups.rb +109 -0
  82. data/lib/rsmp/tlc/modules/startup_sequence.rb +22 -0
  83. data/lib/rsmp/tlc/modules/system.rb +140 -0
  84. data/lib/rsmp/tlc/modules/traffic_data.rb +49 -0
  85. data/lib/rsmp/tlc/signal_group.rb +38 -41
  86. data/lib/rsmp/tlc/signal_plan.rb +14 -11
  87. data/lib/rsmp/tlc/signal_priority.rb +40 -35
  88. data/lib/rsmp/tlc/startup_sequence.rb +59 -0
  89. data/lib/rsmp/tlc/traffic_controller.rb +38 -1010
  90. data/lib/rsmp/tlc/traffic_controller_site.rb +58 -57
  91. data/lib/rsmp/version.rb +1 -1
  92. data/lib/rsmp.rb +82 -48
  93. data/rsmp.gemspec +24 -31
  94. metadata +79 -139
  95. data/lib/rsmp/archive.rb +0 -76
  96. data/lib/rsmp/collect/message_matchers.rb +0 -0
  97. data/lib/rsmp/component_base.rb +0 -87
  98. data/lib/rsmp/component_proxy.rb +0 -57
  99. data/lib/rsmp/components.rb +0 -65
  100. data/lib/rsmp/error.rb +0 -71
  101. data/lib/rsmp/inspect.rb +0 -46
  102. data/lib/rsmp/logger.rb +0 -216
  103. data/lib/rsmp/proxy.rb +0 -693
  104. data/lib/rsmp/site.rb +0 -188
  105. data/lib/rsmp/site_proxy.rb +0 -389
  106. data/lib/rsmp/supervisor.rb +0 -302
  107. data/lib/rsmp/supervisor_proxy.rb +0 -510
  108. data/lib/rsmp/tlc/inputs.rb +0 -134
@@ -0,0 +1,73 @@
1
+ module RSMP
2
+ class SupervisorProxy < Proxy
3
+ module Modules
4
+ # Alarm handling
5
+ module Alarms
6
+ def send_alarm(_component, alarm, options = {})
7
+ send_and_optionally_collect alarm, options do |collect_options|
8
+ Collector.new self, collect_options.merge(task: @task, type: 'MessageAck')
9
+ end
10
+ end
11
+
12
+ def send_active_alarms
13
+ @site.components.each_pair do |_c_id, component|
14
+ component.alarms.each_pair do |_alarm_code, alarm_state|
15
+ if alarm_state.active
16
+ alarm = AlarmIssue.new(alarm_state.to_hash.merge('aSp' => 'Issue'))
17
+ send_message alarm
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ def process_alarm(message)
24
+ case message
25
+ when AlarmAcknowledge
26
+ handle_alarm_acknowledge message
27
+ when AlarmSuspend
28
+ handle_alarm_suspend message
29
+ when AlarmResume
30
+ handle_alarm_resume message
31
+ when AlarmRequest
32
+ handle_alarm_request message
33
+ else
34
+ dont_acknowledge message, 'Invalid alarm message type'
35
+ end
36
+ end
37
+
38
+ def handle_alarm_acknowledge(message)
39
+ component_id = message.attributes['cId']
40
+ component = @site.find_component component_id
41
+ alarm_code = message.attribute('aCId')
42
+ log "Received #{message.type} #{alarm_code} acknowledgement", message: message, level: :log
43
+ acknowledge message
44
+ component.acknowledge_alarm alarm_code
45
+ end
46
+
47
+ def handle_alarm_suspend(message)
48
+ component_id = message.attributes['cId']
49
+ component = @site.find_component component_id
50
+ alarm_code = message.attribute('aCId')
51
+ log "Received #{message.type} #{alarm_code} suspend", message: message, level: :log
52
+ acknowledge message
53
+ component.suspend_alarm alarm_code
54
+ end
55
+
56
+ def handle_alarm_resume(message)
57
+ component_id = message.attributes['cId']
58
+ component = @site.find_component component_id
59
+ alarm_code = message.attribute('aCId')
60
+ log "Received #{message.type} #{alarm_code} resume", message: message, level: :log
61
+ acknowledge message
62
+ component.resume_alarm alarm_code
63
+ end
64
+
65
+ def handle_alarm_request(message)
66
+ log "Received #{message.type}", message: message, level: :log
67
+ acknowledge message
68
+ send_active_alarms
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,53 @@
1
+ module RSMP
2
+ class SupervisorProxy < Proxy
3
+ module Modules
4
+ # Command request handling
5
+ module Commands
6
+ def simplify_command_requests(arg)
7
+ sorted = {}
8
+ arg.each do |item|
9
+ sorted[item['cCI']] ||= {}
10
+ sorted[item['cCI']][item['n']] = item['v']
11
+ end
12
+ sorted
13
+ end
14
+
15
+ def build_command_rvs(args)
16
+ args.map do |item|
17
+ item = item.dup.merge('age' => 'recent')
18
+ item.delete 'cO'
19
+ item
20
+ end
21
+ end
22
+
23
+ def execute_commands(message, component_id, rvs)
24
+ component = @site.find_component component_id
25
+ commands = simplify_command_requests message.attributes['arg']
26
+ commands.each_pair do |command_code, arg|
27
+ component.handle_command command_code, arg
28
+ end
29
+ log "Received #{message.type}", message: message, level: :log
30
+ rescue UnknownComponent
31
+ log "Received #{message.type} with unknown component id '#{component_id}' and cannot infer type",
32
+ message: message, level: :warning
33
+ rvs.map { |item| item['age'] = 'undefined' }
34
+ end
35
+
36
+ def process_command_request(message)
37
+ component_id = message.attributes['cId']
38
+ rvs = build_command_rvs(message.attributes['arg'])
39
+ execute_commands(message, component_id, rvs)
40
+
41
+ response = CommandResponse.new({
42
+ 'cId' => component_id,
43
+ 'cTS' => clock.to_s,
44
+ 'rvs' => rvs
45
+ })
46
+ apply_nts_message_attributes response
47
+ acknowledge message
48
+ send_message response
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,204 @@
1
+ module RSMP
2
+ class SupervisorProxy < Proxy
3
+ module Modules
4
+ # Status request and subscription handling
5
+ module Status
6
+ def rsmpify_value(value, quality)
7
+ if value.is_a?(Array) || value.is_a?(Set)
8
+ value
9
+ elsif %w[undefined unknown].include?(quality.to_s)
10
+ nil
11
+ else
12
+ value.to_s
13
+ end
14
+ end
15
+
16
+ def fetch_status_values(component, args)
17
+ args.map do |arg|
18
+ value, quality = component.get_status arg['sCI'], arg['n'], { sxl_version: sxl_version }
19
+ { 's' => rsmpify_value(value, quality), 'q' => quality.to_s }.merge arg
20
+ end
21
+ end
22
+
23
+ def build_undefined_statuses(args)
24
+ args.map { |arg| arg.dup.merge('q' => 'undefined', 's' => nil) }
25
+ end
26
+
27
+ def process_status_request(message, options = {})
28
+ component_id = message.attributes['cId']
29
+ args = message.attributes['sS']
30
+
31
+ begin
32
+ component = @site.find_component component_id
33
+ ss = fetch_status_values(component, args)
34
+ log "Received #{message.type}", message: message, level: :log
35
+ rescue UnknownComponent
36
+ log "Received #{message.type} with unknown component id '#{component_id}' and cannot infer type",
37
+ message: message, level: :warning
38
+ ss = build_undefined_statuses(args)
39
+ end
40
+
41
+ response = StatusResponse.new({
42
+ 'cId' => component_id,
43
+ 'sTs' => clock.to_s,
44
+ 'sS' => ss,
45
+ 'mId' => options[:m_id]
46
+ })
47
+
48
+ apply_nts_message_attributes response
49
+ acknowledge message
50
+ send_message response
51
+ end
52
+
53
+ def add_status_subscription(component_id, subs, update_list, arg, now)
54
+ sci = arg['sCI']
55
+ name = arg['n']
56
+ subcription = { interval: arg['uRt'].to_i, last_sent_at: now }
57
+ subs[sci] ||= {}
58
+ subs[sci][name] = subcription
59
+ update_list[component_id][sci] ||= []
60
+ update_list[component_id][sci] << name
61
+ end
62
+
63
+ def process_status_subcribe(message)
64
+ log "Received #{message.type}", message: message, level: :log
65
+
66
+ update_list = {}
67
+ component_id = message.attributes['cId']
68
+ @status_subscriptions[component_id] ||= {}
69
+ update_list[component_id] ||= {}
70
+ now = Time.now
71
+ subs = @status_subscriptions[component_id]
72
+
73
+ message.attributes['sS'].each do |arg|
74
+ add_status_subscription(component_id, subs, update_list, arg, now)
75
+ end
76
+ acknowledge message
77
+ send_status_updates update_list
78
+ end
79
+
80
+ def get_status_subscribe_interval(component_id, sci, name)
81
+ @status_subscriptions.dig component_id, sci, name
82
+ end
83
+
84
+ def remove_status_subscription(subs, arg)
85
+ sci = arg['sCI']
86
+ return unless subs[sci]
87
+
88
+ subs[sci].delete arg['n']
89
+ subs.delete(sci) if subs[sci].empty?
90
+ end
91
+
92
+ def process_status_unsubcribe(message)
93
+ log "Received #{message.type}", message: message, level: :log
94
+ component = message.attributes['cId']
95
+
96
+ subs = @status_subscriptions[component]
97
+ if subs
98
+ message.attributes['sS'].each { |arg| remove_status_subscription(subs, arg) }
99
+ @status_subscriptions.delete(component) if subs.empty?
100
+ end
101
+ acknowledge message
102
+ end
103
+
104
+ def fetch_last_sent_status(component, code, name)
105
+ @last_status_sent&.dig component, code, name
106
+ end
107
+
108
+ def store_last_sent_status(message)
109
+ component_id = message.attribute('cId')
110
+ @last_status_sent ||= {}
111
+ @last_status_sent[component_id] ||= {}
112
+ message.attribute('sS').each do |item|
113
+ sci = item['sCI']
114
+ n = item['n']
115
+ s = item['s']
116
+ @last_status_sent[component_id][sci] ||= {}
117
+ @last_status_sent[component_id][sci][n] = s
118
+ end
119
+ end
120
+
121
+ def check_on_change_update(subscription, component, code, name)
122
+ return [nil, false] unless subscription[:interval].zero?
123
+
124
+ current = nil
125
+ if component
126
+ current, quality = *(component.get_status code, name)
127
+ current = rsmpify_value(current, quality)
128
+ end
129
+ last_sent = fetch_last_sent_status component.c_id, code, name
130
+ [current, current != last_sent]
131
+ end
132
+
133
+ def interval_update_due?(subscription, now)
134
+ return true if subscription[:last_sent_at].nil?
135
+
136
+ (now - subscription[:last_sent_at]) >= subscription[:interval]
137
+ end
138
+
139
+ def check_status_subscription(subscription, component, code, name, now)
140
+ current, should_send = check_on_change_update(subscription, component, code, name)
141
+ should_send ||= interval_update_due?(subscription, now)
142
+ return [nil, false] unless should_send
143
+
144
+ subscription[:last_sent_at] = now
145
+ [current, true]
146
+ end
147
+
148
+ def status_update_timer(now)
149
+ update_list = {}
150
+
151
+ @status_subscriptions.each_pair do |component_id, by_code|
152
+ component = @site.find_component component_id
153
+ by_code.each_pair do |code, by_name|
154
+ by_name.each_pair do |name, subscription|
155
+ current, should_send = check_status_subscription(subscription, component, code, name, now)
156
+ next unless should_send
157
+
158
+ update_list[component_id] ||= {}
159
+ update_list[component_id][code] ||= {}
160
+ update_list[component_id][code][name] = current
161
+ end
162
+ end
163
+ end
164
+ send_status_updates update_list
165
+ end
166
+
167
+ def build_status_list(component, by_code)
168
+ ss = []
169
+ by_code.each_pair do |code, names|
170
+ names.map do |status_name, value|
171
+ if value
172
+ quality = 'recent'
173
+ else
174
+ value, quality = component.get_status code, status_name
175
+ end
176
+ ss << { 'sCI' => code,
177
+ 'n' => status_name,
178
+ 's' => rsmpify_value(value, quality),
179
+ 'q' => quality }
180
+ end
181
+ end
182
+ ss
183
+ end
184
+
185
+ def send_status_updates(update_list)
186
+ now = clock.to_s
187
+ update_list.each_pair do |component_id, by_code|
188
+ component = @site.find_component component_id
189
+ ss = build_status_list(component, by_code)
190
+ update = StatusUpdate.new({
191
+ 'cId' => component_id,
192
+ 'sTs' => now,
193
+ 'sS' => ss
194
+ })
195
+ apply_nts_message_attributes update
196
+ send_message update
197
+ store_last_sent_status update
198
+ component.status_updates_sent
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,177 @@
1
+ require 'digest'
2
+
3
+ module RSMP
4
+ # Proxy used by sites to connect to a remote supervisor.
5
+ class SupervisorProxy < Proxy
6
+ include Modules::Status
7
+ include Modules::Commands
8
+ include Modules::Alarms
9
+ include Modules::AggregatedStatus
10
+
11
+ attr_reader :supervisor_id, :site
12
+
13
+ def initialize(options)
14
+ super(options.merge(node: options[:site]))
15
+ @site = options[:site]
16
+ @site_settings = @site.site_settings.clone
17
+ @ip = options[:ip]
18
+ @port = options[:port]
19
+ @status_subscriptions = {}
20
+ @sxl = @site_settings['sxl']
21
+ @synthetic_id = Supervisor.build_id_from_ip_port @ip, @port
22
+ end
23
+
24
+ # handle communication
25
+ # if disconnected, then try to reconnect
26
+ def run
27
+ loop do
28
+ connect
29
+ start_reader
30
+ start_handshake
31
+ wait_for_reader # run until disconnected
32
+ break unless reconnect_delay?
33
+ rescue Restart
34
+ @logger.mute @ip, @port
35
+ raise
36
+ rescue RSMP::ConnectionError => e
37
+ log e, level: :error
38
+ break unless reconnect_delay?
39
+ rescue StandardError => e
40
+ distribute_error e, level: :internal
41
+ break unless reconnect_delay?
42
+ ensure
43
+ close
44
+ stop_subtasks
45
+ end
46
+ end
47
+
48
+ def start_handshake
49
+ send_version @site_settings['site_id'], core_versions
50
+ end
51
+
52
+ # connect to the supervisor and initiate handshake supervisor
53
+ def connect
54
+ log "Connecting to supervisor at #{@ip}:#{@port}", level: :info
55
+ self.state = :connecting
56
+ connect_tcp
57
+ @logger.unmute @ip, @port
58
+ log "Connected to supervisor at #{@ip}:#{@port}", level: :info
59
+ rescue SystemCallError => e
60
+ raise ConnectionError, "Could not connect to supervisor at #{@ip}:#{@port}: Errno #{e.errno} #{e}"
61
+ rescue StandardError => e
62
+ raise ConnectionError, "Error while connecting to supervisor at #{@ip}:#{@port}: #{e}"
63
+ end
64
+
65
+ def stop_task
66
+ super
67
+ @last_status_sent = nil
68
+ end
69
+
70
+ def connect_tcp
71
+ @endpoint = IO::Endpoint.tcp(@ip, @port)
72
+
73
+ # this timeout is a workaround for connect hanging on windows if the other side is not present yet
74
+ timeout = @site_settings.dig('timeouts', 'connect') || 1.1
75
+ task.with_timeout timeout do
76
+ @socket = @endpoint.connect
77
+ end
78
+ delay = @site_settings.dig('intervals', 'after_connect')
79
+ task.sleep delay if delay
80
+
81
+ @stream = IO::Stream::Buffered.new(@socket)
82
+ @protocol = RSMP::Protocol.new(@stream) # rsmp messages are json terminated with a form-feed
83
+ self.state = :connected
84
+ rescue Errno::ECONNREFUSED => e # rescue to avoid log output
85
+ log 'Connection refused', level: :warning
86
+ raise e
87
+ end
88
+
89
+ def handshake_complete
90
+ sanitized_sxl_version = RSMP::Schema.sanitize_version(sxl_version)
91
+ log "Connection to supervisor established, using core #{@core_version}, #{sxl} #{sanitized_sxl_version}",
92
+ level: :info
93
+ self.state = :ready
94
+ start_watchdog
95
+ if @site_settings['send_after_connect']
96
+ send_all_aggregated_status
97
+ send_active_alarms
98
+ end
99
+ super
100
+ end
101
+
102
+ def process_message(message)
103
+ case message
104
+ when StatusResponse, StatusUpdate, AggregatedStatus, AlarmIssue
105
+ will_not_handle message
106
+ when AggregatedStatusRequest
107
+ process_aggregated_status_request message
108
+ when CommandRequest
109
+ process_command_request message
110
+ when CommandResponse
111
+ process_command_response message
112
+ when StatusRequest
113
+ process_status_request message
114
+ when StatusSubscribe
115
+ process_status_subcribe message
116
+ when StatusUnsubscribe
117
+ process_status_unsubcribe message
118
+ when Alarm, AlarmAcknowledged, AlarmSuspend, AlarmResume, AlarmRequest
119
+ process_alarm message
120
+ else
121
+ super
122
+ end
123
+ rescue UnknownComponent, UnknownCommand, UnknownStatus,
124
+ MessageRejected, MissingAttribute => e
125
+ dont_acknowledge message, '', e.to_s
126
+ end
127
+
128
+ def acknowledged_first_ingoing(message)
129
+ case message.type
130
+ when 'Watchdog'
131
+ handshake_complete
132
+ end
133
+ end
134
+
135
+ def reconnect_delay?
136
+ return false if @site_settings['intervals']['reconnect'] == :no
137
+
138
+ interval = @site_settings['intervals']['reconnect']
139
+ log "Will try to reconnect again every #{interval} seconds...", level: :info
140
+ @logger.mute @ip, @port
141
+ @task.sleep interval
142
+ true
143
+ end
144
+
145
+ def version_accepted(message)
146
+ log "Received Version message, using RSMP #{@core_version}", message: message, level: :log
147
+ start_timer
148
+ acknowledge message
149
+ @version_determined = true
150
+ send_watchdog
151
+ end
152
+
153
+ def timer(now)
154
+ super
155
+ status_update_timer now if ready?
156
+ end
157
+
158
+ def sxl_version
159
+ @site_settings['sxl_version'].to_s
160
+ end
161
+
162
+ def process_version(message)
163
+ return extraneous_version message if @version_determined
164
+
165
+ check_core_version message
166
+ check_sxl_version message
167
+ @site_id = Supervisor.build_id_from_ip_port @ip, @port
168
+ version_accepted message
169
+ end
170
+
171
+ def check_sxl_version(message); end
172
+
173
+ def main
174
+ @site.main
175
+ end
176
+ end
177
+ end
@@ -1,24 +1,25 @@
1
1
  module RSMP
2
2
  module TLC
3
+ # Detector logic component for the TLC.
3
4
  class DetectorLogic < Component
4
5
  attr_reader :forced, :value
5
6
 
6
- def initialize node:, id:
7
- super node: node, id: id, grouped: false
7
+ def initialize(node:, id:)
8
+ super(node: node, id: id, grouped: false)
8
9
  @forced = 0
9
10
  @value = 0
10
11
  end
11
12
 
12
- def get_status code, name=nil, options={}
13
+ def get_status(code, name = nil, _options = {})
13
14
  case code
14
15
  when 'S0201', 'S0202', 'S0203', 'S0204'
15
- return send("handle_#{code.downcase}", code, name)
16
+ send("handle_#{code.downcase}", code, name)
16
17
  else
17
- raise InvalidMessage.new "unknown status code #{code}"
18
+ raise InvalidMessage, "unknown status code #{code}"
18
19
  end
19
20
  end
20
21
 
21
- def handle_s0201 status_code, status_name=nil, options={}
22
+ def handle_s0201(_status_code, status_name = nil, _options = {})
22
23
  case status_name
23
24
  when 'starttime'
24
25
  TrafficControllerSite.make_status @node.clock.to_s
@@ -27,7 +28,7 @@ module RSMP
27
28
  end
28
29
  end
29
30
 
30
- def handle_s0202 status_code, status_name=nil, options={}
31
+ def handle_s0202(_status_code, status_name = nil, _options = {})
31
32
  case status_name
32
33
  when 'starttime'
33
34
  TrafficControllerSite.make_status @node.clock.to_s
@@ -36,7 +37,7 @@ module RSMP
36
37
  end
37
38
  end
38
39
 
39
- def handle_s0203 status_code, status_name=nil, options={}
40
+ def handle_s0203(_status_code, status_name = nil, _options = {})
40
41
  case status_name
41
42
  when 'starttime'
42
43
  TrafficControllerSite.make_status @node.clock.to_s
@@ -45,57 +46,41 @@ module RSMP
45
46
  end
46
47
  end
47
48
 
48
- def handle_s0204 status_code, status_name=nil, options={}
49
+ def handle_s0204(_status_code, status_name = nil, _options = {})
49
50
  case status_name
50
51
  when 'starttime'
51
52
  TrafficControllerSite.make_status @node.clock.to_s
52
- when 'P'
53
- TrafficControllerSite.make_status 0
54
- when 'PS'
55
- TrafficControllerSite.make_status 0
56
- when 'L'
57
- TrafficControllerSite.make_status 0
58
- when 'LS'
59
- TrafficControllerSite.make_status 0
60
- when 'B'
61
- TrafficControllerSite.make_status 0
62
- when 'SP'
63
- TrafficControllerSite.make_status 0
64
- when 'MC'
65
- TrafficControllerSite.make_status 0
66
- when 'C'
67
- TrafficControllerSite.make_status 0
68
- when 'F'
53
+ when 'P', 'PS', 'L', 'LS', 'B', 'SP', 'MC', 'C', 'F'
69
54
  TrafficControllerSite.make_status 0
70
55
  end
71
56
  end
72
57
 
73
- def handle_command command_code, arg, options={}
58
+ def handle_command(command_code, arg, _options = {})
74
59
  case command_code
75
60
  when 'M0008'
76
61
  handle_m0008 arg
77
62
  else
78
- raise UnknownCommand.new "Unknown command #{command_code}"
63
+ raise UnknownCommand, "Unknown command #{command_code}"
79
64
  end
80
65
  end
81
66
 
82
- def handle_m0008 arg, options={}
67
+ def handle_m0008(arg, _options = {})
83
68
  @node.verify_security_code 2, arg['securityCode']
84
- status = arg['status']=='True'
85
- mode = arg['mode']=='True'
69
+ status = arg['status'] == 'True'
70
+ mode = arg['mode'] == 'True'
86
71
  force_detector_logic status, mode
87
72
  arg
88
73
  end
89
74
 
90
- def force_detector_logic forced, value
75
+ def force_detector_logic(forced, value)
91
76
  @forced = forced
92
77
  @value = value
93
78
  if @forced
94
79
  log "Forcing to #{value}", level: :info
95
80
  else
96
- log "Releasing", level: :info
81
+ log 'Releasing', level: :info
97
82
  end
98
83
  end
99
84
  end
100
85
  end
101
- end
86
+ end