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
data/lib/rsmp/supervisor.rb
DELETED
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
# RSMP supervisor (server)
|
|
2
|
-
# The supervisor waits for sites to connect.
|
|
3
|
-
# Connections to sites are handles via site proxies.
|
|
4
|
-
|
|
5
|
-
module RSMP
|
|
6
|
-
class Supervisor < Node
|
|
7
|
-
attr_reader :core_version, :site_id, :supervisor_settings, :proxies, :logger, :ready_condition
|
|
8
|
-
|
|
9
|
-
attr_accessor :site_id_condition
|
|
10
|
-
|
|
11
|
-
def initialize options={}
|
|
12
|
-
handle_supervisor_settings( options[:supervisor_settings] || {} )
|
|
13
|
-
super options
|
|
14
|
-
@proxies = []
|
|
15
|
-
@ready_condition = Async::Notification.new
|
|
16
|
-
@site_id_condition = Async::Notification.new
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def site_id
|
|
20
|
-
@supervisor_settings['site_id']
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def handle_supervisor_settings supervisor_settings
|
|
24
|
-
defaults = {
|
|
25
|
-
'port' => 12111,
|
|
26
|
-
'ips' => 'all',
|
|
27
|
-
'guest' => {
|
|
28
|
-
'sxl' => 'tlc',
|
|
29
|
-
'intervals' => {
|
|
30
|
-
'timer' => 1,
|
|
31
|
-
'watchdog' => 1
|
|
32
|
-
},
|
|
33
|
-
'timeouts' => {
|
|
34
|
-
'watchdog' => 2,
|
|
35
|
-
'acknowledgement' => 2
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
# merge options into defaults
|
|
41
|
-
@supervisor_settings = defaults.deep_merge(supervisor_settings)
|
|
42
|
-
@core_version = @supervisor_settings["guest"]["core_version"]
|
|
43
|
-
check_site_sxl_types
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def check_site_sxl_types
|
|
47
|
-
sites = @supervisor_settings['sites'].clone || {}
|
|
48
|
-
sites['guest'] = @supervisor_settings['guest']
|
|
49
|
-
sites.each do |site_id,settings|
|
|
50
|
-
unless settings
|
|
51
|
-
raise RSMP::ConfigurationError.new("Configuration for site '#{site_id}' is empty")
|
|
52
|
-
end
|
|
53
|
-
sxl = settings['sxl']
|
|
54
|
-
unless sxl
|
|
55
|
-
raise RSMP::ConfigurationError.new("Configuration error for site '#{site_id}': No SXL specified")
|
|
56
|
-
end
|
|
57
|
-
RSMP::Schema.find_schemas! sxl if sxl
|
|
58
|
-
rescue RSMP::Schema::UnknownSchemaError => e
|
|
59
|
-
raise RSMP::ConfigurationError.new("Configuration error for site '#{site_id}': #{e}")
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# listen for connections
|
|
64
|
-
def run
|
|
65
|
-
log "Starting supervisor on port #{@supervisor_settings["port"]}",
|
|
66
|
-
level: :info,
|
|
67
|
-
timestamp: @clock.now
|
|
68
|
-
|
|
69
|
-
@endpoint = IO::Endpoint.tcp('0.0.0.0', @supervisor_settings["port"])
|
|
70
|
-
@accept_task = Async::Task.current.async do |task|
|
|
71
|
-
task.annotate "supervisor accept loop"
|
|
72
|
-
@endpoint.accept() do |socket| # creates fibers
|
|
73
|
-
handle_connection(socket)
|
|
74
|
-
rescue StandardError => e
|
|
75
|
-
distribute_error e, level: :internal
|
|
76
|
-
end
|
|
77
|
-
rescue Async::Stop # will happen at shutdown
|
|
78
|
-
rescue StandardError => e
|
|
79
|
-
distribute_error e, level: :internal
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
@ready_condition.signal
|
|
83
|
-
@accept_task.wait
|
|
84
|
-
rescue StandardError => e
|
|
85
|
-
distribute_error e, level: :internal
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# stop
|
|
89
|
-
def stop
|
|
90
|
-
log "Stopping supervisor #{@supervisor_settings["site_id"]}", level: :info
|
|
91
|
-
|
|
92
|
-
@accept_task.stop if @accept_task
|
|
93
|
-
@accept_task = nil
|
|
94
|
-
|
|
95
|
-
@endpoint = nil
|
|
96
|
-
super
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# handle an incoming connction by either accepting of rejecting it
|
|
100
|
-
def handle_connection socket
|
|
101
|
-
remote_port = socket.remote_address.ip_port
|
|
102
|
-
remote_hostname = socket.remote_address.ip_address
|
|
103
|
-
remote_ip = socket.remote_address.ip_address
|
|
104
|
-
|
|
105
|
-
info = {ip:remote_ip, port:remote_port, hostname:remote_hostname, now:Clock.now}
|
|
106
|
-
if accept? socket, info
|
|
107
|
-
accept_connection socket, info
|
|
108
|
-
else
|
|
109
|
-
reject_connection socket, info
|
|
110
|
-
end
|
|
111
|
-
rescue ConnectionError, HandshakeError => e
|
|
112
|
-
log "Rejected connection from #{remote_ip}:#{remote_port}, #{e.to_s}", level: :warning
|
|
113
|
-
distribute_error e
|
|
114
|
-
rescue StandardError => e
|
|
115
|
-
log "Connection: #{e.to_s}", exception: e, level: :error
|
|
116
|
-
distribute_error e, level: :internal
|
|
117
|
-
ensure
|
|
118
|
-
close socket, info
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def accept? socket, info
|
|
122
|
-
true
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def build_proxy settings
|
|
126
|
-
SiteProxy.new settings
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def format_ip_and_port info
|
|
130
|
-
if @logger.settings['hide_ip_and_port']
|
|
131
|
-
'********'
|
|
132
|
-
else
|
|
133
|
-
"#{info[:ip]}:#{info[:port]}"
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def authorize_ip ip
|
|
138
|
-
return if @supervisor_settings['ips'] == 'all'
|
|
139
|
-
return if @supervisor_settings['ips'].include? ip
|
|
140
|
-
raise ConnectionError.new('guest ip not allowed')
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def check_max_sites
|
|
144
|
-
max = @supervisor_settings['max_sites']
|
|
145
|
-
if max
|
|
146
|
-
if @proxies.size >= max
|
|
147
|
-
raise ConnectionError.new("maximum of #{max} sites already connected")
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def peek_version_message protocol
|
|
153
|
-
json = protocol.peek_line
|
|
154
|
-
attributes = Message.parse_attributes json
|
|
155
|
-
Message.build attributes, json
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
# accept an incoming connecting by creating and starting a proxy
|
|
159
|
-
def accept_connection socket, info
|
|
160
|
-
log "Site connected from #{format_ip_and_port(info)}",
|
|
161
|
-
ip: info[:ip],
|
|
162
|
-
port: info[:port],
|
|
163
|
-
level: :info,
|
|
164
|
-
timestamp: Clock.now
|
|
165
|
-
|
|
166
|
-
authorize_ip info[:ip]
|
|
167
|
-
|
|
168
|
-
stream = IO::Stream::Buffered.new(socket)
|
|
169
|
-
protocol = RSMP::Protocol.new stream
|
|
170
|
-
|
|
171
|
-
settings = {
|
|
172
|
-
supervisor: self,
|
|
173
|
-
ip: info[:ip],
|
|
174
|
-
port: info[:port],
|
|
175
|
-
task: @task,
|
|
176
|
-
collect: @collect,
|
|
177
|
-
socket: socket,
|
|
178
|
-
stream: stream,
|
|
179
|
-
protocol: protocol,
|
|
180
|
-
info: info,
|
|
181
|
-
logger: @logger,
|
|
182
|
-
archive: @archive
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
version_message = peek_version_message protocol
|
|
186
|
-
id = version_message.attribute('siteId').first['sId']
|
|
187
|
-
|
|
188
|
-
proxy = find_site id
|
|
189
|
-
if proxy
|
|
190
|
-
if proxy.connected?
|
|
191
|
-
raise ConnectionError.new("Site #{id} alredy connected from port #{proxy.port}")
|
|
192
|
-
else
|
|
193
|
-
proxy.revive settings
|
|
194
|
-
end
|
|
195
|
-
else
|
|
196
|
-
check_max_sites
|
|
197
|
-
proxy = build_proxy settings.merge(site_id:id) # keep the id learned by peeking above
|
|
198
|
-
@proxies.push proxy
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
proxy.setup_site_settings
|
|
202
|
-
proxy.check_core_version version_message
|
|
203
|
-
log "Validating using core version #{proxy.core_version}", level: :debug
|
|
204
|
-
|
|
205
|
-
proxy.start # will run until the site disconnects
|
|
206
|
-
proxy.wait
|
|
207
|
-
ensure
|
|
208
|
-
site_ids_changed
|
|
209
|
-
stop if @supervisor_settings['one_shot']
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
def site_ids_changed
|
|
213
|
-
@site_id_condition.signal
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
def reject_connection socket, info
|
|
217
|
-
log "Site rejected", ip: info[:ip], level: :info
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def close socket, info
|
|
221
|
-
if info
|
|
222
|
-
log "Connection to #{format_ip_and_port(info)} closed", ip: info[:ip], level: :info, timestamp: Clock.now
|
|
223
|
-
else
|
|
224
|
-
log "Connection closed", level: :info, timestamp: Clock.now
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
socket.close
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
def site_connected? site_id
|
|
231
|
-
return find_site(site_id) != nil
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
def find_site_from_ip_port ip, port
|
|
235
|
-
@proxies.each do |site|
|
|
236
|
-
return site if site.ip == ip && site.port == port
|
|
237
|
-
end
|
|
238
|
-
nil
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def find_site site_id
|
|
242
|
-
@proxies.each do |site|
|
|
243
|
-
return site if site_id == :any || site.site_id == site_id
|
|
244
|
-
end
|
|
245
|
-
nil
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def wait_for_site site_id, timeout:
|
|
249
|
-
site = find_site site_id
|
|
250
|
-
return site if site
|
|
251
|
-
wait_for_condition(@site_id_condition,timeout:timeout) do
|
|
252
|
-
find_site site_id
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
rescue Async::TimeoutError
|
|
256
|
-
if site_id == :any
|
|
257
|
-
str = "No site connected"
|
|
258
|
-
else
|
|
259
|
-
str = "Site '#{site_id}' did not connect"
|
|
260
|
-
end
|
|
261
|
-
raise RSMP::TimeoutError.new "#{str} within #{timeout}s"
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
def wait_for_site_disconnect site_id, timeout:
|
|
265
|
-
wait_for_condition(@site_id_condition,timeout:timeout) { true unless find_site site_id }
|
|
266
|
-
rescue Async::TimeoutError
|
|
267
|
-
raise RSMP::TimeoutError.new "Site '#{site_id}' did not disconnect within #{timeout}s"
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
def check_site_id site_id
|
|
271
|
-
#check_site_already_connected site_id
|
|
272
|
-
return site_id_to_site_setting site_id
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def check_site_already_connected site_id
|
|
276
|
-
site = find_site(site_id)
|
|
277
|
-
raise HandshakeError.new "Site '#{site_id}' already connected" if site != nil && site != self
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
def site_id_to_site_setting site_id
|
|
281
|
-
return {} unless @supervisor_settings['sites']
|
|
282
|
-
@supervisor_settings['sites'].each_pair do |id,settings|
|
|
283
|
-
if id == 'guest' || id == site_id
|
|
284
|
-
return settings
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
raise HandshakeError.new "site id #{site_id} unknown"
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
def ip_to_site_settings ip
|
|
291
|
-
@supervisor_settings['sites'][ip] || @supervisor_settings['sites']['guest']
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
def aggregated_status_changed site_proxy, component
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
def self.build_id_from_ip_port ip, port
|
|
298
|
-
Digest::MD5.hexdigest("#{ip}:#{port}")[0..8]
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
end
|
|
302
|
-
end
|