rsmp 0.1.27 → 0.1.33

Sign up to get free protection for your applications and to get access to all the features.
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
-