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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95c0244d87cf4f53324931c8a898915c54a520ddf0112c4753ef41b03099122c
4
- data.tar.gz: d09df39a9b9042fc1c9a118986138fff5436e74d743146776b69d22a300826e5
3
+ metadata.gz: 7db642eae802d3f31456b221ab6297516eb081375f1778cf06cd25b597ae3d07
4
+ data.tar.gz: e64b67b905975ca8862dd3610a2c3553c8527378db05fc0242dbd56996f850a5
5
5
  SHA512:
6
- metadata.gz: 96bfd44c55d893634aebbed5eb0a8d830190b0fc7abdeb644f2fe9da1fecae60b1e1a723806d93cdfb124e33e3a89e7e0ca28e2ba14111b43346741e9dfd4086
7
- data.tar.gz: 32dc5721a03a4d2a5161954e5c0a2b9273c3b245dcb1769902b13001582cc34ba13bc8e301954bad68b3d336e7be8bbf565aede3edcfc8e7e3f504504dcf44be
6
+ metadata.gz: 9dbceb076fdfd4aee419daceb587c7802eaf664f3bde3bcd7bb944e9e1408e78b9da0987ca7b56ab0e29d65cc120822f2e2c501bff3de2f22676141194394af3
7
+ data.tar.gz: 25cdeff92403011140b4164541ad94a785ad8b62449563a49f1ae1ccdc99f8489e940a310d140ddda3db34f66bcded08382d5e3bfdc5cf5307cb7529c11f94d7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.39.0)
4
+ rsmp (0.40.0)
5
5
  async (~> 2.32)
6
6
  colorize (~> 1.1)
7
7
  io-endpoint (~> 0.15)
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
- if File.exist? options[:config]
67
- settings = YAML.load_file options[:config]
68
- log_settings = settings.delete('log') || log_settings
69
- else
70
- puts "Error: Config #{options[:config]} not found"
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
- if File.exist? options[:config]
139
- settings = YAML.load_file options[:config]
140
- log_settings = settings.delete('log') || log_settings
141
- else
142
- puts "Error: Config #{options[:config]} not found"
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
 
@@ -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
- defaults = default_site_settings
54
- defaults['components']['main'] = options[:site_settings]['components']['main'] if options.dig(
55
- :site_settings, 'components', 'main'
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
- 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']
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
@@ -0,0 +1,12 @@
1
+ module RSMP
2
+ module TLC
3
+ class TrafficControllerSite < Site
4
+ # Configuration options for traffic controller sites.
5
+ class Options < RSMP::Site::Options
6
+ def schema_file
7
+ 'traffic_controller_site.json'
8
+ end
9
+ end
10
+ end
11
+ end
12
+ 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
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = '0.39.0'.freeze
2
+ VERSION = '0.40.0'.freeze
3
3
  end
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.39.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