rsmp 0.48.4 → 0.51.1
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/CHANGELOG.md +14 -0
- data/Gemfile.lock +19 -20
- data/README.md +27 -3
- data/Rakefile +3 -1
- data/documentation/cli.md +79 -4
- data/documentation/collecting_message.md +90 -170
- data/documentation/configuration.md +8 -0
- data/documentation/message_distribution.md +17 -3
- data/documentation/tasks.md +65 -117
- data/lib/rsmp/cli.rb +93 -5
- data/lib/rsmp/collect/collector.rb +117 -134
- data/lib/rsmp/collect/distributor.rb +16 -3
- data/lib/rsmp/collect/queue.rb +14 -6
- data/lib/rsmp/collect/receiver.rb +1 -1
- data/lib/rsmp/collect/state_collector.rb +11 -2
- data/lib/rsmp/collection.rb +12 -0
- data/lib/rsmp/completion.rb +49 -0
- data/lib/rsmp/component/component_base.rb +3 -3
- data/lib/rsmp/convert/export/json_schema/index.rb +8 -4
- data/lib/rsmp/convert/import/yaml.rb +12 -8
- data/lib/rsmp/delivery.rb +18 -0
- data/lib/rsmp/event.rb +19 -0
- data/lib/rsmp/event_source.rb +36 -0
- data/lib/rsmp/exchange.rb +10 -0
- data/lib/rsmp/failure.rb +23 -0
- data/lib/rsmp/helpers/error.rb +14 -23
- data/lib/rsmp/message.rb +10 -9
- data/lib/rsmp/node/node.rb +3 -21
- data/lib/rsmp/node/site/connections.rb +4 -9
- data/lib/rsmp/node/site/site.rb +33 -17
- data/lib/rsmp/node/supervisor/modules/configuration.rb +24 -11
- data/lib/rsmp/node/supervisor/modules/connection.rb +19 -5
- data/lib/rsmp/node/supervisor/modules/sites.rb +16 -5
- data/lib/rsmp/node/supervisor/supervisor.rb +13 -14
- data/lib/rsmp/node/task.rb +59 -53
- data/lib/rsmp/proxy/modules/acknowledgements.rb +22 -9
- data/lib/rsmp/proxy/modules/lifecycle.rb +134 -0
- data/lib/rsmp/proxy/modules/receive.rb +109 -66
- data/lib/rsmp/proxy/modules/send.rb +109 -51
- data/lib/rsmp/proxy/modules/state.rb +15 -5
- data/lib/rsmp/proxy/modules/tasks.rb +96 -70
- data/lib/rsmp/proxy/modules/versions.rb +69 -19
- data/lib/rsmp/proxy/modules/watchdogs.rb +15 -2
- data/lib/rsmp/proxy/proxy.rb +7 -69
- data/lib/rsmp/proxy/site/connection.rb +27 -22
- data/lib/rsmp/proxy/site/modules/aggregated_status.rb +18 -8
- data/lib/rsmp/proxy/site/modules/alarms.rb +45 -38
- data/lib/rsmp/proxy/site/modules/commands.rb +18 -8
- data/lib/rsmp/proxy/site/modules/status.rb +44 -19
- data/lib/rsmp/proxy/site/site_proxy.rb +12 -10
- data/lib/rsmp/proxy/site/sxl_selection.rb +7 -2
- data/lib/rsmp/proxy/supervisor/modules/aggregated_status.rb +1 -1
- data/lib/rsmp/proxy/supervisor/modules/alarms.rb +1 -1
- data/lib/rsmp/proxy/supervisor/modules/commands.rb +1 -1
- data/lib/rsmp/proxy/supervisor/modules/message_buffer.rb +8 -9
- data/lib/rsmp/proxy/supervisor/modules/status.rb +1 -1
- data/lib/rsmp/proxy/supervisor/modules/status_updates.rb +1 -1
- data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +36 -31
- data/lib/rsmp/result.rb +95 -0
- data/lib/rsmp/schema/validation.rb +5 -3
- data/lib/rsmp/schema/version.rb +27 -0
- data/lib/rsmp/schema.rb +1 -0
- data/lib/rsmp/sxl/interface.rb +8 -1
- data/lib/rsmp/sxl/processing/catalogue.rb +61 -0
- data/lib/rsmp/sxl/processing/conflict_checker.rb +30 -0
- data/lib/rsmp/sxl/processing/dependency_graph.rb +37 -0
- data/lib/rsmp/sxl/processing/document.rb +158 -0
- data/lib/rsmp/sxl/processing/error.rb +8 -0
- data/lib/rsmp/sxl/processing/manifest.rb +144 -0
- data/lib/rsmp/sxl/processing/natural_sort.rb +22 -0
- data/lib/rsmp/sxl/processing/resolver.rb +94 -0
- data/lib/rsmp/sxl/processing/version_requirement.rb +86 -0
- data/lib/rsmp/sxl/processing.rb +18 -0
- data/lib/rsmp/sxl/supervisor_interface.rb +8 -1
- data/lib/rsmp/termination.rb +10 -0
- data/lib/rsmp/tlc/modules/plans.rb +0 -2
- data/lib/rsmp/tlc/modules/system.rb +2 -2
- data/lib/rsmp/tlc/proxy/control.rb +50 -16
- data/lib/rsmp/tlc/proxy/detectors.rb +15 -4
- data/lib/rsmp/tlc/proxy/io.rb +46 -31
- data/lib/rsmp/tlc/proxy/plans.rb +36 -19
- data/lib/rsmp/tlc/proxy/plans_bang.rb +44 -0
- data/lib/rsmp/tlc/proxy/status.rb +47 -23
- data/lib/rsmp/tlc/proxy/system.rb +16 -4
- data/lib/rsmp/tlc/supervisor_interface.rb +7 -1
- data/lib/rsmp/tlc/traffic_controller_site.rb +6 -9
- data/lib/rsmp/validation.rb +22 -0
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +19 -4
- data/rsmp.gemspec +1 -1
- metadata +26 -4
- data/lib/rsmp/collect/collector/status.rb +0 -34
data/lib/rsmp/proxy/proxy.rb
CHANGED
|
@@ -16,10 +16,11 @@ module RSMP
|
|
|
16
16
|
include Modules::Receive
|
|
17
17
|
include Modules::Versions
|
|
18
18
|
include Modules::Tasks
|
|
19
|
+
include Modules::Lifecycle
|
|
19
20
|
|
|
20
21
|
attr_reader :state, :archive, :connection_info, :sxls, :accepted_sxls, :rejected_sxls,
|
|
21
|
-
:collector, :ip, :port, :node, :core_version, :sxl_interfaces,
|
|
22
|
-
:site_settings
|
|
22
|
+
:collector, :ip, :port, :node, :core_version, :core_version_string, :sxl_interfaces,
|
|
23
|
+
:site_settings, :session_id
|
|
23
24
|
|
|
24
25
|
def initialize(options)
|
|
25
26
|
@node = options[:node]
|
|
@@ -31,6 +32,8 @@ module RSMP
|
|
|
31
32
|
clear
|
|
32
33
|
@state = :disconnected
|
|
33
34
|
@state_condition = Async::Notification.new
|
|
35
|
+
@session_id = 0
|
|
36
|
+
@session_closed = true
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
def inspect
|
|
@@ -41,67 +44,6 @@ module RSMP
|
|
|
41
44
|
node.now
|
|
42
45
|
end
|
|
43
46
|
|
|
44
|
-
# Connection lifecycle methods
|
|
45
|
-
|
|
46
|
-
def disconnect; end
|
|
47
|
-
|
|
48
|
-
# wait for the reader task to complete,
|
|
49
|
-
# which is not expected to happen before the connection is closed
|
|
50
|
-
def wait_for_reader
|
|
51
|
-
@reader&.wait
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# close connection, but keep our main task running so we can reconnect
|
|
55
|
-
def close
|
|
56
|
-
log 'Closing connection', level: :warning
|
|
57
|
-
close_stream
|
|
58
|
-
close_socket
|
|
59
|
-
stop_reader
|
|
60
|
-
self.state = :disconnected
|
|
61
|
-
distribute_error DisconnectError.new('Connection was closed')
|
|
62
|
-
|
|
63
|
-
# stop timer
|
|
64
|
-
# as we're running inside the timer, code after stop_timer() will not be called,
|
|
65
|
-
# unless it's in the ensure block
|
|
66
|
-
stop_timer
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def stop_subtasks
|
|
70
|
-
stop_timer
|
|
71
|
-
stop_reader
|
|
72
|
-
clear
|
|
73
|
-
super
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def stop_timer
|
|
77
|
-
@timer&.stop
|
|
78
|
-
ensure
|
|
79
|
-
@timer = nil
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def stop_reader
|
|
83
|
-
@reader&.stop
|
|
84
|
-
ensure
|
|
85
|
-
@reader = nil
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def close_stream
|
|
89
|
-
@stream&.close
|
|
90
|
-
ensure
|
|
91
|
-
@stream = nil
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def close_socket
|
|
95
|
-
@socket&.close
|
|
96
|
-
ensure
|
|
97
|
-
@socket = nil
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def stop_task
|
|
101
|
-
close
|
|
102
|
-
super
|
|
103
|
-
end
|
|
104
|
-
|
|
105
47
|
# State management methods
|
|
106
48
|
|
|
107
49
|
def ready?
|
|
@@ -174,10 +116,6 @@ module RSMP
|
|
|
174
116
|
@node.clock
|
|
175
117
|
end
|
|
176
118
|
|
|
177
|
-
def receive_error(error, options = {})
|
|
178
|
-
@node.receive_error error, options
|
|
179
|
-
end
|
|
180
|
-
|
|
181
119
|
def log(str, options = {})
|
|
182
120
|
super(str, options.merge(ip: @ip, port: @port, site_id: @site_id))
|
|
183
121
|
end
|
|
@@ -252,8 +190,8 @@ module RSMP
|
|
|
252
190
|
end
|
|
253
191
|
|
|
254
192
|
# Use Gem class to check version requirement
|
|
255
|
-
# Requirement must be a string like '1.1', '>=1.0.3' or '<2.1.4',
|
|
256
|
-
# or list of strings, like ['<=1.4','<1.5']
|
|
193
|
+
# Requirement must be a string like '1.1.0', '>=1.0.3' or '<2.1.4',
|
|
194
|
+
# or list of strings, like ['<=1.4.0','<1.5.0']
|
|
257
195
|
def self.version_meets_requirement?(version, requirement)
|
|
258
196
|
Modules::Versions.version_meets_requirement?(version, requirement)
|
|
259
197
|
end
|
|
@@ -12,50 +12,46 @@ module RSMP
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def run_accepted_connection
|
|
15
|
+
begin_session
|
|
15
16
|
self.state = :connected
|
|
16
17
|
start_reader
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
log e, level: :error
|
|
20
|
-
rescue StandardError => e
|
|
21
|
-
distribute_error e, level: :internal
|
|
18
|
+
ended = wait_for_reader
|
|
19
|
+
close_from_result(ended)
|
|
22
20
|
ensure
|
|
21
|
+
close(reason: :internal_failure) if $ERROR_INFO
|
|
23
22
|
close
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
def run_outbound_connection
|
|
27
26
|
loop do
|
|
28
27
|
setup_site_settings
|
|
29
|
-
connect
|
|
28
|
+
connected = connect
|
|
29
|
+
unless connected.success?
|
|
30
|
+
publish_connection_attempt_failure(connected.failure)
|
|
31
|
+
break unless reconnect_delay?
|
|
32
|
+
|
|
33
|
+
next
|
|
34
|
+
end
|
|
30
35
|
start_reader
|
|
31
|
-
wait_for_reader
|
|
32
|
-
break unless reconnect_delay?
|
|
33
|
-
rescue Restart
|
|
34
|
-
@logger.mute @ip, @port
|
|
35
|
-
raise
|
|
36
|
-
rescue RSMP::ConnectionError => e
|
|
37
|
-
log e, level: :error
|
|
38
|
-
break unless reconnect_delay?
|
|
39
|
-
rescue StandardError => e
|
|
40
|
-
distribute_error e, level: :internal
|
|
36
|
+
close_from_result(wait_for_reader)
|
|
41
37
|
break unless reconnect_delay?
|
|
42
38
|
ensure
|
|
39
|
+
close(reason: :internal_failure) if $ERROR_INFO
|
|
43
40
|
close
|
|
44
|
-
stop_subtasks
|
|
45
41
|
end
|
|
46
42
|
end
|
|
47
43
|
|
|
48
44
|
def connect
|
|
49
45
|
log "Connecting to site #{@site_id} at #{@ip}:#{@port}", level: :info
|
|
46
|
+
begin_session
|
|
50
47
|
self.state = :connecting
|
|
51
|
-
open_socket
|
|
48
|
+
opened = open_socket
|
|
49
|
+
return opened if opened.failure?
|
|
50
|
+
|
|
52
51
|
self.state = :connected
|
|
53
52
|
@logger.unmute @ip, @port
|
|
54
53
|
log "Connected to site #{@site_id} at #{@ip}:#{@port}", level: :info
|
|
55
|
-
|
|
56
|
-
raise ConnectionError, "Could not connect to site #{@site_id} at #{@ip}:#{@port}: Errno #{e.errno} #{e}"
|
|
57
|
-
rescue StandardError => e
|
|
58
|
-
raise ConnectionError, "Error while connecting to site #{@site_id} at #{@ip}:#{@port}: #{e}"
|
|
54
|
+
Result.success(self)
|
|
59
55
|
end
|
|
60
56
|
|
|
61
57
|
def open_socket
|
|
@@ -64,6 +60,15 @@ module RSMP
|
|
|
64
60
|
task.with_timeout(timeout) { @socket = endpoint.connect }
|
|
65
61
|
@stream = IO::Stream::Buffered.new(@socket)
|
|
66
62
|
@protocol = RSMP::Protocol.new(@stream)
|
|
63
|
+
Result.success(self)
|
|
64
|
+
rescue SystemCallError, SocketError, IOError, Async::TimeoutError => e
|
|
65
|
+
Result.failure(
|
|
66
|
+
:connection_failed,
|
|
67
|
+
message: "Could not connect to site #{@site_id} at #{@ip}:#{@port}: #{e.message}",
|
|
68
|
+
source: :transport,
|
|
69
|
+
context: { ip: @ip, port: @port, session_id: @session_id },
|
|
70
|
+
cause: e
|
|
71
|
+
)
|
|
67
72
|
end
|
|
68
73
|
|
|
69
74
|
def reconnect_delay?
|
|
@@ -3,23 +3,29 @@ module RSMP
|
|
|
3
3
|
module Modules
|
|
4
4
|
# Handles aggregated status requests and responses
|
|
5
5
|
module AggregatedStatus
|
|
6
|
-
# Build and send an AggregatedStatusRequest. Returns
|
|
6
|
+
# Build and send an AggregatedStatusRequest. Returns Result<AggregatedStatusRequest>.
|
|
7
7
|
def request_aggregated_status(component, m_id: nil, validate: true)
|
|
8
|
-
validate_ready 'request aggregated status'
|
|
8
|
+
readiness = validate_ready 'request aggregated status'
|
|
9
|
+
return readiness if readiness.failure?
|
|
10
|
+
|
|
9
11
|
m_id ||= RSMP::Message.make_m_id
|
|
10
12
|
message = RSMP::AggregatedStatusRequest.new({
|
|
11
13
|
'cId' => component,
|
|
12
14
|
'mId' => m_id
|
|
13
15
|
})
|
|
14
16
|
apply_nts_message_attributes message
|
|
15
|
-
send_message
|
|
16
|
-
|
|
17
|
+
send_message(message, validate: validate).map(&:message)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def request_aggregated_status!(...)
|
|
21
|
+
request_aggregated_status(...).value!
|
|
17
22
|
end
|
|
18
23
|
|
|
19
|
-
# Build, send an AggregatedStatusRequest and collect the response. Returns
|
|
20
|
-
# Call .ok! on the result to raise on NotAck or timeout.
|
|
24
|
+
# Build, send an AggregatedStatusRequest and collect the response. Returns Result<Exchange>.
|
|
21
25
|
def request_aggregated_status_and_collect(component, within:, m_id: nil, validate: true)
|
|
22
|
-
validate_ready 'request aggregated status'
|
|
26
|
+
readiness = validate_ready 'request aggregated status'
|
|
27
|
+
return readiness if readiness.failure?
|
|
28
|
+
|
|
23
29
|
m_id ||= RSMP::Message.make_m_id
|
|
24
30
|
message = RSMP::AggregatedStatusRequest.new({
|
|
25
31
|
'cId' => component,
|
|
@@ -27,7 +33,11 @@ module RSMP
|
|
|
27
33
|
})
|
|
28
34
|
apply_nts_message_attributes message
|
|
29
35
|
collector = AggregatedStatusCollector.new(self, timeout: within, m_id: m_id, num: 1)
|
|
30
|
-
send_message_and_collect(message, collector, validate: validate)
|
|
36
|
+
send_message_and_collect(message, collector, validate: validate)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def request_aggregated_status_and_collect!(...)
|
|
40
|
+
request_aggregated_status_and_collect(...).value!
|
|
31
41
|
end
|
|
32
42
|
|
|
33
43
|
def validate_aggregated_status(message, status_elements)
|
|
@@ -18,67 +18,74 @@ module RSMP
|
|
|
18
18
|
'cId' => component,
|
|
19
19
|
'aCId' => alarm_code
|
|
20
20
|
})
|
|
21
|
-
send_message
|
|
22
|
-
|
|
21
|
+
send_message(message, validate: options[:validate]).map(&:message)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def send_alarm_acknowledgement!(...)
|
|
25
|
+
send_alarm_acknowledgement(...).value!
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
# Send an AlarmSuspend message and optionally collect the confirming response.
|
|
26
|
-
#
|
|
27
|
-
def suspend_alarm(
|
|
29
|
+
# Returns Result<Exchange> when collecting and Result<AlarmSuspend> otherwise.
|
|
30
|
+
def suspend_alarm(c_id:, a_c_id:, collect: false)
|
|
28
31
|
message = RSMP::AlarmSuspend.new(
|
|
29
32
|
'mId' => RSMP::Message.make_m_id,
|
|
30
33
|
'cId' => c_id,
|
|
31
34
|
'aCId' => a_c_id
|
|
32
35
|
)
|
|
33
36
|
if collect
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
[message, collect_task.wait.first]
|
|
37
|
+
collector = RSMP::AlarmCollector.new(
|
|
38
|
+
self,
|
|
39
|
+
m_id: message.m_id,
|
|
40
|
+
num: 1,
|
|
41
|
+
matcher: {
|
|
42
|
+
'cId' => c_id,
|
|
43
|
+
'aCId' => a_c_id,
|
|
44
|
+
'aSp' => 'Suspend',
|
|
45
|
+
'sS' => /^Suspended/i
|
|
46
|
+
},
|
|
47
|
+
timeout: node.supervisor_settings.dig('default', 'timeouts', 'alarm')
|
|
48
|
+
)
|
|
49
|
+
send_message_and_collect(message, collector)
|
|
48
50
|
else
|
|
49
|
-
send_message
|
|
50
|
-
message
|
|
51
|
+
send_message(message).map(&:message)
|
|
51
52
|
end
|
|
52
53
|
end
|
|
53
54
|
|
|
55
|
+
def suspend_alarm!(...)
|
|
56
|
+
suspend_alarm(...).value!
|
|
57
|
+
end
|
|
58
|
+
|
|
54
59
|
# Send an AlarmResume message and optionally collect the confirming response.
|
|
55
|
-
#
|
|
56
|
-
def resume_alarm(
|
|
60
|
+
# Returns Result<Exchange> when collecting and Result<AlarmResume> otherwise.
|
|
61
|
+
def resume_alarm(c_id:, a_c_id:, collect: false)
|
|
57
62
|
message = RSMP::AlarmResume.new(
|
|
58
63
|
'mId' => RSMP::Message.make_m_id,
|
|
59
64
|
'cId' => c_id,
|
|
60
65
|
'aCId' => a_c_id
|
|
61
66
|
)
|
|
62
67
|
if collect
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
[message, collect_task.wait.first]
|
|
68
|
+
collector = RSMP::AlarmCollector.new(
|
|
69
|
+
self,
|
|
70
|
+
m_id: message.m_id,
|
|
71
|
+
num: 1,
|
|
72
|
+
matcher: {
|
|
73
|
+
'cId' => c_id,
|
|
74
|
+
'aCId' => a_c_id,
|
|
75
|
+
'aSp' => 'Suspend',
|
|
76
|
+
'sS' => /^notSuspended/i
|
|
77
|
+
},
|
|
78
|
+
timeout: node.supervisor_settings.dig('default', 'timeouts', 'alarm')
|
|
79
|
+
)
|
|
80
|
+
send_message_and_collect(message, collector)
|
|
77
81
|
else
|
|
78
|
-
send_message
|
|
79
|
-
message
|
|
82
|
+
send_message(message).map(&:message)
|
|
80
83
|
end
|
|
81
84
|
end
|
|
85
|
+
|
|
86
|
+
def resume_alarm!(...)
|
|
87
|
+
resume_alarm(...).value!
|
|
88
|
+
end
|
|
82
89
|
end
|
|
83
90
|
end
|
|
84
91
|
end
|
|
@@ -3,9 +3,11 @@ module RSMP
|
|
|
3
3
|
module Modules
|
|
4
4
|
# Handles command requests and responses
|
|
5
5
|
module Commands
|
|
6
|
-
# Build and send a CommandRequest. Returns
|
|
6
|
+
# Build and send a CommandRequest. Returns Result<CommandRequest>.
|
|
7
7
|
def send_command(command_list, component: nil, validate: true)
|
|
8
|
-
validate_ready 'send command'
|
|
8
|
+
readiness = validate_ready 'send command'
|
|
9
|
+
return readiness if readiness.failure?
|
|
10
|
+
|
|
9
11
|
component ||= main.c_id
|
|
10
12
|
m_id = RSMP::Message.make_m_id
|
|
11
13
|
message = RSMP::CommandRequest.new({
|
|
@@ -14,14 +16,18 @@ module RSMP
|
|
|
14
16
|
'mId' => m_id
|
|
15
17
|
})
|
|
16
18
|
apply_nts_message_attributes message
|
|
17
|
-
send_message
|
|
18
|
-
|
|
19
|
+
send_message(message, validate: validate).map(&:message)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def send_command!(...)
|
|
23
|
+
send_command(...).value!
|
|
19
24
|
end
|
|
20
25
|
|
|
21
|
-
# Build, send a CommandRequest and collect
|
|
22
|
-
# Raises on NotAck or timeout if ok! is called on the result.
|
|
26
|
+
# Build, send a CommandRequest and collect its responses. Returns Result<Exchange>.
|
|
23
27
|
def send_command_and_collect(command_list, within:, component: nil, validate: true)
|
|
24
|
-
validate_ready 'send command'
|
|
28
|
+
readiness = validate_ready 'send command'
|
|
29
|
+
return readiness if readiness.failure?
|
|
30
|
+
|
|
25
31
|
component ||= main.c_id
|
|
26
32
|
m_id = RSMP::Message.make_m_id
|
|
27
33
|
collector_list = command_collector_list(command_list)
|
|
@@ -32,7 +38,11 @@ module RSMP
|
|
|
32
38
|
})
|
|
33
39
|
apply_nts_message_attributes message
|
|
34
40
|
collector = CommandResponseCollector.new(self, collector_list, timeout: within, initiator: message)
|
|
35
|
-
send_message_and_collect(message, collector, validate: validate)
|
|
41
|
+
send_message_and_collect(message, collector, validate: validate)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def send_command_and_collect!(...)
|
|
45
|
+
send_command_and_collect(...).value!
|
|
36
46
|
end
|
|
37
47
|
|
|
38
48
|
def command_collector_list(command_list)
|
|
@@ -3,9 +3,11 @@ module RSMP
|
|
|
3
3
|
module Modules
|
|
4
4
|
# Handles status requests, responses, subscriptions and updates
|
|
5
5
|
module Status
|
|
6
|
-
# Build and send a StatusRequest. Returns
|
|
6
|
+
# Build and send a StatusRequest. Returns Result<StatusRequest>.
|
|
7
7
|
def request_status(status_list, component: nil, m_id: nil, validate: true)
|
|
8
|
-
validate_ready 'request status'
|
|
8
|
+
readiness = validate_ready 'request status'
|
|
9
|
+
return readiness if readiness.failure?
|
|
10
|
+
|
|
9
11
|
component ||= main.c_id
|
|
10
12
|
m_id ||= RSMP::Message.make_m_id
|
|
11
13
|
|
|
@@ -21,14 +23,18 @@ module RSMP
|
|
|
21
23
|
'mId' => m_id
|
|
22
24
|
})
|
|
23
25
|
apply_nts_message_attributes message
|
|
24
|
-
send_message
|
|
25
|
-
|
|
26
|
+
send_message(message, validate: validate).map(&:message)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def request_status!(...)
|
|
30
|
+
request_status(...).value!
|
|
26
31
|
end
|
|
27
32
|
|
|
28
|
-
# Build, send a StatusRequest and collect the StatusResponse. Returns
|
|
29
|
-
# Call .ok! on the result to raise on NotAck or timeout.
|
|
33
|
+
# Build, send a StatusRequest and collect the StatusResponse. Returns Result<Exchange>.
|
|
30
34
|
def request_status_and_collect(status_list, within:, component: nil, m_id: nil, validate: true)
|
|
31
|
-
validate_ready 'request status'
|
|
35
|
+
readiness = validate_ready 'request status'
|
|
36
|
+
return readiness if readiness.failure?
|
|
37
|
+
|
|
32
38
|
component ||= main.c_id
|
|
33
39
|
m_id ||= RSMP::Message.make_m_id
|
|
34
40
|
|
|
@@ -45,7 +51,11 @@ module RSMP
|
|
|
45
51
|
})
|
|
46
52
|
apply_nts_message_attributes message
|
|
47
53
|
collector = StatusCollector.new(self, list.to_a, timeout: within, m_id: m_id)
|
|
48
|
-
send_message_and_collect(message, collector, validate: validate)
|
|
54
|
+
send_message_and_collect(message, collector, validate: validate)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def request_status_and_collect!(...)
|
|
58
|
+
request_status_and_collect(...).value!
|
|
49
59
|
end
|
|
50
60
|
|
|
51
61
|
def process_status_response(message)
|
|
@@ -71,9 +81,11 @@ module RSMP
|
|
|
71
81
|
end
|
|
72
82
|
end
|
|
73
83
|
|
|
74
|
-
# Build and send a StatusSubscribe. Returns
|
|
84
|
+
# Build and send a StatusSubscribe. Returns Result<StatusSubscribe>.
|
|
75
85
|
def subscribe_to_status(status_list, component: nil, m_id: nil, validate: true)
|
|
76
|
-
validate_ready 'subscribe to status'
|
|
86
|
+
readiness = validate_ready 'subscribe to status'
|
|
87
|
+
return readiness if readiness.failure?
|
|
88
|
+
|
|
77
89
|
component ||= main.c_id
|
|
78
90
|
m_id ||= RSMP::Message.make_m_id
|
|
79
91
|
|
|
@@ -89,14 +101,18 @@ module RSMP
|
|
|
89
101
|
'mId' => m_id
|
|
90
102
|
})
|
|
91
103
|
apply_nts_message_attributes message
|
|
92
|
-
send_message
|
|
93
|
-
{ sent: message }
|
|
104
|
+
send_message(message, validate: validate).map(&:message)
|
|
94
105
|
end
|
|
95
106
|
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
def subscribe_to_status!(...)
|
|
108
|
+
subscribe_to_status(...).value!
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Build, send a StatusSubscribe and collect the first matching status update. Returns Result<Exchange>.
|
|
98
112
|
def subscribe_to_status_and_collect(status_list, within:, component: nil, m_id: nil, validate: true)
|
|
99
|
-
validate_ready 'subscribe to status'
|
|
113
|
+
readiness = validate_ready 'subscribe to status'
|
|
114
|
+
return readiness if readiness.failure?
|
|
115
|
+
|
|
100
116
|
component ||= main.c_id
|
|
101
117
|
m_id ||= RSMP::Message.make_m_id
|
|
102
118
|
|
|
@@ -113,7 +129,11 @@ module RSMP
|
|
|
113
129
|
})
|
|
114
130
|
apply_nts_message_attributes message
|
|
115
131
|
collector = StatusCollector.new(self, list.to_a, timeout: within, m_id: m_id)
|
|
116
|
-
send_message_and_collect(message, collector, validate: validate)
|
|
132
|
+
send_message_and_collect(message, collector, validate: validate)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def subscribe_to_status_and_collect!(...)
|
|
136
|
+
subscribe_to_status_and_collect(...).value!
|
|
117
137
|
end
|
|
118
138
|
|
|
119
139
|
def remove_subscription_item(component_id, code, name)
|
|
@@ -131,15 +151,20 @@ module RSMP
|
|
|
131
151
|
remove_subscription_item(component, item['sCI'], item['n'])
|
|
132
152
|
end
|
|
133
153
|
|
|
134
|
-
|
|
154
|
+
# Local subscription state must be cleaned up even when the peer has
|
|
155
|
+
# already disconnected. In that case there is nothing left to send.
|
|
156
|
+
return Result.success(nil) unless ready?
|
|
135
157
|
|
|
136
158
|
message = RSMP::StatusUnsubscribe.new({
|
|
137
159
|
'cId' => component,
|
|
138
160
|
'sS' => status_list
|
|
139
161
|
})
|
|
140
162
|
apply_nts_message_attributes message
|
|
141
|
-
send_message
|
|
142
|
-
|
|
163
|
+
send_message(message, validate: validate).map(&:message)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def unsubscribe_to_status!(...)
|
|
167
|
+
unsubscribe_to_status(...).value!
|
|
143
168
|
end
|
|
144
169
|
|
|
145
170
|
# unsubscribes to all statuses (with all attributes) defined in the used SXL
|
|
@@ -56,10 +56,6 @@ module RSMP
|
|
|
56
56
|
else
|
|
57
57
|
super
|
|
58
58
|
end
|
|
59
|
-
rescue RSMP::RepeatedAlarmError, RSMP::RepeatedStatusError, RSMP::TimestampError => e
|
|
60
|
-
str = "Rejected #{message.type} message,"
|
|
61
|
-
dont_acknowledge message, str, e.to_s
|
|
62
|
-
distribute_error e.exception("#{str}#{e.message} #{message.json}")
|
|
63
59
|
end
|
|
64
60
|
|
|
65
61
|
def handled_by_parent?(message)
|
|
@@ -115,7 +111,18 @@ module RSMP
|
|
|
115
111
|
end
|
|
116
112
|
|
|
117
113
|
def validate_ready(action)
|
|
118
|
-
|
|
114
|
+
return Result.success(self) if ready?
|
|
115
|
+
|
|
116
|
+
Result.failure(
|
|
117
|
+
:not_ready,
|
|
118
|
+
message: "Can't #{action} because connection is not ready. (Currently #{@state})",
|
|
119
|
+
source: :connection,
|
|
120
|
+
context: { action: action, state: @state, session_id: session_id }
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def validate_ready!(action)
|
|
125
|
+
validate_ready(action).value!
|
|
119
126
|
end
|
|
120
127
|
|
|
121
128
|
def version_acknowledged; end
|
|
@@ -204,11 +211,6 @@ module RSMP
|
|
|
204
211
|
end
|
|
205
212
|
end
|
|
206
213
|
|
|
207
|
-
def receive_error(error, options = {})
|
|
208
|
-
@supervisor&.receive_error error, options
|
|
209
|
-
distribute_error error, options
|
|
210
|
-
end
|
|
211
|
-
|
|
212
214
|
def build_component(id:, type:, settings: {})
|
|
213
215
|
settings ||= {}
|
|
214
216
|
if type == 'main'
|
|
@@ -34,8 +34,13 @@ module RSMP
|
|
|
34
34
|
configured = configured_sxls.find { |item| item['name'] == requested['name'] }
|
|
35
35
|
return rejected_sxl(requested, 1, 'SXL not supported') unless configured
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
unless RSMP::Schema.strict_version?(requested['version'])
|
|
38
|
+
return rejected_sxl(requested, 2, 'Core 3.3 requires SXL versions to use MAJOR.MINOR.PATCH')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
configured_version = RSMP::Schema.sanitize_version(configured['version'].to_s)
|
|
42
|
+
if configured_version == requested['version']
|
|
43
|
+
RSMP::Schema.find_schema! requested['name'], requested['version']
|
|
39
44
|
requested.slice('name', 'version', 'prefix')
|
|
40
45
|
else
|
|
41
46
|
rejected_sxl(requested, 2, "Supervisor only supports #{configured['version']}")
|
|
@@ -88,7 +88,7 @@ module RSMP
|
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
def buffer_message(message
|
|
91
|
+
def buffer_message(message)
|
|
92
92
|
prepared = prepare_message_for_buffer message, core_version: @core_version
|
|
93
93
|
if prepared
|
|
94
94
|
enqueue_buffered_message prepared
|
|
@@ -97,8 +97,6 @@ module RSMP
|
|
|
97
97
|
else
|
|
98
98
|
super
|
|
99
99
|
end
|
|
100
|
-
rescue NotReady, IOError
|
|
101
|
-
raise error if error
|
|
102
100
|
end
|
|
103
101
|
|
|
104
102
|
def enqueue_buffered_message(message)
|
|
@@ -118,19 +116,20 @@ module RSMP
|
|
|
118
116
|
@message_buffer = []
|
|
119
117
|
log "Sending #{queued.size} buffered message(s)", level: :info
|
|
120
118
|
queued.each_with_index do |message, index|
|
|
121
|
-
break unless flush_buffered_message(message, queued, index)
|
|
119
|
+
break unless flush_buffered_message?(message, queued, index)
|
|
122
120
|
end
|
|
123
121
|
end
|
|
124
122
|
|
|
125
|
-
def flush_buffered_message(message, queued, index)
|
|
123
|
+
def flush_buffered_message?(message, queued, index)
|
|
126
124
|
prepared = prepare_message_for_buffer message, core_version: @core_version, for_send: true
|
|
127
125
|
return true unless prepared
|
|
128
126
|
|
|
129
|
-
send_message
|
|
130
|
-
true
|
|
131
|
-
|
|
127
|
+
result = send_message(prepared, 'from buffer', buffer: false)
|
|
128
|
+
return true if result.success?
|
|
129
|
+
|
|
132
130
|
@message_buffer = queued[index..] + @message_buffer
|
|
133
|
-
log "Stopped sending buffered messages
|
|
131
|
+
log "Stopped sending buffered messages (#{result.failure.code}); " \
|
|
132
|
+
"#{message_buffer.size} message(s) remain queued", level: :warning
|
|
134
133
|
false
|
|
135
134
|
end
|
|
136
135
|
end
|