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.
Files changed (106) 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 +80 -0
  6. data/Gemfile +13 -1
  7. data/Gemfile.lock +34 -1
  8. data/Rakefile +3 -3
  9. data/lib/rsmp/cli.rb +147 -124
  10. data/lib/rsmp/collect/ack_collector.rb +8 -7
  11. data/lib/rsmp/collect/aggregated_status_collector.rb +4 -4
  12. data/lib/rsmp/collect/alarm_collector.rb +31 -23
  13. data/lib/rsmp/collect/alarm_matcher.rb +3 -3
  14. data/lib/rsmp/collect/collector/logging.rb +17 -0
  15. data/lib/rsmp/collect/collector/reporting.rb +44 -0
  16. data/lib/rsmp/collect/collector/status.rb +34 -0
  17. data/lib/rsmp/collect/collector.rb +69 -150
  18. data/lib/rsmp/collect/command_matcher.rb +19 -6
  19. data/lib/rsmp/collect/command_response_collector.rb +7 -7
  20. data/lib/rsmp/collect/distributor.rb +14 -11
  21. data/lib/rsmp/collect/filter.rb +31 -15
  22. data/lib/rsmp/collect/matcher.rb +7 -11
  23. data/lib/rsmp/collect/queue.rb +4 -4
  24. data/lib/rsmp/collect/receiver.rb +10 -12
  25. data/lib/rsmp/collect/state_collector.rb +116 -77
  26. data/lib/rsmp/collect/status_collector.rb +6 -6
  27. data/lib/rsmp/collect/status_matcher.rb +17 -7
  28. data/lib/rsmp/{alarm_state.rb → component/alarm_state.rb} +76 -37
  29. data/lib/rsmp/{component.rb → component/component.rb} +15 -15
  30. data/lib/rsmp/component/component_base.rb +89 -0
  31. data/lib/rsmp/component/component_proxy.rb +75 -0
  32. data/lib/rsmp/component/components.rb +63 -0
  33. data/lib/rsmp/convert/export/json_schema.rb +116 -110
  34. data/lib/rsmp/convert/import/yaml.rb +21 -18
  35. data/lib/rsmp/{rsmp.rb → helpers/clock.rb} +5 -6
  36. data/lib/rsmp/{deep_merge.rb → helpers/deep_merge.rb} +2 -1
  37. data/lib/rsmp/helpers/error.rb +71 -0
  38. data/lib/rsmp/{inspect.rb → helpers/inspect.rb} +6 -10
  39. data/lib/rsmp/log/archive.rb +98 -0
  40. data/lib/rsmp/log/colorization.rb +41 -0
  41. data/lib/rsmp/log/filtering.rb +54 -0
  42. data/lib/rsmp/log/logger.rb +206 -0
  43. data/lib/rsmp/{logging.rb → log/logging.rb} +5 -7
  44. data/lib/rsmp/message.rb +159 -148
  45. data/lib/rsmp/{node.rb → node/node.rb} +19 -17
  46. data/lib/rsmp/{protocol.rb → node/protocol.rb} +5 -3
  47. data/lib/rsmp/node/site/site.rb +195 -0
  48. data/lib/rsmp/node/supervisor/modules/configuration.rb +59 -0
  49. data/lib/rsmp/node/supervisor/modules/connection.rb +140 -0
  50. data/lib/rsmp/node/supervisor/modules/sites.rb +64 -0
  51. data/lib/rsmp/node/supervisor/supervisor.rb +72 -0
  52. data/lib/rsmp/{task.rb → node/task.rb} +12 -14
  53. data/lib/rsmp/proxy/modules/acknowledgements.rb +144 -0
  54. data/lib/rsmp/proxy/modules/receive.rb +119 -0
  55. data/lib/rsmp/proxy/modules/send.rb +76 -0
  56. data/lib/rsmp/proxy/modules/state.rb +25 -0
  57. data/lib/rsmp/proxy/modules/tasks.rb +105 -0
  58. data/lib/rsmp/proxy/modules/versions.rb +69 -0
  59. data/lib/rsmp/proxy/modules/watchdogs.rb +66 -0
  60. data/lib/rsmp/proxy/proxy.rb +199 -0
  61. data/lib/rsmp/proxy/site/modules/aggregated_status.rb +52 -0
  62. data/lib/rsmp/proxy/site/modules/alarms.rb +27 -0
  63. data/lib/rsmp/proxy/site/modules/commands.rb +31 -0
  64. data/lib/rsmp/proxy/site/modules/status.rb +110 -0
  65. data/lib/rsmp/proxy/site/site_proxy.rb +205 -0
  66. data/lib/rsmp/proxy/supervisor/modules/aggregated_status.rb +47 -0
  67. data/lib/rsmp/proxy/supervisor/modules/alarms.rb +73 -0
  68. data/lib/rsmp/proxy/supervisor/modules/commands.rb +53 -0
  69. data/lib/rsmp/proxy/supervisor/modules/status.rb +204 -0
  70. data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +178 -0
  71. data/lib/rsmp/tlc/detector_logic.rb +18 -34
  72. data/lib/rsmp/tlc/input_states.rb +126 -0
  73. data/lib/rsmp/tlc/modules/detector_logics.rb +50 -0
  74. data/lib/rsmp/tlc/modules/display.rb +78 -0
  75. data/lib/rsmp/tlc/modules/helpers.rb +41 -0
  76. data/lib/rsmp/tlc/modules/inputs.rb +173 -0
  77. data/lib/rsmp/tlc/modules/modes.rb +253 -0
  78. data/lib/rsmp/tlc/modules/outputs.rb +30 -0
  79. data/lib/rsmp/tlc/modules/plans.rb +218 -0
  80. data/lib/rsmp/tlc/modules/signal_groups.rb +109 -0
  81. data/lib/rsmp/tlc/modules/startup_sequence.rb +22 -0
  82. data/lib/rsmp/tlc/modules/system.rb +140 -0
  83. data/lib/rsmp/tlc/modules/traffic_data.rb +49 -0
  84. data/lib/rsmp/tlc/signal_group.rb +37 -41
  85. data/lib/rsmp/tlc/signal_plan.rb +14 -11
  86. data/lib/rsmp/tlc/signal_priority.rb +39 -35
  87. data/lib/rsmp/tlc/startup_sequence.rb +59 -0
  88. data/lib/rsmp/tlc/traffic_controller.rb +38 -1010
  89. data/lib/rsmp/tlc/traffic_controller_site.rb +58 -57
  90. data/lib/rsmp/version.rb +1 -1
  91. data/lib/rsmp.rb +82 -48
  92. data/rsmp.gemspec +24 -31
  93. metadata +79 -139
  94. data/lib/rsmp/archive.rb +0 -76
  95. data/lib/rsmp/collect/message_matchers.rb +0 -0
  96. data/lib/rsmp/component_base.rb +0 -87
  97. data/lib/rsmp/component_proxy.rb +0 -57
  98. data/lib/rsmp/components.rb +0 -65
  99. data/lib/rsmp/error.rb +0 -71
  100. data/lib/rsmp/logger.rb +0 -216
  101. data/lib/rsmp/proxy.rb +0 -693
  102. data/lib/rsmp/site.rb +0 -188
  103. data/lib/rsmp/site_proxy.rb +0 -389
  104. data/lib/rsmp/supervisor.rb +0 -302
  105. data/lib/rsmp/supervisor_proxy.rb +0 -510
  106. data/lib/rsmp/tlc/inputs.rb +0 -134
@@ -0,0 +1,195 @@
1
+ # RSMP site
2
+ # The site initializes the connection to the supervisor.
3
+ # Connections to supervisors are handles via supervisor proxies.
4
+
5
+ module RSMP
6
+ class Site < Node
7
+ include Components
8
+
9
+ attr_reader :core_version, :site_settings, :logger, :proxies
10
+
11
+ def initialize(options = {})
12
+ super
13
+ initialize_components
14
+ handle_site_settings options
15
+ @proxies = []
16
+ @sleep_condition = Async::Notification.new
17
+ @proxies_condition = Async::Notification.new
18
+ build_proxies
19
+ end
20
+
21
+ def sxl_version
22
+ @site_settings['sxl_version']
23
+ end
24
+
25
+ def site_id
26
+ @site_settings['site_id']
27
+ end
28
+
29
+ def default_site_settings
30
+ {
31
+ 'site_id' => 'RN+SI0001',
32
+ 'supervisors' => [
33
+ { 'ip' => '127.0.0.1', 'port' => 12_111 }
34
+ ],
35
+ 'sxl' => 'tlc',
36
+ 'sxl_version' => RSMP::Schema.latest_version(:tlc),
37
+ 'intervals' => {
38
+ 'timer' => 0.1,
39
+ 'watchdog' => 1,
40
+ 'reconnect' => 0.1
41
+ },
42
+ 'timeouts' => {
43
+ 'watchdog' => 2,
44
+ 'acknowledgement' => 2
45
+ },
46
+ 'send_after_connect' => true,
47
+ 'components' => {
48
+ 'main' => {
49
+ 'C1' => {}
50
+ }
51
+ }
52
+ }
53
+ end
54
+
55
+ def handle_site_settings(options = {})
56
+ defaults = default_site_settings
57
+ defaults['components']['main'] = options[:site_settings]['components']['main'] if options.dig(
58
+ :site_settings, 'components', 'main'
59
+ )
60
+
61
+ @site_settings = defaults.deep_merge options[:site_settings]
62
+
63
+ check_sxl_version
64
+ check_core_versions
65
+ setup_components @site_settings['components']
66
+ end
67
+
68
+ def check_sxl_version
69
+ sxl = @site_settings['sxl']
70
+ version = @site_settings['sxl_version'].to_s
71
+ RSMP::Schema.find_schema! sxl, version, lenient: true
72
+ end
73
+
74
+ def check_core_versions
75
+ version = @site_settings['core_version']
76
+ return unless version
77
+
78
+ return if RSMP::Schema.core_versions.include? version
79
+
80
+ error_str = "Unknown core version: #{version}"
81
+ raise RSMP::ConfigurationError, error_str
82
+ end
83
+
84
+ def site_type_name
85
+ 'site'
86
+ end
87
+
88
+ def log_site_starting
89
+ log "Starting #{site_type_name} #{@site_settings['site_id']}", level: :info, timestamp: @clock.now
90
+ sxl = "Using #{@site_settings['sxl']} sxl #{@site_settings['sxl_version']}"
91
+ version = @site_settings['core_version']
92
+ core = if version
93
+ "accepting only core version #{version}"
94
+ else
95
+ "accepting all core versions [#{RSMP::Schema.core_versions.join(', ')}]"
96
+ end
97
+ log "#{sxl}, #{core}", level: :info, timestamp: @clock.now
98
+ end
99
+
100
+ def run
101
+ log_site_starting
102
+ @proxies.each do |proxy|
103
+ proxy.start
104
+ proxy.wait
105
+ end
106
+ end
107
+
108
+ def build_proxies
109
+ @site_settings['supervisors'].each do |supervisor_settings|
110
+ @proxies << SupervisorProxy.new({
111
+ site: self,
112
+ task: @task,
113
+ settings: @site_settings,
114
+ ip: supervisor_settings['ip'],
115
+ port: supervisor_settings['port'],
116
+ logger: @logger,
117
+ archive: @archive,
118
+ collect: @collect
119
+ })
120
+ end
121
+ end
122
+
123
+ def aggregated_status_changed(component, options = {})
124
+ @proxies.each do |proxy|
125
+ proxy.send_aggregated_status component, options if proxy.ready?
126
+ end
127
+ end
128
+
129
+ def alarm_acknowledged(alarm_state)
130
+ send_alarm AlarmAcknowledged.new(alarm_state.to_hash)
131
+ end
132
+
133
+ def alarm_suspended_or_resumed(alarm_state)
134
+ send_alarm AlarmSuspended.new(alarm_state.to_hash)
135
+ end
136
+
137
+ def alarm_activated_or_deactivated(alarm_state)
138
+ send_alarm AlarmIssue.new(alarm_state.to_hash)
139
+ end
140
+
141
+ def send_alarm(alarm)
142
+ @proxies.each do |proxy|
143
+ proxy.send_message alarm if proxy.ready?
144
+ end
145
+ end
146
+
147
+ def connect_to_supervisor(_task, supervisor_settings)
148
+ proxy = build_proxy({
149
+ site: self,
150
+ task: @task,
151
+ settings: @site_settings,
152
+ ip: supervisor_settings['ip'],
153
+ port: supervisor_settings['port'],
154
+ logger: @logger,
155
+ archive: @archive,
156
+ collect: @collect
157
+ })
158
+ @proxies << proxy
159
+ proxy.start
160
+ @proxies_condition.signal
161
+ end
162
+
163
+ # stop
164
+ def stop
165
+ log "Stopping site #{@site_settings['site_id']}", level: :info
166
+ super
167
+ end
168
+
169
+ def wait_for_supervisor(ip, timeout)
170
+ supervisor = find_supervisor ip
171
+ return supervisor if supervisor
172
+
173
+ wait_for_condition(@proxy_condition, timeout: timeout) { find_supervisor ip }
174
+ rescue Async::TimeoutError
175
+ raise RSMP::TimeoutError, "Supervisor '#{ip}' did not connect within #{timeout}s"
176
+ end
177
+
178
+ def find_supervisor(ip)
179
+ @proxies.each do |supervisor|
180
+ return supervisor if ip == :any || supervisor.ip == ip
181
+ end
182
+ nil
183
+ end
184
+
185
+ def build_component(id:, type:, settings:)
186
+ settings ||= {}
187
+ if type == 'main'
188
+ Component.new id: id, node: self, grouped: true,
189
+ ntsoid: settings['ntsOId'], xnid: settings['xNId']
190
+ else
191
+ Component.new id: id, node: self, grouped: false
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,59 @@
1
+ module RSMP
2
+ class Supervisor < Node
3
+ module Modules
4
+ # Handles supervisor configuration and site settings
5
+ module Configuration
6
+ def handle_supervisor_settings(supervisor_settings)
7
+ defaults = {
8
+ 'port' => 12_111,
9
+ 'ips' => 'all',
10
+ 'guest' => {
11
+ 'sxl' => 'tlc',
12
+ 'intervals' => {
13
+ 'timer' => 1,
14
+ 'watchdog' => 1
15
+ },
16
+ 'timeouts' => {
17
+ 'watchdog' => 2,
18
+ 'acknowledgement' => 2
19
+ }
20
+ }
21
+ }
22
+
23
+ # merge options into defaults
24
+ @supervisor_settings = defaults.deep_merge(supervisor_settings)
25
+ @core_version = @supervisor_settings['guest']['core_version']
26
+ check_site_sxl_types
27
+ end
28
+
29
+ def check_site_sxl_types
30
+ sites = @supervisor_settings['sites'].clone || {}
31
+ sites['guest'] = @supervisor_settings['guest']
32
+ sites.each do |site_id, settings|
33
+ raise RSMP::ConfigurationError, "Configuration for site '#{site_id}' is empty" unless settings
34
+
35
+ sxl = settings['sxl']
36
+ raise RSMP::ConfigurationError, "Configuration error for site '#{site_id}': No SXL specified" unless sxl
37
+
38
+ RSMP::Schema.find_schemas! sxl if sxl
39
+ rescue RSMP::Schema::UnknownSchemaError => e
40
+ raise RSMP::ConfigurationError, "Configuration error for site '#{site_id}': #{e}"
41
+ end
42
+ end
43
+
44
+ def site_id_to_site_setting(site_id)
45
+ return {} unless @supervisor_settings['sites']
46
+
47
+ @supervisor_settings['sites'].each_pair do |id, settings|
48
+ return settings if id == 'guest' || id == site_id
49
+ end
50
+ raise HandshakeError, "site id #{site_id} unknown"
51
+ end
52
+
53
+ def ip_to_site_settings(ip)
54
+ @supervisor_settings['sites'][ip] || @supervisor_settings['sites']['guest']
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,140 @@
1
+ module RSMP
2
+ class Supervisor < Node
3
+ module Modules
4
+ # Handles incoming connections from sites
5
+ module Connection
6
+ def handle_connection(socket)
7
+ remote_port = socket.remote_address.ip_port
8
+ remote_hostname = socket.remote_address.ip_address
9
+ remote_ip = socket.remote_address.ip_address
10
+
11
+ info = { ip: remote_ip, port: remote_port, hostname: remote_hostname, now: Clock.now }
12
+ if accept? socket, info
13
+ accept_connection socket, info
14
+ else
15
+ reject_connection socket, info
16
+ end
17
+ rescue ConnectionError, HandshakeError => e
18
+ log "Rejected connection from #{remote_ip}:#{remote_port}, #{e}", level: :warning
19
+ distribute_error e
20
+ rescue StandardError => e
21
+ log "Connection: #{e}", exception: e, level: :error
22
+ distribute_error e, level: :internal
23
+ ensure
24
+ close socket, info
25
+ end
26
+
27
+ def accept?(_socket, _info)
28
+ true
29
+ end
30
+
31
+ def format_ip_and_port(info)
32
+ if @logger.settings['hide_ip_and_port']
33
+ '********'
34
+ else
35
+ "#{info[:ip]}:#{info[:port]}"
36
+ end
37
+ end
38
+
39
+ def authorize_ip(ip)
40
+ return if @supervisor_settings['ips'] == 'all'
41
+ return if @supervisor_settings['ips'].include? ip
42
+
43
+ raise ConnectionError, 'guest ip not allowed'
44
+ end
45
+
46
+ def check_max_sites
47
+ max = @supervisor_settings['max_sites']
48
+ return unless max
49
+ return unless @proxies.size >= max
50
+
51
+ raise ConnectionError, "maximum of #{max} sites already connected"
52
+ end
53
+
54
+ def peek_version_message(protocol)
55
+ json = protocol.peek_line
56
+ attributes = Message.parse_attributes json
57
+ Message.build attributes, json
58
+ end
59
+
60
+ def build_proxy_settings(socket, info)
61
+ stream = IO::Stream::Buffered.new(socket)
62
+ protocol = RSMP::Protocol.new stream
63
+
64
+ {
65
+ supervisor: self,
66
+ ip: info[:ip],
67
+ port: info[:port],
68
+ task: @task,
69
+ collect: @collect,
70
+ socket: socket,
71
+ stream: stream,
72
+ protocol: protocol,
73
+ info: info,
74
+ logger: @logger,
75
+ archive: @archive
76
+ }
77
+ end
78
+
79
+ def retrieve_site_id(protocol)
80
+ version_message = peek_version_message protocol
81
+ version_message.attribute('siteId').first['sId']
82
+ end
83
+
84
+ def setup_proxy(proxy, settings, id)
85
+ if proxy
86
+ raise ConnectionError, "Site #{id} alredy connected from port #{proxy.port}" if proxy.connected?
87
+
88
+ proxy.revive settings
89
+ else
90
+ check_max_sites
91
+ proxy = build_proxy settings.merge(site_id: id)
92
+ @proxies.push proxy
93
+ end
94
+ proxy
95
+ end
96
+
97
+ def validate_and_start_proxy(proxy, protocol)
98
+ proxy.setup_site_settings
99
+ proxy.check_core_version peek_version_message(protocol)
100
+ log "Validating using core version #{proxy.core_version}", level: :debug
101
+ proxy.start
102
+ proxy.wait
103
+ end
104
+
105
+ def accept_connection(socket, info)
106
+ log "Site connected from #{format_ip_and_port(info)}",
107
+ ip: info[:ip],
108
+ port: info[:port],
109
+ level: :info,
110
+ timestamp: Clock.now
111
+
112
+ authorize_ip info[:ip]
113
+
114
+ settings = build_proxy_settings(socket, info)
115
+ id = retrieve_site_id(settings[:protocol])
116
+ proxy = setup_proxy(find_site(id), settings, id)
117
+
118
+ validate_and_start_proxy(proxy, settings[:protocol])
119
+ ensure
120
+ site_ids_changed
121
+ stop if @supervisor_settings['one_shot']
122
+ end
123
+
124
+ def reject_connection(_socket, info)
125
+ log 'Site rejected', ip: info[:ip], level: :info
126
+ end
127
+
128
+ def close(socket, info)
129
+ if info
130
+ log "Connection to #{format_ip_and_port(info)} closed", ip: info[:ip], level: :info, timestamp: Clock.now
131
+ else
132
+ log 'Connection closed', level: :info, timestamp: Clock.now
133
+ end
134
+
135
+ socket.close
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,64 @@
1
+ module RSMP
2
+ class Supervisor < Node
3
+ module Modules
4
+ # Manages connected sites and site discovery
5
+ module Sites
6
+ def site_connected?(site_id)
7
+ !find_site(site_id).nil?
8
+ end
9
+
10
+ def find_site_from_ip_port(ip, port)
11
+ @proxies.each do |site|
12
+ return site if site.ip == ip && site.port == port
13
+ end
14
+ nil
15
+ end
16
+
17
+ def find_site(site_id)
18
+ @proxies.each do |site|
19
+ return site if site_id == :any || site.site_id == site_id
20
+ end
21
+ nil
22
+ end
23
+
24
+ def wait_for_site(site_id, timeout:)
25
+ site = find_site site_id
26
+ return site if site
27
+
28
+ wait_for_condition(@site_id_condition, timeout: timeout) do
29
+ find_site site_id
30
+ end
31
+ rescue Async::TimeoutError
32
+ str = if site_id == :any
33
+ 'No site connected'
34
+ else
35
+ "Site '#{site_id}' did not connect"
36
+ end
37
+ raise RSMP::TimeoutError, "#{str} within #{timeout}s"
38
+ end
39
+
40
+ def wait_for_site_disconnect(site_id, timeout:)
41
+ wait_for_condition(@site_id_condition, timeout: timeout) { true unless find_site site_id }
42
+ rescue Async::TimeoutError
43
+ raise RSMP::TimeoutError, "Site '#{site_id}' did not disconnect within #{timeout}s"
44
+ end
45
+
46
+ def check_site_id(site_id)
47
+ # check_site_already_connected site_id
48
+ site_id_to_site_setting site_id
49
+ end
50
+
51
+ def check_site_already_connected(site_id)
52
+ site = find_site(site_id)
53
+ raise HandshakeError, "Site '#{site_id}' already connected" if !site.nil? && site != self
54
+ end
55
+
56
+ def site_ids_changed
57
+ @site_id_condition.signal
58
+ end
59
+
60
+ def aggregated_status_changed(site_proxy, component); end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,72 @@
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
+ include Modules::Configuration
8
+ include Modules::Connection
9
+ include Modules::Sites
10
+
11
+ attr_reader :core_version, :supervisor_settings, :proxies, :logger, :ready_condition
12
+
13
+ attr_accessor :site_id_condition
14
+
15
+ def initialize(options = {})
16
+ handle_supervisor_settings(options[:supervisor_settings] || {})
17
+ super
18
+ @proxies = []
19
+ @ready_condition = Async::Notification.new
20
+ @site_id_condition = Async::Notification.new
21
+ end
22
+
23
+ def site_id
24
+ @supervisor_settings['site_id']
25
+ end
26
+
27
+ # listen for connections
28
+ def run
29
+ log "Starting supervisor on port #{@supervisor_settings['port']}",
30
+ level: :info,
31
+ timestamp: @clock.now
32
+
33
+ @endpoint = IO::Endpoint.tcp('0.0.0.0', @supervisor_settings['port'])
34
+ @accept_task = Async::Task.current.async do |task|
35
+ task.annotate 'supervisor accept loop'
36
+ @endpoint.accept do |socket| # creates fibers
37
+ handle_connection(socket)
38
+ rescue StandardError => e
39
+ distribute_error e, level: :internal
40
+ end
41
+ rescue Async::Stop
42
+ # Expected during shutdown - no action needed
43
+ rescue StandardError => e
44
+ distribute_error e, level: :internal
45
+ end
46
+
47
+ @ready_condition.signal
48
+ @accept_task.wait
49
+ rescue StandardError => e
50
+ distribute_error e, level: :internal
51
+ end
52
+
53
+ # stop
54
+ def stop
55
+ log "Stopping supervisor #{@supervisor_settings['site_id']}", level: :info
56
+
57
+ @accept_task&.stop
58
+ @accept_task = nil
59
+
60
+ @endpoint = nil
61
+ super
62
+ end
63
+
64
+ def build_proxy(settings)
65
+ SiteProxy.new settings
66
+ end
67
+
68
+ def self.build_id_from_ip_port(ip, port)
69
+ Digest::MD5.hexdigest("#{ip}:#{port}")[0..8]
70
+ end
71
+ end
72
+ end
@@ -13,7 +13,7 @@ module RSMP
13
13
  # run() will be called inside the task to perform actual long-running work
14
14
  def start
15
15
  return if @task
16
-
16
+
17
17
  # Use current task context if available, otherwise create new reactor
18
18
  if Async::Task.current?
19
19
  Async::Task.current.async do |task|
@@ -37,12 +37,12 @@ module RSMP
37
37
 
38
38
  # initiate restart by raising a Restart exception
39
39
  def restart
40
- raise Restart.new "restart initiated by #{self.class.name}:#{object_id}"
40
+ raise Restart, "restart initiated by #{self.class.name}:#{object_id}"
41
41
  end
42
42
 
43
43
  # get the status of our task, or nil of no task
44
44
  def task_status
45
- @task.status if @task
45
+ @task&.status
46
46
  end
47
47
 
48
48
  # perform any long-running work
@@ -55,7 +55,7 @@ module RSMP
55
55
 
56
56
  # wait for our task to complete
57
57
  def wait
58
- @task.wait if @task
58
+ @task&.wait
59
59
  end
60
60
 
61
61
  # stop our task
@@ -64,8 +64,7 @@ module RSMP
64
64
  stop_task if @task
65
65
  end
66
66
 
67
- def stop_subtasks
68
- end
67
+ def stop_subtasks; end
69
68
 
70
69
  # stop our task and any subtask
71
70
  def stop_task
@@ -75,22 +74,21 @@ module RSMP
75
74
 
76
75
  # wait for an async condition to signal, then yield to block
77
76
  # if block returns true we're done. otherwise, wait again
78
- def wait_for_condition condition, timeout:, task:Async::Task.current, &block
79
- unless task
80
- raise RuntimeError.new("Can't wait without a task")
81
- end
77
+ def wait_for_condition(condition, timeout:, task: Async::Task.current, &block)
78
+ raise "Can't wait without a task" unless task
79
+
82
80
  task.with_timeout(timeout) do
83
81
  while task.running?
84
82
  value = condition.wait
85
83
  return value unless block
84
+
86
85
  result = yield value
87
86
  return result if result
88
87
  end
89
- raise RuntimeError.new("Can't wait for condition because task #{task.object_id} #{task.annotation} is not running")
88
+ raise "Can't wait for condition because task #{task.object_id} #{task.annotation} is not running"
90
89
  end
91
90
  rescue Async::TimeoutError
92
- raise RSMP::TimeoutError.new
91
+ raise RSMP::TimeoutError
93
92
  end
94
-
95
93
  end
96
- end
94
+ end