rsmp 0.53.3 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +1 -1
- data/README.md +6 -0
- data/documentation/cli.md +15 -2
- data/documentation/configuration.md +65 -1
- data/lib/rsmp/node/site/site.rb +9 -3
- data/lib/rsmp/node/supervisor/modules/configuration.rb +2 -2
- data/lib/rsmp/options/options.rb +3 -34
- data/lib/rsmp/options/schemas/config_common.json +11 -0
- data/lib/rsmp/options/schemas/site.json +1 -1
- data/lib/rsmp/options/schemas/supervisor_site.json +1 -1
- data/lib/rsmp/options/sxl_options.rb +56 -0
- data/lib/rsmp/proxy/modules/versions.rb +4 -2
- data/lib/rsmp/proxy/proxy.rb +1 -0
- data/lib/rsmp/proxy/site/sxl_selection.rb +12 -8
- data/lib/rsmp/proxy/supervisor/modules/sxl_hints.rb +60 -0
- data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +2 -4
- data/lib/rsmp/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 634c31243e8753c8e71a0617a3bd9a2747a320fdeb8b78827746095202eb0092
|
|
4
|
+
data.tar.gz: ff873bb9211175d9577595dabe5e747f47fceb556e584d33f1ee6c1d86db2420
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e774cdf65f73e20fa881bc269011afb791c0b695eabdbe2c1aa4c953ad408c2bc5deb21894820829cbde16c9c2448ddd64c685d4bec638d0d049a93e9ac36ad8
|
|
7
|
+
data.tar.gz: b9eb1b8cd9abedc414236b74749b9ba818619137a95b5edae74fc4881b9299a1fae6f804001858b42dc4ff668d5634aa32261fd44eba7f0e8bc819b4fcf016da
|
data/CHANGELOG.md
CHANGED
|
@@ -745,3 +745,18 @@ Initial release.
|
|
|
745
745
|
## 0.53.2
|
|
746
746
|
- fix issues with Alarm enum casing
|
|
747
747
|
- update TLC schemas
|
|
748
|
+
|
|
749
|
+
## 0.53.3
|
|
750
|
+
- prevent possible sxl negotiation race
|
|
751
|
+
|
|
752
|
+
## 0.54.4
|
|
753
|
+
- accept only the sxl version the supervisor has configured
|
|
754
|
+
- require configured sxl versions to use strick SemVer format major.minor.patch
|
|
755
|
+
|
|
756
|
+
## Unreleased
|
|
757
|
+
|
|
758
|
+
- support ordered SXL version lists: sites start with the first version; supervisors accept any listed version
|
|
759
|
+
- add optional testing hints in legacy-only initial Version rejections, allowing sites with version lists to reconnect using an allowed hinted version
|
|
760
|
+
- retain hinted selections per supervisor across reconnects and rejections, while fixed-version sites ignore hints
|
|
761
|
+
- clear subscriptions and buffered messages when switching SXL versions
|
|
762
|
+
- document that hint-based switching is a testing convention outside the RSMP Core specification
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -159,6 +159,12 @@ sxls:
|
|
|
159
159
|
tlc: '1.3.0'
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
+
Each SXL name has a configured version string or an ordered list of versions in `MAJOR.MINOR.PATCH` form.
|
|
163
|
+
Supervisors accept only matching SXL versions; legacy equipment may use an equivalent spelling such as `1.2` for `1.2.0`.
|
|
164
|
+
On sites, a list starts with its first version and enables [SXL hints for testing](documentation/configuration.md#sxl-hints-for-testing)
|
|
165
|
+
when the handshake offers only Core versions before 3.3.0.
|
|
166
|
+
Hint-based reconnects are a testing convention, not part of the RSMP Core specification.
|
|
167
|
+
|
|
162
168
|
See [configuration](documentation/configuration.md) for connection-role examples and other YAML settings.
|
|
163
169
|
|
|
164
170
|
## Command-line tool
|
data/documentation/cli.md
CHANGED
|
@@ -116,7 +116,7 @@ Common options:
|
|
|
116
116
|
- `--id ID`, `-i ID`: set the site id.
|
|
117
117
|
- `--supervisors LIST`, `-s LIST`: set one or more supervisor endpoints.
|
|
118
118
|
- `--core VERSION`: set the RSMP Core version.
|
|
119
|
-
- `--sxls LIST`: set the SXLs announced by the site as a comma-separated `name:version` list.
|
|
119
|
+
- `--sxls LIST`: set the SXLs announced by the site as a comma-separated `name:version` list, with one `MAJOR.MINOR.PATCH` version per SXL name.
|
|
120
120
|
- `--type tlc`, `-t tlc`: choose the site type. Currently `tlc` is the supported CLI type.
|
|
121
121
|
- `--log PATH`, `-l PATH`: write log output to a file.
|
|
122
122
|
- `--json`, `-j`: include raw JSON messages in the log.
|
|
@@ -145,6 +145,19 @@ Use `--sxls` to specify several SXLs for a site:
|
|
|
145
145
|
$ rsmp site --sxls tlc:1.3.0,vms:1.0.0
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
+
`--sxls` sets one fixed version per SXL name. To enable the optional hint/reconnect testing convention,
|
|
149
|
+
configure ordered version lists in YAML and use `--config` without overriding those SXLs:
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
core_version: '3.2.2'
|
|
153
|
+
sxls:
|
|
154
|
+
tlc: ['1.2.1', '1.0.15', '1.2.0']
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
See [SXL hints for testing](configuration.md#sxl-hints-for-testing). This convention is not part of RSMP Core
|
|
158
|
+
and applies only when the initial handshake offers Core versions before 3.3.0.
|
|
159
|
+
For a supervisor, YAML version lists specify the accepted versions; `--sxls` replaces them with fixed versions.
|
|
160
|
+
|
|
148
161
|
Example with explicit core and SXL versions:
|
|
149
162
|
|
|
150
163
|
```console
|
|
@@ -166,7 +179,7 @@ Common options:
|
|
|
166
179
|
- `--ip ADDRESS`: set the listen address.
|
|
167
180
|
- `--port PORT`, `-p PORT`: set the listen port.
|
|
168
181
|
- `--core VERSION`: override the accepted RSMP Core version.
|
|
169
|
-
- `--sxls LIST`: override SXL versions as a comma-separated `name:version` list.
|
|
182
|
+
- `--sxls LIST`: override supported SXL versions as a comma-separated `name:version` list, with one `MAJOR.MINOR.PATCH` version per SXL name.
|
|
170
183
|
- `--log PATH`, `-l PATH`: write log output to a file.
|
|
171
184
|
- `--json`, `-j`: include raw JSON messages in the log.
|
|
172
185
|
|
|
@@ -37,7 +37,71 @@ Core 3.3.0 and later use exact `MAJOR.MINOR.PATCH` version strings for both Core
|
|
|
37
37
|
|
|
38
38
|
Earlier Core versions retain their historical wire formats for compatibility. In particular, the Core 3.2 release may be written as either `3.2` or `3.2.0`. The library resolves both to the `3.2.0` schema internally, but a supervisor responding to a legacy Version message uses the exact Core and SXL strings sent by the site. Ambiguous versions such as `3.1` are rejected because they do not identify one of the supported 3.1.x releases.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Configured SXL versions must use `MAJOR.MINOR.PATCH`, for example `sxls: { tlc: '1.2.0' }`.
|
|
41
|
+
Each SXL name maps to a version string or a non-empty, ordered list of distinct version strings.
|
|
42
|
+
Abbreviated versions such as `1.2` and versions with suffixes are rejected in configuration and CLI overrides.
|
|
43
|
+
For connections using a Core version before 3.3.0, equipment may still send legacy SXL strings such as `1.2`.
|
|
44
|
+
The supervisor compares their three-part equivalents against the configured version and uses the original string in its response.
|
|
45
|
+
|
|
46
|
+
The supervisor rejects a legacy Version message when the offered SXL version
|
|
47
|
+
does not match its effective configuration for that site, even if a schema for the offered version is available.
|
|
48
|
+
For example, with `tlc: '1.2.1'` configured, an offer of `1.0.15` receives `MessageNotAck` and the
|
|
49
|
+
connection closes. Its `rea` field identifies the requested and supported versions.
|
|
50
|
+
Core 3.3.0 uses the SXL response statuses described below.
|
|
51
|
+
|
|
52
|
+
## SXL hints for testing
|
|
53
|
+
|
|
54
|
+
**SXL hints and reconnect-based switching are an optional testing convention, not part of the RSMP Core specification.**
|
|
55
|
+
Other equipment is not expected to understand them. Hints apply only to handshakes offering Core versions
|
|
56
|
+
before 3.3.0. Core 3.3.0 uses its standard SXL response statuses.
|
|
57
|
+
|
|
58
|
+
A site configured with a single version string always uses that version and ignores hints.
|
|
59
|
+
A list enables hint handling for that SXL name:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
core_version: '3.2.2'
|
|
63
|
+
sxls:
|
|
64
|
+
tlc: ['1.2.1', '1.0.15', '1.2.0']
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Configure a legacy Core version explicitly. An initial rejection does not identify the selected Core version,
|
|
68
|
+
so hints are ignored if the request offers Core 3.3.0 or later, including mixed-version offers.
|
|
69
|
+
|
|
70
|
+
The site initially offers the first version, `1.2.1` in this example. It follows a hint only when
|
|
71
|
+
`MessageNotAck.oMId` refers to its outstanding initial Version request, before a Version response has been accepted.
|
|
72
|
+
On rejection, it closes the connection and uses the normal `intervals.reconnect` delay before reconnecting in client role.
|
|
73
|
+
A site in server role waits for the supervisor to reconnect.
|
|
74
|
+
|
|
75
|
+
The hint is a case-sensitive `hint:` token in `MessageNotAck.rea`. It must start at a word boundary,
|
|
76
|
+
so `thint:` does not count. The value must be a complete version, without extra version parts or suffixes,
|
|
77
|
+
and end at whitespace, a semicolon or the end of the string. For example:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
SXL tlc version 1.2.1 requested, but only 1.0.15 supported; hint: 1.0.15
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`hint: 1.0.15` refers to the connection's single legacy `SXL` version. The gem takes this SXL from
|
|
84
|
+
the first entry in its `sxls` configuration. The hinted version must use `MAJOR.MINOR.PATCH` and appear
|
|
85
|
+
in that entry's configured list. Named hints and rejections containing multiple `hint:` tokens are ignored.
|
|
86
|
+
|
|
87
|
+
The last allowed hinted version is retained across ordinary reconnects and later rejections.
|
|
88
|
+
Missing, malformed or unlisted hints leave it unchanged. Unknown message IDs, rejections of other messages,
|
|
89
|
+
and rejections after Version acceptance cannot change the selection. Creating a new site instance or
|
|
90
|
+
restarting the process restores the first configured version.
|
|
91
|
+
|
|
92
|
+
Selections are kept separately for each supervisor address and port, without modifying the configuration.
|
|
93
|
+
For sites in server role, selections are keyed by the supervisor's source IP because its source port changes
|
|
94
|
+
on reconnect. When switching versions, the connection's subscriptions and buffered messages are cleared;
|
|
95
|
+
the supervisor must subscribe again after reconnection.
|
|
96
|
+
|
|
97
|
+
On a supervisor, a version list means that any listed version is supported. A legacy SXL mismatch is rejected
|
|
98
|
+
with a hint for the first version in that list (or the single configured version). A supported offer is accepted
|
|
99
|
+
even if it is not the first entry. All listed versions must have schemas available locally.
|
|
100
|
+
Core 3.3.0 continues to report `mismatch` with a sorted `supported` list; that response does not trigger automatic switching.
|
|
101
|
+
|
|
102
|
+
For matrix testing, use a separate run with one fixed supervisor version for each matrix entry.
|
|
103
|
+
Wait for a matching handshake before running tests, and serialize runs sharing a physical site.
|
|
104
|
+
A version retained from a previous run will then be rejected with the next run's required version.
|
|
41
105
|
|
|
42
106
|
## Core 3.3.0
|
|
43
107
|
|
data/lib/rsmp/node/site/site.rb
CHANGED
|
@@ -65,7 +65,7 @@ module RSMP
|
|
|
65
65
|
return settings unless sxls.is_a?(Array)
|
|
66
66
|
|
|
67
67
|
settings.merge(
|
|
68
|
-
'sxls' => sxls.to_h { |sxl| [sxl['name'], sxl['version']] }
|
|
68
|
+
'sxls' => sxls.to_h { |sxl| [sxl['name'], sxl['versions'] || sxl['version']] }
|
|
69
69
|
)
|
|
70
70
|
end
|
|
71
71
|
|
|
@@ -74,13 +74,19 @@ module RSMP
|
|
|
74
74
|
|
|
75
75
|
sxls.each do |sxl|
|
|
76
76
|
name = sxl['name']
|
|
77
|
-
version = sxl['version'].to_s
|
|
78
77
|
raise RSMP::ConfigurationError, 'SXL name cannot be core' if name.to_s == 'core'
|
|
79
78
|
|
|
80
|
-
RSMP::Schema.find_schema! name, version
|
|
79
|
+
(sxl['versions'] || [sxl['version']]).each { |version| RSMP::Schema.find_schema! name, version }
|
|
81
80
|
end
|
|
82
81
|
end
|
|
83
82
|
|
|
83
|
+
# Keep testing selections separate from configuration and scoped to the peer.
|
|
84
|
+
# Incoming connections have changing source ports, so server sites use the IP.
|
|
85
|
+
def hinted_sxl_versions(ip, port)
|
|
86
|
+
@hinted_sxl_versions ||= {}
|
|
87
|
+
@hinted_sxl_versions[[ip, server_role? ? nil : port]] ||= {}
|
|
88
|
+
end
|
|
89
|
+
|
|
84
90
|
def check_core_versions
|
|
85
91
|
version = @site_settings['core_version']
|
|
86
92
|
return unless version
|
|
@@ -25,7 +25,7 @@ module RSMP
|
|
|
25
25
|
return settings unless sxls.is_a?(Array)
|
|
26
26
|
|
|
27
27
|
settings.merge(
|
|
28
|
-
'sxls' => sxls.to_h { |sxl| [sxl['name'], sxl['version']] }
|
|
28
|
+
'sxls' => sxls.to_h { |sxl| [sxl['name'], sxl['versions'] || sxl['version']] }
|
|
29
29
|
)
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -52,7 +52,7 @@ module RSMP
|
|
|
52
52
|
"Configuration error for site '#{site_id}': SXL name cannot be core"
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
RSMP::Schema.find_schema! name,
|
|
55
|
+
(sxl['versions'] || [sxl['version']]).each { |version| RSMP::Schema.find_schema! name, version }
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
data/lib/rsmp/options/options.rb
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
require 'yaml'
|
|
2
2
|
require 'pathname'
|
|
3
|
+
require_relative 'sxl_options'
|
|
3
4
|
|
|
4
5
|
module RSMP
|
|
5
6
|
# Base class for configuration options.
|
|
6
7
|
class Options
|
|
8
|
+
include SxlOptions
|
|
9
|
+
|
|
7
10
|
SCHEMAS_PATH = File.expand_path('schemas', __dir__)
|
|
8
11
|
|
|
9
12
|
attr_reader :data, :log_settings, :source
|
|
@@ -108,19 +111,6 @@ module RSMP
|
|
|
108
111
|
end
|
|
109
112
|
end
|
|
110
113
|
|
|
111
|
-
def normalize_sxls(value)
|
|
112
|
-
case value
|
|
113
|
-
when Hash
|
|
114
|
-
value.map do |name, details|
|
|
115
|
-
normalize_sxl_item(name.to_s, details)
|
|
116
|
-
end
|
|
117
|
-
when Array
|
|
118
|
-
value.map { |item| normalize(item) }
|
|
119
|
-
else
|
|
120
|
-
value
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
|
|
124
114
|
def normalize_config(value)
|
|
125
115
|
case value
|
|
126
116
|
when Hash
|
|
@@ -135,27 +125,6 @@ module RSMP
|
|
|
135
125
|
end
|
|
136
126
|
end
|
|
137
127
|
|
|
138
|
-
def normalize_config_sxls(value)
|
|
139
|
-
raise RSMP::ConfigurationError, 'sxls must be a hash of SXL names to versions' unless value.is_a?(Hash)
|
|
140
|
-
|
|
141
|
-
value.each_with_object({}) do |(name, details), memo|
|
|
142
|
-
raise RSMP::ConfigurationError, "sxls/#{name} must be a version string" if details.is_a?(Hash)
|
|
143
|
-
|
|
144
|
-
memo[name.to_s] = details.to_s
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def normalize_sxl_item(name, details)
|
|
149
|
-
case details
|
|
150
|
-
when Hash
|
|
151
|
-
raise RSMP::ConfigurationError, "sxls/#{name} must be a version string"
|
|
152
|
-
when nil
|
|
153
|
-
{ 'name' => name }
|
|
154
|
-
else
|
|
155
|
-
{ 'name' => name, 'version' => details.to_s }
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
128
|
def format_error(error)
|
|
160
129
|
pointer = error_pointer(error)
|
|
161
130
|
details = error_details(error)
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "config_common.json",
|
|
4
4
|
"$defs": {
|
|
5
|
+
"sxl_versions": {
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{ "type": "string" },
|
|
8
|
+
{
|
|
9
|
+
"type": "array",
|
|
10
|
+
"minItems": 1,
|
|
11
|
+
"uniqueItems": true,
|
|
12
|
+
"items": { "type": "string", "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" }
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
5
16
|
"endpoint": {
|
|
6
17
|
"type": "object",
|
|
7
18
|
"properties": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"sxls": {
|
|
16
16
|
"type": "object",
|
|
17
17
|
"propertyNames": { "not": { "const": "core" } },
|
|
18
|
-
"additionalProperties": { "
|
|
18
|
+
"additionalProperties": { "$ref": "config_common.json#/$defs/sxl_versions" }
|
|
19
19
|
},
|
|
20
20
|
"core_version": { "type": "string" },
|
|
21
21
|
"intervals": { "$ref": "config_common.json#/$defs/intervals" },
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"sxls": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"propertyNames": { "not": { "const": "core" } },
|
|
9
|
-
"additionalProperties": { "
|
|
9
|
+
"additionalProperties": { "$ref": "config_common.json#/$defs/sxl_versions" }
|
|
10
10
|
},
|
|
11
11
|
"core_version": { "type": "string" },
|
|
12
12
|
"rsmp_versions": {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
# Configuration and internal representation of supported SXL versions.
|
|
3
|
+
module SxlOptions
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def normalize_sxls(value)
|
|
7
|
+
case value
|
|
8
|
+
when Hash
|
|
9
|
+
value.map do |name, details|
|
|
10
|
+
normalize_sxl_item(name.to_s, details)
|
|
11
|
+
end
|
|
12
|
+
when Array
|
|
13
|
+
value.map { |item| normalize(item) }
|
|
14
|
+
else
|
|
15
|
+
value
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def normalize_config_sxls(value)
|
|
20
|
+
raise RSMP::ConfigurationError, 'sxls must be a hash of SXL names to versions' unless value.is_a?(Hash)
|
|
21
|
+
|
|
22
|
+
value.each_with_object({}) do |(name, details), memo|
|
|
23
|
+
validate_sxl_versions!(name, details)
|
|
24
|
+
memo[name.to_s] = details
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def validate_sxl_versions!(name, details)
|
|
29
|
+
versions = details.is_a?(Array) ? details : [details]
|
|
30
|
+
if versions.empty? || versions.any? { |version| !version.is_a?(String) }
|
|
31
|
+
raise RSMP::ConfigurationError, "sxls/#{name} must be a version string or a non-empty list of version strings"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
valid = versions.all? do |version|
|
|
35
|
+
RSMP::Schema.strict_version?(version) || (details.is_a?(String) && version == 'latest')
|
|
36
|
+
end
|
|
37
|
+
raise RSMP::ConfigurationError, "sxls/#{name} must use MAJOR.MINOR.PATCH" unless valid
|
|
38
|
+
return if versions.uniq == versions
|
|
39
|
+
|
|
40
|
+
raise RSMP::ConfigurationError, "sxls/#{name} must not contain duplicate versions"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def normalize_sxl_item(name, details)
|
|
44
|
+
case details
|
|
45
|
+
when Array
|
|
46
|
+
{ 'name' => name, 'version' => details.first, 'versions' => details.dup }
|
|
47
|
+
when Hash
|
|
48
|
+
raise RSMP::ConfigurationError, "sxls/#{name} must be a version string"
|
|
49
|
+
when nil
|
|
50
|
+
{ 'name' => name }
|
|
51
|
+
else
|
|
52
|
+
{ 'name' => name, 'version' => details.to_s }
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -45,7 +45,7 @@ module RSMP
|
|
|
45
45
|
|
|
46
46
|
def sxl_request_items
|
|
47
47
|
configured_sxls.map do |sxl|
|
|
48
|
-
version =
|
|
48
|
+
version = sxl['version']
|
|
49
49
|
item = { 'name' => sxl['name'], 'version' => version }
|
|
50
50
|
prefix = RSMP::Schema.sxl_prefix(sxl['name'], version)
|
|
51
51
|
item['prefix'] = prefix if prefix
|
|
@@ -120,7 +120,9 @@ module RSMP
|
|
|
120
120
|
attributes.merge!(version_request_attributes)
|
|
121
121
|
attributes['SXL'] = legacy_sxl unless @offered_core_versions.include?('3.3.0')
|
|
122
122
|
end
|
|
123
|
-
|
|
123
|
+
message = Version.new(attributes)
|
|
124
|
+
@initial_version_request_id = message.m_id if step == 'Request'
|
|
125
|
+
send_generated_message message, validate: false
|
|
124
126
|
end
|
|
125
127
|
|
|
126
128
|
def version_message_attributes(site_id, core_versions)
|
data/lib/rsmp/proxy/proxy.rb
CHANGED
|
@@ -14,13 +14,15 @@ module RSMP
|
|
|
14
14
|
|
|
15
15
|
def select_legacy_sxl(message)
|
|
16
16
|
primary = configured_sxls.first
|
|
17
|
-
unless primary
|
|
18
|
-
reason = 'Legacy Version message received, but no SXL is configured'
|
|
19
|
-
dont_acknowledge message, "Rejected #{message.type} message,", reason
|
|
20
|
-
raise HandshakeError, reason
|
|
21
|
-
end
|
|
17
|
+
raise HandshakeError, 'Legacy Version message received, but no SXL is configured' unless primary
|
|
22
18
|
|
|
23
19
|
sanitized_version = RSMP::Schema.sanitize_version(message.attribute('SXL'))
|
|
20
|
+
versions = primary['versions'] || [primary['version']]
|
|
21
|
+
unless versions.include?(sanitized_version)
|
|
22
|
+
raise HandshakeError,
|
|
23
|
+
"SXL #{primary['name']} version #{message.attribute('SXL')} requested, " \
|
|
24
|
+
"but only #{versions.join(', ')} supported; hint: #{versions.first}"
|
|
25
|
+
end
|
|
24
26
|
RSMP::Schema.find_schema! primary['name'], sanitized_version
|
|
25
27
|
@accepted_sxls = [{ 'name' => primary['name'], 'version' => message.attribute('SXL') }]
|
|
26
28
|
@rejected_sxls = []
|
|
@@ -39,12 +41,14 @@ module RSMP
|
|
|
39
41
|
configured = configured_sxls.find { |item| item['name'] == requested['name'] }
|
|
40
42
|
return { 'name' => requested['name'], 'status' => 'unsupported' } unless configured
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
versions = configured['versions'] || [configured['version']]
|
|
45
|
+
version = requested['version']
|
|
46
|
+
if versions.include?(version)
|
|
44
47
|
RSMP::Schema.find_schema! requested['name'], version
|
|
45
48
|
{ 'name' => requested['name'], 'status' => 'ok', 'version' => version }
|
|
46
49
|
else
|
|
47
|
-
{ 'name' => requested['name'], 'status' => 'mismatch',
|
|
50
|
+
{ 'name' => requested['name'], 'status' => 'mismatch',
|
|
51
|
+
'supported' => versions.sort_by { |item| Gem::Version.new(item) } }
|
|
48
52
|
end
|
|
49
53
|
end
|
|
50
54
|
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
class SupervisorProxy < Proxy
|
|
3
|
+
module Modules
|
|
4
|
+
# Optional testing convention, not RSMP Core SXL negotiation.
|
|
5
|
+
module SxlHints
|
|
6
|
+
def start_handshake
|
|
7
|
+
@sxls = configured_sxls
|
|
8
|
+
@accepted_sxls = @sxls.dup
|
|
9
|
+
@rejected_sxls = []
|
|
10
|
+
send_version_request @site_settings['site_id'], advertised_core_versions
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def configured_sxls
|
|
14
|
+
selections = @site.hinted_sxl_versions(@ip, @port)
|
|
15
|
+
super.map do |item|
|
|
16
|
+
version = selections[item['name']]
|
|
17
|
+
item['versions']&.include?(version) ? item.merge('version' => version) : item
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def process_not_ack(message)
|
|
22
|
+
original = find_original_for_message(message)
|
|
23
|
+
initial = original.is_a?(Version) && original.m_id == @initial_version_request_id && !@version_determined
|
|
24
|
+
super
|
|
25
|
+
return unless initial
|
|
26
|
+
|
|
27
|
+
legacy = original.versions.all? { |version| version_meets_requirement?(version, '<3.3.0') }
|
|
28
|
+
apply_sxl_hint(message.attributes['rea']) if legacy
|
|
29
|
+
close(reason: :version_rejected)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def apply_sxl_hint(reason)
|
|
33
|
+
version = parse_sxl_hint(reason)
|
|
34
|
+
return unless version
|
|
35
|
+
|
|
36
|
+
configured = primary_configured_sxl
|
|
37
|
+
return unless configured && configured['versions']&.include?(version)
|
|
38
|
+
return if configured['version'] == version
|
|
39
|
+
|
|
40
|
+
name = configured['name']
|
|
41
|
+
@site.hinted_sxl_versions(@ip, @port)[name] = version
|
|
42
|
+
# Subscriptions and queued messages belong to the previous SXL version.
|
|
43
|
+
@status_subscriptions.clear
|
|
44
|
+
@message_buffer.clear
|
|
45
|
+
log "Following testing SXL hint: #{name} #{version} on next connection", level: :info
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def parse_sxl_hint(reason)
|
|
49
|
+
return unless reason.is_a?(String)
|
|
50
|
+
|
|
51
|
+
hints = reason.scan(/\bhint:\s*([^\s;]+)/).flatten
|
|
52
|
+
return unless hints.size == 1
|
|
53
|
+
|
|
54
|
+
version = hints.first
|
|
55
|
+
version if RSMP::Schema.strict_version?(version)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'digest'
|
|
2
|
+
require_relative 'modules/sxl_hints'
|
|
2
3
|
|
|
3
4
|
module RSMP
|
|
4
5
|
# Proxy used by sites to connect to a remote supervisor.
|
|
@@ -8,6 +9,7 @@ module RSMP
|
|
|
8
9
|
include Modules::Alarms
|
|
9
10
|
include Modules::AggregatedStatus
|
|
10
11
|
include Modules::MessageBuffer
|
|
12
|
+
include Modules::SxlHints
|
|
11
13
|
|
|
12
14
|
attr_reader :supervisor_id, :site, :message_buffer
|
|
13
15
|
|
|
@@ -62,10 +64,6 @@ module RSMP
|
|
|
62
64
|
close
|
|
63
65
|
end
|
|
64
66
|
|
|
65
|
-
def start_handshake
|
|
66
|
-
send_version_request @site_settings['site_id'], advertised_core_versions
|
|
67
|
-
end
|
|
68
|
-
|
|
69
67
|
def close(...)
|
|
70
68
|
prune_unbuffered_status_subscriptions
|
|
71
69
|
super
|
data/lib/rsmp/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rsmp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.54.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emil Tin
|
|
@@ -227,6 +227,7 @@ files:
|
|
|
227
227
|
- lib/rsmp/options/schemas/traffic_controller_site.json
|
|
228
228
|
- lib/rsmp/options/site_options.rb
|
|
229
229
|
- lib/rsmp/options/supervisor_options.rb
|
|
230
|
+
- lib/rsmp/options/sxl_options.rb
|
|
230
231
|
- lib/rsmp/options/traffic_controller_site_options.rb
|
|
231
232
|
- lib/rsmp/proxy/modules/acknowledgements.rb
|
|
232
233
|
- lib/rsmp/proxy/modules/lifecycle.rb
|
|
@@ -251,6 +252,7 @@ files:
|
|
|
251
252
|
- lib/rsmp/proxy/supervisor/modules/message_buffer.rb
|
|
252
253
|
- lib/rsmp/proxy/supervisor/modules/status.rb
|
|
253
254
|
- lib/rsmp/proxy/supervisor/modules/status_updates.rb
|
|
255
|
+
- lib/rsmp/proxy/supervisor/modules/sxl_hints.rb
|
|
254
256
|
- lib/rsmp/proxy/supervisor/supervisor_proxy.rb
|
|
255
257
|
- lib/rsmp/result.rb
|
|
256
258
|
- lib/rsmp/schema.rb
|