rsmp 0.39.0 → 0.40.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/Gemfile.lock +1 -1
- data/README.md +4 -3
- data/documentation/configuration.md +76 -0
- data/lib/rsmp/cli.rb +14 -12
- data/lib/rsmp/node/site/site.rb +8 -32
- data/lib/rsmp/node/supervisor/modules/configuration.rb +3 -19
- data/lib/rsmp/options/options.rb +185 -0
- data/lib/rsmp/options/schemas/site.json +49 -0
- data/lib/rsmp/options/schemas/supervisor.json +43 -0
- data/lib/rsmp/options/schemas/traffic_controller_site.json +18 -0
- data/lib/rsmp/options/site_options.rb +44 -0
- data/lib/rsmp/options/supervisor_options.rb +28 -0
- data/lib/rsmp/options/traffic_controller_site_options.rb +12 -0
- data/lib/rsmp/tlc/traffic_controller_site.rb +4 -0
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +4 -0
- metadata +9 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7db642eae802d3f31456b221ab6297516eb081375f1778cf06cd25b597ae3d07
|
|
4
|
+
data.tar.gz: e64b67b905975ca8862dd3610a2c3553c8527378db05fc0242dbd56996f850a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9dbceb076fdfd4aee419daceb587c7802eaf664f3bde3bcd7bb944e9e1408e78b9da0987ca7b56ab0e29d65cc120822f2e2c501bff3de2f22676141194394af3
|
|
7
|
+
data.tar.gz: 25cdeff92403011140b4164541ad94a785ad8b62449563a49f1ae1ccdc99f8489e940a310d140ddda3db34f66bcded08382d5e3bfdc5cf5307cb7529c11f94d7
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -31,6 +31,9 @@ Be default, a site will try to connect to a single supervisor on localhost 127.0
|
|
|
31
31
|
|
|
32
32
|
You can pass options to control ip adresseses, ports, logging and other behaviour:
|
|
33
33
|
|
|
34
|
+
Configuration files can be loaded from YAML using the CLI or the options classes. These are validated
|
|
35
|
+
against JSON schemas and will raise errors with details on what is wrong.
|
|
36
|
+
|
|
34
37
|
```ruby
|
|
35
38
|
require 'rsmp'
|
|
36
39
|
settings = {
|
|
@@ -45,8 +48,6 @@ settings = {
|
|
|
45
48
|
RSMP::Site.new(site_settings:settings)
|
|
46
49
|
```
|
|
47
50
|
|
|
48
|
-
See lib/rsmp/site.rb and lib/rsmp/supervisor.rb for a list of settings and their default values.
|
|
49
|
-
|
|
50
51
|
### Concurrency
|
|
51
52
|
The [async](https://github.com/socketry/async) and [async-io](https://github.com/socketry/async-io) gems are used to handle concurrency. Everything happens in a single thread, but fibers are used to switch between tasks whenever an IO operation blocks.
|
|
52
53
|
|
|
@@ -162,7 +163,7 @@ Use the ```tlc``` site type to run an emulation of a traffic light controller. T
|
|
|
162
163
|
### CLI help and options.
|
|
163
164
|
Use ```--help <command>``` to get a list of available options.
|
|
164
165
|
|
|
165
|
-
Use ```--config <path>``` to point to a .yaml config file, controlling things like IP adresses, ports, and log output. Examples of config files can be found the folder ```config/```.
|
|
166
|
+
Use ```--config <path>``` or ```--options <path>``` to point to a .yaml config file, controlling things like IP adresses, ports, and log output. Examples of config files can be found the folder ```config/```.
|
|
166
167
|
|
|
167
168
|
## Tests
|
|
168
169
|
### RSpec
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
RSMP uses option classes to handle configuration for sites and supervisors. These classes provide:
|
|
5
|
+
|
|
6
|
+
- File-based configuration via YAML
|
|
7
|
+
- JSON Schema validation with descriptive errors
|
|
8
|
+
- Safe access to nested values using Ruby's `dig`
|
|
9
|
+
- Deep merging of provided values with defaults
|
|
10
|
+
|
|
11
|
+
## Option classes
|
|
12
|
+
|
|
13
|
+
- `RSMP::Site::Options` for sites
|
|
14
|
+
- `RSMP::Supervisor::Options` for supervisors
|
|
15
|
+
- `RSMP::TLC::TrafficControllerSite::Options` for TLC sites
|
|
16
|
+
|
|
17
|
+
Each class applies defaults and validates the configuration against a JSON Schema located in `lib/rsmp/options/schemas/`.
|
|
18
|
+
|
|
19
|
+
## Loading a configuration file
|
|
20
|
+
|
|
21
|
+
Use the option classes to load a YAML configuration file:
|
|
22
|
+
|
|
23
|
+
- `RSMP::Site::Options.load_file(path)`
|
|
24
|
+
- `RSMP::Supervisor::Options.load_file(path)`
|
|
25
|
+
|
|
26
|
+
The top-level `log` section is separated into `log_settings`. Other keys are treated as settings for the site or supervisor.
|
|
27
|
+
|
|
28
|
+
## CLI usage
|
|
29
|
+
|
|
30
|
+
Use the CLI with a config file:
|
|
31
|
+
|
|
32
|
+
- `rsmp site --config path/to/site.yaml`
|
|
33
|
+
- `rsmp supervisor --options path/to/supervisor.yaml`
|
|
34
|
+
|
|
35
|
+
Both `--config` and `--options` are accepted as aliases.
|
|
36
|
+
|
|
37
|
+
## Example: site YAML
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
site_id: RN+SI0001
|
|
41
|
+
supervisors:
|
|
42
|
+
- ip: 127.0.0.1
|
|
43
|
+
port: 12111
|
|
44
|
+
sxl: tlc
|
|
45
|
+
sxl_version: "1.2.1"
|
|
46
|
+
components:
|
|
47
|
+
main:
|
|
48
|
+
TC:
|
|
49
|
+
log:
|
|
50
|
+
json: true
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Example: supervisor YAML
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
port: 12111
|
|
57
|
+
guest:
|
|
58
|
+
sxl: tlc
|
|
59
|
+
intervals:
|
|
60
|
+
timer: 0.1
|
|
61
|
+
watchdog: 0.1
|
|
62
|
+
log:
|
|
63
|
+
json: true
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Validation
|
|
67
|
+
|
|
68
|
+
Invalid configurations raise `RSMP::ConfigurationError` with details about the failing path. The CLI prints these errors when loading config files.
|
|
69
|
+
|
|
70
|
+
Errors include the failing JSON pointer and helpful type hints, for example:
|
|
71
|
+
|
|
72
|
+
- `/supervisors: value at \`/supervisors\` is not an array (expected array, got string)`
|
|
73
|
+
|
|
74
|
+
## Defaults and overrides
|
|
75
|
+
|
|
76
|
+
Configuration values override defaults via deep merge. A notable exception is `components.main`, which replaces the default component list when provided.
|
data/lib/rsmp/cli.rb
CHANGED
|
@@ -10,7 +10,7 @@ module RSMP
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
desc 'site', 'Run RSMP site'
|
|
13
|
-
method_option :config, type: :string, aliases: '-c', banner: 'Path to .yaml config file'
|
|
13
|
+
method_option :config, type: :string, aliases: ['-c', '--options'], banner: 'Path to .yaml config file'
|
|
14
14
|
method_option :id, type: :string, aliases: '-i', banner: 'RSMP site id'
|
|
15
15
|
method_option :supervisors, type: :string, aliases: '-s',
|
|
16
16
|
banner: 'ip:port,... list of supervisor to connect to'
|
|
@@ -32,7 +32,7 @@ module RSMP
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
desc 'supervisor', 'Run RSMP supervisor'
|
|
35
|
-
method_option :config, type: :string, aliases: '-c', banner: 'Path to .yaml config file'
|
|
35
|
+
method_option :config, type: :string, aliases: ['-c', '--options'], banner: 'Path to .yaml config file'
|
|
36
36
|
method_option :id, type: :string, aliases: '-i', banner: 'RSMP site id'
|
|
37
37
|
method_option :ip, type: :string, banner: 'IP address to listen on'
|
|
38
38
|
method_option :port, type: :string, aliases: '-p', banner: 'Port to listen on'
|
|
@@ -63,11 +63,12 @@ module RSMP
|
|
|
63
63
|
|
|
64
64
|
return [settings, log_settings] unless options[:config]
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
begin
|
|
67
|
+
options_object = RSMP::Site::Options.load_file(options[:config])
|
|
68
|
+
settings = options_object.to_h
|
|
69
|
+
log_settings = log_settings.deep_merge(options_object.log_settings)
|
|
70
|
+
rescue RSMP::ConfigurationError => e
|
|
71
|
+
puts "Error: #{e}"
|
|
71
72
|
exit
|
|
72
73
|
end
|
|
73
74
|
|
|
@@ -135,11 +136,12 @@ module RSMP
|
|
|
135
136
|
|
|
136
137
|
return [settings, log_settings] unless options[:config]
|
|
137
138
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
begin
|
|
140
|
+
options_object = RSMP::Supervisor::Options.load_file(options[:config])
|
|
141
|
+
settings = options_object.to_h
|
|
142
|
+
log_settings = log_settings.deep_merge(options_object.log_settings)
|
|
143
|
+
rescue RSMP::ConfigurationError => e
|
|
144
|
+
puts "Error: #{e}"
|
|
143
145
|
exit
|
|
144
146
|
end
|
|
145
147
|
|
data/lib/rsmp/node/site/site.rb
CHANGED
|
@@ -5,6 +5,10 @@ module RSMP
|
|
|
5
5
|
|
|
6
6
|
attr_reader :core_version, :site_settings, :logger, :proxies
|
|
7
7
|
|
|
8
|
+
def self.options_class
|
|
9
|
+
RSMP::Site::Options
|
|
10
|
+
end
|
|
11
|
+
|
|
8
12
|
def initialize(options = {})
|
|
9
13
|
super
|
|
10
14
|
initialize_components
|
|
@@ -23,39 +27,11 @@ module RSMP
|
|
|
23
27
|
@site_settings['site_id']
|
|
24
28
|
end
|
|
25
29
|
|
|
26
|
-
def default_site_settings
|
|
27
|
-
{
|
|
28
|
-
'site_id' => 'RN+SI0001',
|
|
29
|
-
'supervisors' => [
|
|
30
|
-
{ 'ip' => '127.0.0.1', 'port' => 12_111 }
|
|
31
|
-
],
|
|
32
|
-
'sxl' => 'tlc',
|
|
33
|
-
'sxl_version' => RSMP::Schema.latest_version(:tlc),
|
|
34
|
-
'intervals' => {
|
|
35
|
-
'timer' => 0.1,
|
|
36
|
-
'watchdog' => 1,
|
|
37
|
-
'reconnect' => 0.1
|
|
38
|
-
},
|
|
39
|
-
'timeouts' => {
|
|
40
|
-
'watchdog' => 2,
|
|
41
|
-
'acknowledgement' => 2
|
|
42
|
-
},
|
|
43
|
-
'send_after_connect' => true,
|
|
44
|
-
'components' => {
|
|
45
|
-
'main' => {
|
|
46
|
-
'C1' => {}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
end
|
|
51
|
-
|
|
52
30
|
def handle_site_settings(options = {})
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@site_settings = defaults.deep_merge options[:site_settings]
|
|
31
|
+
options_class = self.class.options_class
|
|
32
|
+
settings = options[:site_settings] || {}
|
|
33
|
+
@site_options = options_class.new(settings)
|
|
34
|
+
@site_settings = @site_options.to_h
|
|
59
35
|
|
|
60
36
|
check_sxl_version
|
|
61
37
|
check_core_versions
|
|
@@ -4,25 +4,9 @@ module RSMP
|
|
|
4
4
|
# Handles supervisor configuration and site settings
|
|
5
5
|
module Configuration
|
|
6
6
|
def handle_supervisor_settings(supervisor_settings)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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']
|
|
7
|
+
options = RSMP::Supervisor::Options.new(supervisor_settings || {})
|
|
8
|
+
@supervisor_settings = options.to_h
|
|
9
|
+
@core_version = @supervisor_settings.dig('guest', 'core_version')
|
|
26
10
|
check_site_sxl_types
|
|
27
11
|
end
|
|
28
12
|
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'pathname'
|
|
3
|
+
|
|
4
|
+
module RSMP
|
|
5
|
+
# Base class for configuration options.
|
|
6
|
+
class Options
|
|
7
|
+
SCHEMAS_PATH = File.expand_path('schemas', __dir__)
|
|
8
|
+
|
|
9
|
+
attr_reader :data, :log_settings, :source
|
|
10
|
+
|
|
11
|
+
def self.load_file(path, validate: true)
|
|
12
|
+
raise RSMP::ConfigurationError, "Config #{path} not found" unless File.exist?(path)
|
|
13
|
+
|
|
14
|
+
raw = YAML.load_file(path)
|
|
15
|
+
raise RSMP::ConfigurationError, "Config #{path} must be a hash" unless raw.is_a?(Hash) || raw.nil?
|
|
16
|
+
|
|
17
|
+
raw ||= {}
|
|
18
|
+
log_settings = raw.delete('log') || {}
|
|
19
|
+
new(raw, source: path, log_settings: log_settings, validate: validate)
|
|
20
|
+
rescue Psych::SyntaxError => e
|
|
21
|
+
raise RSMP::ConfigurationError, "Cannot read config file #{path}: #{e}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize(options = nil, source: nil, log_settings: nil, validate: true, **extra)
|
|
25
|
+
options = extra if options.nil? && extra.any?
|
|
26
|
+
@source = source
|
|
27
|
+
@log_settings = normalize(log_settings || {})
|
|
28
|
+
normalized = normalize(options || {})
|
|
29
|
+
@data = apply_defaults(normalized)
|
|
30
|
+
validate! if validate
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def defaults
|
|
34
|
+
{}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def schema_file
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def schema_path
|
|
42
|
+
return unless schema_file
|
|
43
|
+
|
|
44
|
+
File.join(SCHEMAS_PATH, schema_file)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def validate!
|
|
48
|
+
return unless schema_path && File.exist?(schema_path)
|
|
49
|
+
|
|
50
|
+
schemer = JSONSchemer.schema(Pathname.new(schema_path))
|
|
51
|
+
errors = schemer.validate(@data).to_a
|
|
52
|
+
return if errors.empty?
|
|
53
|
+
|
|
54
|
+
message = errors.map { |error| format_error(error) }.join("\n")
|
|
55
|
+
raise RSMP::ConfigurationError, "Invalid configuration#{source_suffix}:\n#{message}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def dig(*path, default: nil, assume: nil)
|
|
59
|
+
value = @data.dig(*path)
|
|
60
|
+
return value unless value.nil?
|
|
61
|
+
return default unless default.nil?
|
|
62
|
+
return assume unless assume.nil?
|
|
63
|
+
|
|
64
|
+
raise RSMP::ConfigurationError, "Config #{path.inspect} is missing"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def [](key)
|
|
68
|
+
@data[key]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def to_h
|
|
72
|
+
@data
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def apply_defaults(options)
|
|
78
|
+
defaults.deep_merge(options)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def normalize(value)
|
|
82
|
+
case value
|
|
83
|
+
when Hash
|
|
84
|
+
value.each_with_object({}) do |(key, val), memo|
|
|
85
|
+
memo[key.to_s] = normalize(val)
|
|
86
|
+
end
|
|
87
|
+
when Array
|
|
88
|
+
value.map { |item| normalize(item) }
|
|
89
|
+
else
|
|
90
|
+
value
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def format_error(error)
|
|
95
|
+
pointer = error_pointer(error)
|
|
96
|
+
details = error_details(error)
|
|
97
|
+
type_hint = error_type_hint(error)
|
|
98
|
+
schema_suffix = schema_pointer_suffix(error)
|
|
99
|
+
|
|
100
|
+
"#{pointer}: #{details}#{type_hint}#{schema_suffix}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def error_pointer(error)
|
|
104
|
+
pointer = error['data_pointer'] || error['instanceLocation'] || error['dataPath']
|
|
105
|
+
pointer = pointer.to_s
|
|
106
|
+
pointer.empty? ? '/' : pointer
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def error_details(error)
|
|
110
|
+
details = error['message'] || error['error']
|
|
111
|
+
details ||= begin
|
|
112
|
+
type = error['type'] || error['keyword']
|
|
113
|
+
extra = error['details']
|
|
114
|
+
[type, extra].compact.join(' ')
|
|
115
|
+
end
|
|
116
|
+
details.to_s
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def error_type_hint(error)
|
|
120
|
+
expected = expected_type(error['schema'])
|
|
121
|
+
actual = describe_type(error['data'])
|
|
122
|
+
return '' unless expected && actual
|
|
123
|
+
|
|
124
|
+
" (expected #{expected}, got #{actual})"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def schema_pointer_suffix(error)
|
|
128
|
+
schema_pointer = error['schema_pointer'] || error['schemaLocation'] || error['keywordLocation']
|
|
129
|
+
schema_pointer = schema_pointer.to_s
|
|
130
|
+
schema_pointer.empty? ? '' : " (schema #{schema_pointer})"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def expected_type(schema)
|
|
134
|
+
return unless schema.is_a?(Hash)
|
|
135
|
+
|
|
136
|
+
type = schema['type']
|
|
137
|
+
return format_type(type) if type
|
|
138
|
+
|
|
139
|
+
types = []
|
|
140
|
+
%w[oneOf anyOf].each do |key|
|
|
141
|
+
next unless schema[key].is_a?(Array)
|
|
142
|
+
|
|
143
|
+
types.concat(schema[key].map { |item| item['type'] }.compact)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
format_type(types) if types.any?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def format_type(type)
|
|
150
|
+
case type
|
|
151
|
+
when Array
|
|
152
|
+
type.join(' or ')
|
|
153
|
+
when nil
|
|
154
|
+
nil
|
|
155
|
+
else
|
|
156
|
+
type.to_s
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def describe_type(value)
|
|
161
|
+
case value
|
|
162
|
+
when NilClass
|
|
163
|
+
'null'
|
|
164
|
+
when String
|
|
165
|
+
'string'
|
|
166
|
+
when Integer
|
|
167
|
+
'integer'
|
|
168
|
+
when Float
|
|
169
|
+
'number'
|
|
170
|
+
when TrueClass, FalseClass
|
|
171
|
+
'boolean'
|
|
172
|
+
when Array
|
|
173
|
+
'array'
|
|
174
|
+
when Hash
|
|
175
|
+
'object'
|
|
176
|
+
else
|
|
177
|
+
value.class.name
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def source_suffix
|
|
182
|
+
source ? " (#{source})" : ''
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "site.json",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"site_id": { "type": "string" },
|
|
7
|
+
"type": { "type": "string" },
|
|
8
|
+
"supervisors": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"ip": { "type": "string" },
|
|
14
|
+
"port": { "type": ["integer", "string"] }
|
|
15
|
+
},
|
|
16
|
+
"required": ["ip", "port"],
|
|
17
|
+
"additionalProperties": true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"sxl": { "type": "string" },
|
|
21
|
+
"sxl_version": { "type": "string" },
|
|
22
|
+
"core_version": { "type": "string" },
|
|
23
|
+
"intervals": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"properties": {
|
|
26
|
+
"timer": { "type": "number" },
|
|
27
|
+
"watchdog": { "type": "number" },
|
|
28
|
+
"reconnect": { "type": "number" }
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": true
|
|
31
|
+
},
|
|
32
|
+
"timeouts": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"watchdog": { "type": "number" },
|
|
36
|
+
"acknowledgement": { "type": "number" }
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": true
|
|
39
|
+
},
|
|
40
|
+
"send_after_connect": { "type": "boolean" },
|
|
41
|
+
"components": { "type": "object" },
|
|
42
|
+
"security_codes": { "type": "object" },
|
|
43
|
+
"startup_sequence": { "type": "string" },
|
|
44
|
+
"signal_plans": { "type": "object" },
|
|
45
|
+
"inputs": { "type": "object" },
|
|
46
|
+
"live_output": { "type": ["string", "null"] }
|
|
47
|
+
},
|
|
48
|
+
"additionalProperties": true
|
|
49
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"port": { "type": ["integer", "string"] },
|
|
6
|
+
"ip": { "type": "string" },
|
|
7
|
+
"ips": {
|
|
8
|
+
"oneOf": [
|
|
9
|
+
{ "type": "string" },
|
|
10
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"site_id": { "type": "string" },
|
|
14
|
+
"max_sites": { "type": "integer" },
|
|
15
|
+
"guest": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"properties": {
|
|
18
|
+
"sxl": { "type": "string" },
|
|
19
|
+
"sxl_version": { "type": "string" },
|
|
20
|
+
"core_version": { "type": "string" },
|
|
21
|
+
"intervals": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"properties": {
|
|
24
|
+
"timer": { "type": "number" },
|
|
25
|
+
"watchdog": { "type": "number" }
|
|
26
|
+
},
|
|
27
|
+
"additionalProperties": true
|
|
28
|
+
},
|
|
29
|
+
"timeouts": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"properties": {
|
|
32
|
+
"watchdog": { "type": "number" },
|
|
33
|
+
"acknowledgement": { "type": "number" }
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": true
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": true
|
|
39
|
+
},
|
|
40
|
+
"sites": { "type": "object" }
|
|
41
|
+
},
|
|
42
|
+
"additionalProperties": true
|
|
43
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "traffic_controller_site.json",
|
|
4
|
+
"allOf": [
|
|
5
|
+
{ "$ref": "site.json" },
|
|
6
|
+
{
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"security_codes": { "type": "object" },
|
|
10
|
+
"startup_sequence": { "type": "string" },
|
|
11
|
+
"signal_plans": { "type": "object" },
|
|
12
|
+
"inputs": { "type": "object" },
|
|
13
|
+
"live_output": { "type": ["string", "null"] }
|
|
14
|
+
},
|
|
15
|
+
"additionalProperties": true
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
class Site < Node
|
|
3
|
+
# Configuration options for sites.
|
|
4
|
+
class Options < RSMP::Options
|
|
5
|
+
def defaults
|
|
6
|
+
{
|
|
7
|
+
'site_id' => 'RN+SI0001',
|
|
8
|
+
'supervisors' => [
|
|
9
|
+
{ 'ip' => '127.0.0.1', 'port' => 12_111 }
|
|
10
|
+
],
|
|
11
|
+
'sxl' => 'tlc',
|
|
12
|
+
'sxl_version' => RSMP::Schema.latest_version(:tlc),
|
|
13
|
+
'intervals' => {
|
|
14
|
+
'timer' => 0.1,
|
|
15
|
+
'watchdog' => 1,
|
|
16
|
+
'reconnect' => 0.1
|
|
17
|
+
},
|
|
18
|
+
'timeouts' => {
|
|
19
|
+
'watchdog' => 2,
|
|
20
|
+
'acknowledgement' => 2
|
|
21
|
+
},
|
|
22
|
+
'send_after_connect' => true,
|
|
23
|
+
'components' => {
|
|
24
|
+
'main' => {
|
|
25
|
+
'C1' => {}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def schema_file
|
|
32
|
+
'site.json'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def apply_defaults(options)
|
|
38
|
+
defaults = defaults()
|
|
39
|
+
defaults['components']['main'] = options['components']['main'] if options.dig('components', 'main')
|
|
40
|
+
defaults.deep_merge(options)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module RSMP
|
|
2
|
+
class Supervisor < Node
|
|
3
|
+
# Configuration options for supervisors.
|
|
4
|
+
class Options < RSMP::Options
|
|
5
|
+
def defaults
|
|
6
|
+
{
|
|
7
|
+
'port' => 12_111,
|
|
8
|
+
'ips' => 'all',
|
|
9
|
+
'guest' => {
|
|
10
|
+
'sxl' => 'tlc',
|
|
11
|
+
'intervals' => {
|
|
12
|
+
'timer' => 1,
|
|
13
|
+
'watchdog' => 1
|
|
14
|
+
},
|
|
15
|
+
'timeouts' => {
|
|
16
|
+
'watchdog' => 2,
|
|
17
|
+
'acknowledgement' => 2
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def schema_file
|
|
24
|
+
'supervisor.json'
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -4,6 +4,10 @@ module RSMP
|
|
|
4
4
|
class TrafficControllerSite < Site
|
|
5
5
|
attr_accessor :main, :signal_plans
|
|
6
6
|
|
|
7
|
+
def self.options_class
|
|
8
|
+
RSMP::TLC::TrafficControllerSite::Options
|
|
9
|
+
end
|
|
10
|
+
|
|
7
11
|
def initialize(options = {})
|
|
8
12
|
# setup options before calling super initializer,
|
|
9
13
|
# since build of components depend on options
|
data/lib/rsmp/version.rb
CHANGED
data/lib/rsmp.rb
CHANGED
|
@@ -53,6 +53,10 @@ require_relative 'rsmp/node/supervisor/modules/configuration'
|
|
|
53
53
|
require_relative 'rsmp/node/supervisor/modules/connection'
|
|
54
54
|
require_relative 'rsmp/node/supervisor/modules/sites'
|
|
55
55
|
require_relative 'rsmp/node/supervisor/supervisor'
|
|
56
|
+
require_relative 'rsmp/options/options'
|
|
57
|
+
require_relative 'rsmp/options/site_options'
|
|
58
|
+
require_relative 'rsmp/options/supervisor_options'
|
|
59
|
+
require_relative 'rsmp/options/traffic_controller_site_options'
|
|
56
60
|
require_relative 'rsmp/proxy/modules/state'
|
|
57
61
|
require_relative 'rsmp/proxy/modules/watchdogs'
|
|
58
62
|
require_relative 'rsmp/proxy/modules/acknowledgements'
|
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.40.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emil Tin
|
|
@@ -138,6 +138,7 @@ files:
|
|
|
138
138
|
- cucumber.yml
|
|
139
139
|
- documentation/classes_and_modules.md
|
|
140
140
|
- documentation/collecting_message.md
|
|
141
|
+
- documentation/configuration.md
|
|
141
142
|
- documentation/message_distribution.md
|
|
142
143
|
- documentation/tasks.md
|
|
143
144
|
- exe/rsmp
|
|
@@ -186,6 +187,13 @@ files:
|
|
|
186
187
|
- lib/rsmp/node/supervisor/modules/sites.rb
|
|
187
188
|
- lib/rsmp/node/supervisor/supervisor.rb
|
|
188
189
|
- lib/rsmp/node/task.rb
|
|
190
|
+
- lib/rsmp/options/options.rb
|
|
191
|
+
- lib/rsmp/options/schemas/site.json
|
|
192
|
+
- lib/rsmp/options/schemas/supervisor.json
|
|
193
|
+
- lib/rsmp/options/schemas/traffic_controller_site.json
|
|
194
|
+
- lib/rsmp/options/site_options.rb
|
|
195
|
+
- lib/rsmp/options/supervisor_options.rb
|
|
196
|
+
- lib/rsmp/options/traffic_controller_site_options.rb
|
|
189
197
|
- lib/rsmp/proxy/modules/acknowledgements.rb
|
|
190
198
|
- lib/rsmp/proxy/modules/receive.rb
|
|
191
199
|
- lib/rsmp/proxy/modules/send.rb
|