rsmp 0.1.27 → 0.1.33

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bae0b092e316d3d2fd5297d6c7a36bbe84f80150dd093d101c0c49916f4b93ba
4
- data.tar.gz: 3fb3f09d863c7309e0eae3c61f0a31e3068d5d80ad520f706c4ed437f2414e90
3
+ metadata.gz: ea326578bffa5b75bcd86c0829215d0111b3ba52c88bba7110cca3b9cc0f9fa9
4
+ data.tar.gz: b7d197a3430be8922429ce5ac5ce3512900d85b4b9d276d5d283f150082a3303
5
5
  SHA512:
6
- metadata.gz: 0ca10d29c54b8bcf3c7b359c78838b03f64c50b90c988d1cf2390bf392bad26570b7618045409a8b182df1cbcecd4c820be3ab535a47211c3149bdbcc9ccaab7
7
- data.tar.gz: de933522e4f50fbd861bac067e803e56cad258903ab4a654ee7f994fc0d7c34150c6d70c55f8350e0e73a38e70673db9111bff4a2086b42628a85a71edf50b9b
6
+ metadata.gz: '09ad5202d5feb194cdd9e54177f86910631ac260cd94e5afccdf1a386260de91063b438e5e6dc8675703fdaae8112036f6940793f7d3a266e84827ed38d465c1'
7
+ data.tar.gz: c37dcaac65b0c1a692ef95507ad25f1fa0e78bdfa089758b8511af331e2f47b1bb497cf1452442ad7f9fbf34f8860c9408eeb1674cb3084337ce4fd3b4f552eb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.1.27)
4
+ rsmp (0.1.33)
5
5
  async (~> 1.28.7)
6
6
  async-io (~> 1.30.2)
7
7
  colorize (~> 0.8.1)
@@ -1,23 +1,12 @@
1
1
  port: 12111
2
- rsmp_versions:
3
- - 3.1.1
4
- - 3.1.2
5
- - 3.1.3
6
- - 3.1.4
7
- - 3.1.5
8
-
9
- sites:
10
- :any:
11
- sxl: tlc
12
-
13
- watchdog_interval: 0.1
14
- watchdog_timeout: 0.2
15
- acknowledgement_timeout: 0.2
16
- store_messages: false
17
- command_response_timeout: 0.1
18
- status_response_timeout: 0.1
19
- status_update_timeout: 0.1
20
-
2
+ guest:
3
+ sxl: tlc
4
+ intervals:
5
+ timer: 0.1
6
+ watchdog: 0.1
7
+ timeouts:
8
+ watchdog: 0.2
9
+ acknowledgement: 0.2
21
10
  log:
22
11
  active: true
23
12
  color: true
@@ -33,4 +22,3 @@ log:
33
22
  json: true
34
23
  acknowledgements: false
35
24
  watchdogs: false
36
-
data/config/tlc.yaml CHANGED
@@ -2,15 +2,8 @@ site_id: RN+SI0001
2
2
  supervisors:
3
3
  - ip: 127.0.0.1
4
4
  port: 12111
5
-
6
- # if you leave it out, all know version will be allowed
7
- #rsmp_versions:
8
- # - 3.1.4
9
- # - 3.1.5
10
-
11
5
  sxl: tlc
12
6
  sxl_version: 1.0.15
13
-
14
7
  components:
15
8
  main:
16
9
  TC:
@@ -26,15 +19,16 @@ components:
26
19
  plan: 'BBB1NB'
27
20
  detector_logic:
28
21
  DL1:
29
- watchdog_interval: 0.1
30
- watchdog_timeout: 0.2
31
- acknowledgement_timeout: 0.2
32
- reconnect_interval: 0.1
33
-
22
+ intervals:
23
+ timer: 0.1
24
+ watchdog: 0.1
25
+ reconnect: 0.1
26
+ timeouts:
27
+ watchdog: 0.2
28
+ acknowledgement: 0.2
34
29
  security_codes:
35
30
  1: '1111'
36
31
  2: '2222'
37
-
38
32
  log:
39
33
  active: true
40
34
  color: true
@@ -49,4 +43,3 @@ log:
49
43
  json: true
50
44
  acknowledgements: false
51
45
  watchdogs: false
52
-
data/lib/rsmp.rb CHANGED
@@ -10,6 +10,7 @@ require 'json_schemer'
10
10
  require 'async/queue'
11
11
 
12
12
  require 'rsmp/rsmp'
13
+ require 'rsmp/deep_merge'
13
14
  require 'rsmp/inspect'
14
15
  require 'rsmp/logging'
15
16
  require 'rsmp/wait'
data/lib/rsmp/cli.rb CHANGED
@@ -30,12 +30,12 @@ module RSMP
30
30
  end
31
31
 
32
32
  if options[:supervisors]
33
+ settings['supervisors'] = []
33
34
  options[:supervisors].split(',').each do |supervisor|
34
- settings[:supervisors] ||= []
35
35
  ip, port = supervisor.split ':'
36
36
  ip = '127.0.0.1' if ip.empty?
37
37
  port = '12111' if port.empty?
38
- settings[:supervisors] << {"ip"=>ip, "port"=>port}
38
+ settings['supervisors'] << {"ip"=>ip, "port"=>port}
39
39
  end
40
40
  end
41
41
 
@@ -61,6 +61,8 @@ module RSMP
61
61
  puts "Cannot start site: #{e}"
62
62
  rescue RSMP::Schemer::UnknownSchemaVersionError => e
63
63
  puts "Cannot start site: #{e}"
64
+ rescue Psych::SyntaxError => e
65
+ puts "Cannot read config file #{e}"
64
66
  end
65
67
 
66
68
  desc "supervisor", "Run RSMP supervisor"
@@ -28,7 +28,7 @@ module RSMP
28
28
  @aggregated_status_bools[5] = true
29
29
  end
30
30
 
31
- def set_aggregated_status status
31
+ def set_aggregated_status status, options={}
32
32
  status = [status] if status.is_a? Symbol
33
33
  raise InvalidArgument unless status.is_a? Array
34
34
  input = status & AGGREGATED_STATUS_KEYS
@@ -36,7 +36,7 @@ module RSMP
36
36
  AGGREGATED_STATUS_KEYS.each_with_index do |key,index|
37
37
  @aggregated_status_bools[index] = status.include?(key)
38
38
  end
39
- aggrated_status_changed
39
+ aggrated_status_changed options
40
40
  end
41
41
  end
42
42
 
@@ -54,8 +54,8 @@ module RSMP
54
54
  end
55
55
  end
56
56
 
57
- def aggrated_status_changed
58
- @node.aggrated_status_changed self
57
+ def aggrated_status_changed options={}
58
+ @node.aggrated_status_changed self, options
59
59
  end
60
60
 
61
61
  def alarm code:, status:
@@ -8,7 +8,7 @@ module RSMP
8
8
  @components = {}
9
9
  end
10
10
 
11
- def aggrated_status_changed component
11
+ def aggrated_status_changed component, options={}
12
12
  end
13
13
 
14
14
  def setup_components settings
@@ -0,0 +1,11 @@
1
+ class Hash
2
+ def deep_merge(other_hash)
3
+ self.merge(other_hash) do |key, old, fresh|
4
+ if old.is_a?(Hash) && fresh.is_a?(Hash)
5
+ old.deep_merge(fresh)
6
+ else
7
+ fresh
8
+ end
9
+ end
10
+ end
11
+ end
data/lib/rsmp/proxy.rb CHANGED
@@ -22,10 +22,10 @@ module RSMP
22
22
  @port = options[:port]
23
23
  @connection_info = options[:info]
24
24
  @sxl = nil
25
+ @site_settings = nil # can't pick until we know the site id
25
26
  initialize_distributor
26
27
 
27
- prepare_collection options[:settings]['collect']
28
-
28
+ prepare_collection @settings['collect']
29
29
  clear
30
30
  end
31
31
 
@@ -144,14 +144,14 @@ module RSMP
144
144
  end
145
145
 
146
146
  def start_watchdog
147
- log "Starting watchdog with interval #{@settings["watchdog_interval"]} seconds", level: :debug
147
+ log "Starting watchdog with interval #{@site_settings['intervals']['watchdog']} seconds", level: :debug
148
148
  send_watchdog
149
149
  @watchdog_started = true
150
150
  end
151
151
 
152
152
  def start_timer
153
153
  name = "timer"
154
- interval = @settings["timer_interval"] || 1
154
+ interval = @site_settings['intervals']['timer'] || 1
155
155
  log "Starting #{name} with interval #{interval} seconds", level: :debug
156
156
  @latest_watchdog_received = Clock.now
157
157
 
@@ -189,7 +189,7 @@ module RSMP
189
189
 
190
190
  def watchdog_send_timer now
191
191
  return unless @watchdog_started
192
- return if @settings["watchdog_interval"] == :never
192
+ return if @site_settings['intervals']['watchdog'] == :never
193
193
 
194
194
  if @latest_watchdog_send_at == nil
195
195
  send_watchdog now
@@ -197,7 +197,7 @@ module RSMP
197
197
  # we add half the timer interval to pick the timer
198
198
  # event closes to the wanted wathcdog interval
199
199
  diff = now - @latest_watchdog_send_at
200
- if (diff + 0.5*@settings["timer_interval"]) >= (@settings["watchdog_interval"])
200
+ if (diff + 0.5*@site_settings['intervals']['timer']) >= (@site_settings['intervals']['watchdog'])
201
201
  send_watchdog now
202
202
  end
203
203
  end
@@ -210,7 +210,7 @@ module RSMP
210
210
  end
211
211
 
212
212
  def check_ack_timeout now
213
- timeout = @settings["acknowledgement_timeout"]
213
+ timeout = @site_settings['timeouts']['acknowledgement']
214
214
  # hash cannot be modify during iteration, so clone it
215
215
  @awaiting_acknowledgement.clone.each_pair do |m_id, message|
216
216
  latest = message.timestamp + timeout
@@ -222,7 +222,7 @@ module RSMP
222
222
  end
223
223
 
224
224
  def check_watchdog_timeout now
225
- timeout = @settings["watchdog_timeout"]
225
+ timeout = @site_settings['timeouts']['watchdog']
226
226
  latest = @latest_watchdog_received + timeout
227
227
  left = latest - now
228
228
  if left < 0
@@ -360,13 +360,20 @@ module RSMP
360
360
  dont_acknowledge message, "Received", "extraneous Version message"
361
361
  end
362
362
 
363
+ def rsmp_versions
364
+ return ['3.1.5'] if @site_settings["rsmp_versions"] == 'latest'
365
+ return ['3.1.1','3.1.2','3.1.3','3.1.4','3.1.5'] if @site_settings["rsmp_versions"] == 'all'
366
+ @site_settings["rsmp_versions"]
367
+ end
368
+
363
369
  def check_rsmp_version message
370
+ versions = rsmp_versions
364
371
  # find versions that both we and the client support
365
- candidates = message.versions & @settings["rsmp_versions"]
372
+ candidates = message.versions & versions
366
373
  if candidates.any?
367
374
  @rsmp_version = candidates.sort_by { |v| Gem::Version.new(v) }.last # pick latest version
368
375
  else
369
- raise FatalError.new "RSMP versions [#{message.versions.join(',')}] requested, but only [#{@settings["rsmp_versions"].join(',')}] supported."
376
+ raise FatalError.new "RSMP versions [#{message.versions.join(',')}] requested, but only [#{versions.join(',')}] supported."
370
377
  end
371
378
  end
372
379
 
@@ -410,7 +417,15 @@ module RSMP
410
417
  end
411
418
 
412
419
  def send_version site_id, rsmp_versions
413
- versions_array = [rsmp_versions].flatten.map {|v| {"vers" => v} }
420
+ if rsmp_versions=='latest'
421
+ versions = ['3.1.5']
422
+ elsif rsmp_versions=='all'
423
+ versions = ['3.1.1','3.1.2','3.1.3','3.1.4','3.1.5']
424
+ else
425
+ versions = [rsmp_versions].flatten
426
+ end
427
+ versions_array = versions.map {|v| {"vers" => v} }
428
+
414
429
  site_id_array = [site_id].flatten.map {|id| {"sId" => id} }
415
430
 
416
431
  version_response = Version.new({
@@ -513,18 +528,6 @@ module RSMP
513
528
  def version_acknowledged
514
529
  end
515
530
 
516
- def wait_for_acknowledgement original, timeout
517
- raise ArgumentError unless original
518
- wait_for(@acknowledgement_condition,timeout) do |message|
519
- if message.is_a?(MessageNotAck) && message.attributes["oMId"] == original.m_id
520
- raise RSMP::MessageRejected.new(message.attributes['rea'])
521
- end
522
- message.is_a?(MessageAck) && message.attributes["oMId"] == original.m_id
523
- end
524
- rescue Async::TimeoutError
525
- raise RSMP::TimeoutError.new("Acknowledgement for #{original.type} #{original.m_id} not received within #{timeout}s")
526
- end
527
-
528
531
  def node
529
532
  raise 'Must be overridden'
530
533
  end
@@ -532,5 +535,29 @@ module RSMP
532
535
  def author
533
536
  node.site_id
534
537
  end
538
+
539
+ def wait_for_acknowledgement parent_task, options={}, m_id
540
+ collect(parent_task,options.merge({
541
+ type: ['MessageAck','MessageNotAck'],
542
+ num: 1
543
+ })) do |message|
544
+ if message.is_a?(MessageNotAck)
545
+ if message.attribute('oMId') == m_id
546
+ # set result to an exception, but don't raise it.
547
+ # this will be returned by the task and stored as the task result
548
+ # when the parent task call wait() on the task, the exception
549
+ # will be raised in the parent task, and caught by rspec.
550
+ # rspec will then show the error and record the test as failed
551
+ m_id_short = RSMP::Message.shorten_m_id m_id, 8
552
+ result = RSMP::MessageRejected.new "Aggregated status request #{m_id_short} was rejected: #{message.attribute('rea')}"
553
+ next true # done, no more messages wanted
554
+ end
555
+ elsif message.is_a?(MessageAck)
556
+ next true if message.attribute('oMId') == m_id
557
+ end
558
+ false
559
+ end
560
+ end
561
+
535
562
  end
536
563
  end
data/lib/rsmp/site.rb CHANGED
@@ -14,48 +14,39 @@ module RSMP
14
14
  super options
15
15
  @proxies = []
16
16
  @sleep_condition = Async::Notification.new
17
+ @proxies_condition = Async::Notification.new
17
18
  end
18
19
 
19
20
  def site_id
20
21
  @site_settings['site_id']
21
22
  end
22
23
 
23
- def handle_site_settings options
24
- @site_settings = {
24
+ def handle_site_settings options={}
25
+ defaults = {
25
26
  'site_id' => 'RN+SI0001',
26
27
  'supervisors' => [
27
28
  { 'ip' => '127.0.0.1', 'port' => 12111 }
28
29
  ],
29
- 'rsmp_versions' => ['3.1.1','3.1.2','3.1.3','3.1.4','3.1.5'],
30
+ 'rsmp_versions' => 'all',
30
31
  'sxl' => 'tlc',
31
32
  'sxl_version' => '1.0.15',
32
- 'timer_interval' => 0.1,
33
- 'watchdog_interval' => 1,
34
- 'watchdog_timeout' => 2,
35
- 'acknowledgement_timeout' => 2,
36
- 'command_response_timeout' => 1,
37
- 'status_response_timeout' => 1,
38
- 'status_update_timeout' => 1,
39
- 'site_connect_timeout' => 2,
40
- 'site_ready_timeout' => 1,
41
- 'reconnect_interval' => 0.1,
33
+ 'intervals' => {
34
+ 'timer' => 0.1,
35
+ 'watchdog' => 1,
36
+ 'reconnect' => 0.1
37
+ },
38
+ 'timeouts' => {
39
+ 'watchdog' => 2,
40
+ 'acknowledgement' => 2
41
+ },
42
42
  'send_after_connect' => true,
43
43
  'components' => {
44
44
  'C1' => {}
45
45
  }
46
46
  }
47
- if options[:site_settings]
48
- converted = options[:site_settings].map { |k,v| [k.to_s,v] }.to_h #convert symbol keys to string keys
49
- converted.compact!
50
- @site_settings.merge! converted
51
- end
52
-
53
- required = [:supervisors,:rsmp_versions,:site_id,:watchdog_interval,:watchdog_timeout,
54
- :acknowledgement_timeout,:command_response_timeout]
55
- check_required_settings @site_settings, required
56
-
47
+
48
+ @site_settings = defaults.deep_merge options[:site_settings]
57
49
  check_sxl_version
58
-
59
50
  setup_components @site_settings['components']
60
51
  end
61
52
 
@@ -84,9 +75,9 @@ module RSMP
84
75
  SupervisorProxy.new settings
85
76
  end
86
77
 
87
- def aggrated_status_changed component
78
+ def aggrated_status_changed component, options={}
88
79
  @proxies.each do |proxy|
89
- proxy.send_aggregated_status component
80
+ proxy.send_aggregated_status component, options
90
81
  end
91
82
  end
92
83
 
@@ -101,9 +92,11 @@ module RSMP
101
92
  archive: @archive
102
93
  })
103
94
  @proxies << proxy
95
+ @proxies_condition.signal
104
96
  run_site_proxy task, proxy
105
97
  ensure
106
98
  @proxies.delete proxy
99
+ @proxies_condition.signal
107
100
  end
108
101
 
109
102
  def run_site_proxy task, proxy
@@ -115,10 +108,10 @@ module RSMP
115
108
  notify_error e, level: :internal
116
109
  ensure
117
110
  begin
118
- if @site_settings["reconnect_interval"] != :no
111
+ if @site_settings['intervals']['watchdog'] != :no
119
112
  # sleep until waken by reconnect() or the reconnect interval passed
120
113
  proxy.set_state :wait_for_reconnect
121
- task.with_timeout(@site_settings["reconnect_interval"]) do
114
+ task.with_timeout(@site_settings['intervals']['watchdog']) do
122
115
  @sleep_condition.wait
123
116
  end
124
117
  else
@@ -152,5 +145,19 @@ module RSMP
152
145
  end
153
146
  end
154
147
 
148
+ def wait_for_supervisor ip, timeout
149
+ supervisor = find_supervisor ip
150
+ return supervisor if supervisor
151
+ wait_for(@proxy_condition,timeout) { find_supervisor ip }
152
+ rescue Async::TimeoutError
153
+ raise RSMP::TimeoutError.new "Supervisor '#{ip}' did not connect within #{timeout}s"
154
+ end
155
+
156
+ def find_supervisor ip
157
+ @proxies.each do |supervisor|
158
+ return supervisor if ip == :any || supervisor.ip == ip
159
+ end
160
+ nil
161
+ end
155
162
  end
156
163
  end
@@ -36,7 +36,7 @@ module RSMP
36
36
 
37
37
  def connection_complete
38
38
  super
39
- log "Connection to site #{@site_id} established, using core #{@rsmp_version}, sxl #{@sxl} #{@site_sxl_version}", level: :info
39
+ log "Connection to site #{@site_id} established, using core #{@rsmp_version}, #{@sxl} #{@site_sxl_version}", level: :info
40
40
  end
41
41
 
42
42
  def process_message message
@@ -73,21 +73,10 @@ module RSMP
73
73
  end
74
74
 
75
75
  def version_accepted message
76
- if @settings['sites']
77
- @site_settings = @settings['sites'][@site_id]
78
- @site_settings = @settings['sites'][:any] unless @site_settings
79
- if @site_settings
80
- @sxl = @site_settings['sxl']
81
- setup_components @site_settings['components']
82
- else
83
- dont_acknowledge message, 'Rejected', "No config found for site #{@site_id}"
84
- end
85
- end
86
-
87
76
  log "Received Version message for site #{@site_id}", message: message, level: :log
88
77
  start_timer
89
78
  acknowledge message
90
- send_version @site_id, @settings['rsmp_versions']
79
+ send_version @site_id, rsmp_versions
91
80
  @version_determined = true
92
81
 
93
82
  end
@@ -145,7 +134,7 @@ module RSMP
145
134
  acknowledge message
146
135
  end
147
136
 
148
- def aggrated_status_changed component
137
+ def aggrated_status_changed component, options={}
149
138
  @supervisor.aggregated_status_changed self, component
150
139
  end
151
140
 
@@ -309,7 +298,7 @@ module RSMP
309
298
  end
310
299
 
311
300
  def set_watchdog_interval interval
312
- @settings["watchdog_interval"] = interval
301
+ @settings['intervals']['watchdog'] = interval
313
302
  end
314
303
 
315
304
  def check_sxl_version message
@@ -347,9 +336,35 @@ module RSMP
347
336
  site_id = message.attribute("siteId").map { |item| item["sId"] }.first
348
337
  @supervisor.check_site_id site_id
349
338
  @site_id = site_id
339
+ setup_site_settings
350
340
  site_ids_changed
351
341
  end
352
342
 
343
+ def find_site_settings site_id
344
+ if @settings['sites'] && @settings['sites'][@site_id]
345
+ log "Using site settings for site id #{@site_id}", level: :debug
346
+ return @settings['sites'][@site_id]
347
+ end
348
+
349
+ settings = @settings['guest']
350
+ if @settings['guest']
351
+ log "Using site settings for guest", level: :debug
352
+ return @settings['guest']
353
+ end
354
+
355
+ nil
356
+ end
357
+
358
+ def setup_site_settings
359
+ @site_settings = find_site_settings @site_id
360
+ if @site_settings
361
+ @sxl = @site_settings['sxl']
362
+ setup_components @site_settings['components']
363
+ else
364
+ dont_acknowledge message, 'Rejected', "No config found for site #{@site_id}"
365
+ end
366
+ end
367
+
353
368
  def notify_error e, options={}
354
369
  @supervisor.notify_error e, options if @supervisor
355
370
  end
@@ -2,24 +2,6 @@
2
2
  module RSMP
3
3
  module SiteProxyWait
4
4
 
5
- def wait_for_status_updates parent_task, options={}, &send_block
6
- send_while_collecting parent_task, send_block do |task, m_id|
7
- collect_status_updates_or_responses task, 'StatusUpdate', options, m_id
8
- end
9
- end
10
-
11
- def wait_for_status_responses parent_task, options={}, &send_block
12
- send_while_collecting parent_task, send_block do |task, m_id|
13
- collect_status_updates_or_responses task, 'StatusResponse', options, m_id
14
- end
15
- end
16
-
17
- def wait_for_command_responses parent_task, options={}, &send_block
18
- send_while_collecting parent_task, send_block do |task, m_id|
19
- collect_command_responses task, options, m_id
20
- end
21
- end
22
-
23
5
  def wait_for_alarm parent_task, options={}
24
6
  matching_alarm = nil
25
7
  message = collect(parent_task,options.merge(type: "Alarm", with_message: true, num: 1)) do |message|
@@ -161,23 +143,6 @@ module RSMP
161
143
  true
162
144
  end
163
145
 
164
- def send_while_collecting parent_task, send_block, &collect_block
165
- m_id = RSMP::Message.make_m_id # make message id so we can start waiting for it
166
-
167
- # wait for command responses in an async task
168
- task = parent_task.async do |task|
169
- collect_block.call task, m_id
170
- rescue StandardError => e
171
- notify_error e, level: :internal
172
- end
173
-
174
- # call block, it should send command request using the given m_id
175
- send_block.call m_id
176
-
177
- # wait for the response and return it, raise exception if NotAck received, it it timed out
178
- task.wait
179
- end
180
-
181
146
  def wait_for_aggregated_status parent_task, options={}
182
147
  collect(parent_task,options.merge({
183
148
  type: ['AggregatedStatus','MessageNotAck'],
@@ -17,55 +17,45 @@ module RSMP
17
17
  @supervisor_settings['site_id']
18
18
  end
19
19
 
20
- def handle_supervisor_settings options
21
- @supervisor_settings = {
20
+ def handle_supervisor_settings options={}
21
+ defaults = {
22
22
  'port' => 12111,
23
- 'rsmp_versions' => ['3.1.1','3.1.2','3.1.3','3.1.4','3.1.5'],
24
- 'timer_interval' => 0.1,
25
- 'watchdog_interval' => 1,
26
- 'watchdog_timeout' => 2,
27
- 'acknowledgement_timeout' => 2,
28
- 'command_response_timeout' => 1,
29
- 'status_response_timeout' => 1,
30
- 'status_update_timeout' => 1,
31
- 'site_connect_timeout' => 2,
32
- 'site_ready_timeout' => 1,
33
- 'stop_after_first_session' => false,
34
- 'sites' => {
35
- :any => {
36
- 'sxl' => 'tlc'
23
+ 'ips' => 'all',
24
+ 'guest' => {
25
+ 'rsmp_versions' => 'all',
26
+ 'sxl' => 'tlc',
27
+ 'intervals' => {
28
+ 'timer' => 1,
29
+ 'watchdog' => 1
30
+ },
31
+ 'timeouts' => {
32
+ 'watchdog' => 2,
33
+ 'acknowledgement' => 2
37
34
  }
38
35
  }
39
36
  }
40
-
41
- if options[:supervisor_settings]
42
- converted = options[:supervisor_settings].map { |k,v| [k.to_s,v] }.to_h #convert symbol keys to string keys
43
- converted.compact!
44
- @supervisor_settings.merge! converted
45
- end
46
-
47
- required = [:port, :rsmp_versions, :watchdog_interval, :watchdog_timeout,
48
- :acknowledgement_timeout, :command_response_timeout]
49
- check_required_settings @supervisor_settings, required
50
37
 
38
+ # merge options into defaults
39
+ @supervisor_settings = defaults.deep_merge(options[:supervisor_settings] || {})
51
40
  @rsmp_versions = @supervisor_settings["rsmp_versions"]
52
-
53
41
  check_site_sxl_types
54
42
  end
55
43
 
56
44
  def check_site_sxl_types
57
- @supervisor_settings['sites'].each do |ip,settings|
45
+ sites = @supervisor_settings['sites'].clone || {}
46
+ sites['guest'] = @supervisor_settings['guest']
47
+ sites.each do |site_id,settings|
58
48
  unless settings
59
- raise RSMP::ConfigurationError.new("Configuration for site '#{ip}' is empty")
49
+ raise RSMP::ConfigurationError.new("Configuration for site '#{site_id}' is empty")
60
50
  end
61
51
  sxl = settings['sxl']
62
52
  sxl = 'tlc' unless sxl # temporary fix until configs are updated
63
53
  unless sxl
64
- raise RSMP::ConfigurationError.new("Configuration error for site '#{ip}': No SXL specified")
54
+ raise RSMP::ConfigurationError.new("Configuration error for site '#{site_id}': No SXL specified")
65
55
  end
66
56
  RSMP::Schemer.find_schemas! sxl if sxl
67
57
  rescue RSMP::Schemer::UnknownSchemaError => e
68
- raise RSMP::ConfigurationError.new("Configuration error for site '#{ip}': #{e}")
58
+ raise RSMP::ConfigurationError.new("Configuration error for site '#{site_id}': #{e}")
69
59
  end
70
60
  end
71
61
 
@@ -101,7 +91,8 @@ module RSMP
101
91
  reject socket, info
102
92
  end
103
93
  rescue ConnectionError => e
104
- log "Rejected connection from #{remote_ip}, #{e.to_s}", level: :info
94
+ log "Rejected connection from #{remote_ip}:#{remote_port}, #{e.to_s}", level: :warning
95
+ notify_error e
105
96
  rescue StandardError => e
106
97
  log "Connection: #{e.to_s}", exception: e, level: :error
107
98
  notify_error e, level: :internal
@@ -131,6 +122,21 @@ module RSMP
131
122
  end
132
123
  end
133
124
 
125
+ def authorize_ip ip
126
+ return if @supervisor_settings['ips'] == 'all'
127
+ return if @supervisor_settings['ips'].include? ip
128
+ raise ConnectionError.new('guest ip not allowed')
129
+ end
130
+
131
+ def check_max_sites
132
+ max = @supervisor_settings['max_sites']
133
+ if max
134
+ if @proxies.size >= max
135
+ raise ConnectionError.new("maximum of #{max} sites already connected")
136
+ end
137
+ end
138
+ end
139
+
134
140
  def connect socket, info
135
141
  log "Site connected from #{format_ip_and_port(info)}",
136
142
  ip: info[:ip],
@@ -138,15 +144,15 @@ module RSMP
138
144
  level: :info,
139
145
  timestamp: Clock.now
140
146
 
141
- settings = ip_to_site_settings info[:ip]
142
- raise ConnectionError.new('unknown ip not allowed') unless settings
147
+ authorize_ip info[:ip]
148
+ check_max_sites
143
149
 
144
150
  proxy = build_proxy({
145
151
  supervisor: self,
146
152
  ip: info[:ip],
147
153
  port: info[:port],
148
154
  task: @task,
149
- settings: settings,
155
+ settings: {'collect'=>@supervisor_settings['collect']},
150
156
  socket: socket,
151
157
  info: info,
152
158
  logger: @logger,
@@ -158,7 +164,7 @@ module RSMP
158
164
  @proxies.delete proxy
159
165
  site_ids_changed
160
166
 
161
- stop if @supervisor_settings['stop_after_first_session']
167
+ stop if @supervisor_settings['one_shot']
162
168
  end
163
169
 
164
170
  def site_ids_changed
@@ -195,36 +201,36 @@ module RSMP
195
201
  return site if site
196
202
  wait_for(@site_id_condition,timeout) { find_site site_id }
197
203
  rescue Async::TimeoutError
198
- raise RSMP::TimeoutError.new "Site '#{site_id}'' did not connect within #{timeout}s"
204
+ raise RSMP::TimeoutError.new "Site '#{site_id}' did not connect within #{timeout}s"
199
205
  end
200
206
 
201
207
  def wait_for_site_disconnect site_id, timeout
202
208
  wait_for(@site_id_condition,timeout) { true unless find_site site_id }
203
209
  rescue Async::TimeoutError
204
- raise RSMP::TimeoutError.new "Site '#{site_id}'' did not disconnect within #{timeout}s"
210
+ raise RSMP::TimeoutError.new "Site '#{site_id}' did not disconnect within #{timeout}s"
205
211
  end
206
212
 
207
213
  def check_site_id site_id
208
214
  check_site_already_connected site_id
209
- return find_allowed_site_setting site_id
215
+ return site_id_to_site_setting site_id
210
216
  end
211
217
 
212
218
  def check_site_already_connected site_id
213
- raise FatalError.new "Site '#{site_id}'' already connected" if find_site(site_id)
219
+ raise FatalError.new "Site '#{site_id}' already connected" if find_site(site_id)
214
220
  end
215
221
 
216
- def find_allowed_site_setting site_id
222
+ def site_id_to_site_setting site_id
217
223
  return {} unless @supervisor_settings['sites']
218
224
  @supervisor_settings['sites'].each_pair do |id,settings|
219
- if id == :any || id == site_id
225
+ if id == 'guest' || id == site_id
220
226
  return settings
221
227
  end
222
228
  end
223
- raise FatalError.new "site id #{site_id} rejected"
229
+ raise FatalError.new "site id #{site_id} unknown"
224
230
  end
225
231
 
226
232
  def ip_to_site_settings ip
227
- @supervisor_settings['sites'][ip] || @supervisor_settings['sites'][:any]
233
+ @supervisor_settings['sites'][ip] || @supervisor_settings['sites']['guest']
228
234
  end
229
235
 
230
236
  def aggregated_status_changed site_proxy, component
@@ -32,8 +32,8 @@ module RSMP
32
32
  send_version @site_settings['site_id'], @site_settings["rsmp_versions"]
33
33
  rescue Errno::ECONNREFUSED
34
34
  log "No connection to supervisor at #{@ip}:#{@port}", level: :error
35
- unless @site.site_settings["reconnect_interval"] == :no
36
- log "Will try to reconnect again every #{@site.site_settings["reconnect_interval"]} seconds..", level: :info
35
+ unless @site.site_settings['intervals']['reconnect'] == :no
36
+ log "Will try to reconnect again every #{@site.site_settings['intervals']['reconnect']} seconds..", level: :info
37
37
  @logger.mute @ip, @port
38
38
  end
39
39
  end
@@ -110,7 +110,7 @@ module RSMP
110
110
  end
111
111
 
112
112
  def reconnect_delay
113
- interval = @site_settings["reconnect_interval"]
113
+ interval = @site_settings['intervals']['reconnect']
114
114
  log "Waiting #{interval} seconds before trying to reconnect", level: :info
115
115
  @task.sleep interval
116
116
  end
@@ -123,15 +123,28 @@ module RSMP
123
123
  @version_determined = true
124
124
  end
125
125
 
126
- def send_aggregated_status component
126
+ def send_aggregated_status component, options={}
127
+ m_id = options[:m_id] || RSMP::Message.make_m_id
127
128
  message = AggregatedStatus.new({
128
129
  "aSTS" => clock.to_s,
129
130
  "cId" => component.c_id,
130
131
  "fP" => 'NormalControl',
131
132
  "fS" => nil,
132
- "se" => component.aggregated_status_bools
133
+ "se" => component.aggregated_status_bools,
134
+ "mId" => m_id
133
135
  })
134
- send_message message
136
+
137
+ if options[:collect]
138
+ result = nil
139
+ task = @task.async do |task|
140
+ wait_for_acknowledgement task, options[:collect], m_id
141
+ end
142
+ send_message message, validate: options[:validate]
143
+ return message, task.wait
144
+ else
145
+ send_message message, validate: options[:validate]
146
+ message
147
+ end
135
148
  end
136
149
 
137
150
  def process_aggregated_status message
data/lib/rsmp/tlc.rb CHANGED
@@ -88,7 +88,11 @@ module RSMP
88
88
  end
89
89
 
90
90
  def format_signal_group_status
91
- @signal_groups.map { |group| group.state }.join
91
+ if @yellow_flash
92
+ 'c' * @signal_groups.size
93
+ else
94
+ @signal_groups.map { |group| group.state }.join
95
+ end
92
96
  end
93
97
 
94
98
  def handle_command command_code, arg
@@ -794,7 +798,7 @@ module RSMP
794
798
  super options
795
799
  @sxl = 'traffic_light_controller'
796
800
  @security_codes = options[:site_settings]['security_codes']
797
- @interval = options[:site_settings]['interval'] || 1
801
+ @interval = options[:site_settings]['intervals']['timer'] || 1
798
802
  unless @main
799
803
  raise ConfigurationError.new "TLC must have a main component"
800
804
  end
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.1.27"
2
+ VERSION = "0.1.33"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsmp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.27
4
+ version: 0.1.33
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Tin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-19 00:00:00.000000000 Z
11
+ date: 2021-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -197,7 +197,6 @@ files:
197
197
  - Rakefile
198
198
  - bin/console
199
199
  - bin/setup
200
- - config/site.yaml
201
200
  - config/supervisor.yaml
202
201
  - config/tlc.yaml
203
202
  - documentation/classes_and_modules.md
@@ -212,6 +211,7 @@ files:
212
211
  - lib/rsmp/components.rb
213
212
  - lib/rsmp/convert/export/json_schema.rb
214
213
  - lib/rsmp/convert/import/yaml.rb
214
+ - lib/rsmp/deep_merge.rb
215
215
  - lib/rsmp/error.rb
216
216
  - lib/rsmp/inspect.rb
217
217
  - lib/rsmp/listener.rb
data/config/site.yaml DELETED
@@ -1,40 +0,0 @@
1
- site_id: RN+SI0001
2
- supervisors:
3
- - ip: 127.0.0.1
4
- port: 12111
5
-
6
- sxl: traffic_light_controller
7
-
8
- rsmp_versions:
9
- - 3.1.1
10
- - 3.1.2
11
- - 3.1.3
12
- - 3.1.4
13
-
14
- components:
15
- main:
16
- C1:
17
-
18
- watchdog_interval: 1
19
- watchdog_timeout: 2
20
- acknowledgement_timeout: 1
21
- command_response_timeout: 1
22
- status_response_timeout: 1
23
- status_update_timeout: 1
24
- reconnect_interval: 0.1
25
-
26
- log:
27
- active: true
28
- color: true
29
- timestamp: true
30
- id: true
31
- component: true
32
- ip: false
33
- site_id: true
34
- level: false
35
- text: true
36
- direction: true
37
- json: true
38
- acknowledgements: false
39
- watchdogs: false
40
-