rsmp 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/devcontainer.json +22 -0
  3. data/.github/workflows/rubocop.yaml +17 -0
  4. data/.gitignore +5 -6
  5. data/.rubocop.yml +80 -0
  6. data/Gemfile +13 -1
  7. data/Gemfile.lock +34 -1
  8. data/Rakefile +3 -3
  9. data/lib/rsmp/cli.rb +147 -124
  10. data/lib/rsmp/collect/ack_collector.rb +8 -7
  11. data/lib/rsmp/collect/aggregated_status_collector.rb +4 -4
  12. data/lib/rsmp/collect/alarm_collector.rb +31 -23
  13. data/lib/rsmp/collect/alarm_matcher.rb +3 -3
  14. data/lib/rsmp/collect/collector/logging.rb +17 -0
  15. data/lib/rsmp/collect/collector/reporting.rb +44 -0
  16. data/lib/rsmp/collect/collector/status.rb +34 -0
  17. data/lib/rsmp/collect/collector.rb +69 -150
  18. data/lib/rsmp/collect/command_matcher.rb +19 -6
  19. data/lib/rsmp/collect/command_response_collector.rb +7 -7
  20. data/lib/rsmp/collect/distributor.rb +14 -11
  21. data/lib/rsmp/collect/filter.rb +31 -15
  22. data/lib/rsmp/collect/matcher.rb +7 -11
  23. data/lib/rsmp/collect/queue.rb +4 -4
  24. data/lib/rsmp/collect/receiver.rb +10 -12
  25. data/lib/rsmp/collect/state_collector.rb +116 -77
  26. data/lib/rsmp/collect/status_collector.rb +6 -6
  27. data/lib/rsmp/collect/status_matcher.rb +17 -7
  28. data/lib/rsmp/{alarm_state.rb → component/alarm_state.rb} +76 -37
  29. data/lib/rsmp/{component.rb → component/component.rb} +15 -15
  30. data/lib/rsmp/component/component_base.rb +89 -0
  31. data/lib/rsmp/component/component_proxy.rb +75 -0
  32. data/lib/rsmp/component/components.rb +63 -0
  33. data/lib/rsmp/convert/export/json_schema.rb +116 -110
  34. data/lib/rsmp/convert/import/yaml.rb +21 -18
  35. data/lib/rsmp/{rsmp.rb → helpers/clock.rb} +5 -6
  36. data/lib/rsmp/{deep_merge.rb → helpers/deep_merge.rb} +2 -1
  37. data/lib/rsmp/helpers/error.rb +71 -0
  38. data/lib/rsmp/{inspect.rb → helpers/inspect.rb} +6 -10
  39. data/lib/rsmp/log/archive.rb +98 -0
  40. data/lib/rsmp/log/colorization.rb +41 -0
  41. data/lib/rsmp/log/filtering.rb +54 -0
  42. data/lib/rsmp/log/logger.rb +206 -0
  43. data/lib/rsmp/{logging.rb → log/logging.rb} +5 -7
  44. data/lib/rsmp/message.rb +159 -148
  45. data/lib/rsmp/{node.rb → node/node.rb} +19 -17
  46. data/lib/rsmp/{protocol.rb → node/protocol.rb} +5 -3
  47. data/lib/rsmp/node/site/site.rb +195 -0
  48. data/lib/rsmp/node/supervisor/modules/configuration.rb +59 -0
  49. data/lib/rsmp/node/supervisor/modules/connection.rb +140 -0
  50. data/lib/rsmp/node/supervisor/modules/sites.rb +64 -0
  51. data/lib/rsmp/node/supervisor/supervisor.rb +72 -0
  52. data/lib/rsmp/{task.rb → node/task.rb} +12 -14
  53. data/lib/rsmp/proxy/modules/acknowledgements.rb +144 -0
  54. data/lib/rsmp/proxy/modules/receive.rb +119 -0
  55. data/lib/rsmp/proxy/modules/send.rb +76 -0
  56. data/lib/rsmp/proxy/modules/state.rb +25 -0
  57. data/lib/rsmp/proxy/modules/tasks.rb +105 -0
  58. data/lib/rsmp/proxy/modules/versions.rb +69 -0
  59. data/lib/rsmp/proxy/modules/watchdogs.rb +66 -0
  60. data/lib/rsmp/proxy/proxy.rb +199 -0
  61. data/lib/rsmp/proxy/site/modules/aggregated_status.rb +52 -0
  62. data/lib/rsmp/proxy/site/modules/alarms.rb +27 -0
  63. data/lib/rsmp/proxy/site/modules/commands.rb +31 -0
  64. data/lib/rsmp/proxy/site/modules/status.rb +110 -0
  65. data/lib/rsmp/proxy/site/site_proxy.rb +205 -0
  66. data/lib/rsmp/proxy/supervisor/modules/aggregated_status.rb +47 -0
  67. data/lib/rsmp/proxy/supervisor/modules/alarms.rb +73 -0
  68. data/lib/rsmp/proxy/supervisor/modules/commands.rb +53 -0
  69. data/lib/rsmp/proxy/supervisor/modules/status.rb +204 -0
  70. data/lib/rsmp/proxy/supervisor/supervisor_proxy.rb +178 -0
  71. data/lib/rsmp/tlc/detector_logic.rb +18 -34
  72. data/lib/rsmp/tlc/input_states.rb +126 -0
  73. data/lib/rsmp/tlc/modules/detector_logics.rb +50 -0
  74. data/lib/rsmp/tlc/modules/display.rb +78 -0
  75. data/lib/rsmp/tlc/modules/helpers.rb +41 -0
  76. data/lib/rsmp/tlc/modules/inputs.rb +173 -0
  77. data/lib/rsmp/tlc/modules/modes.rb +253 -0
  78. data/lib/rsmp/tlc/modules/outputs.rb +30 -0
  79. data/lib/rsmp/tlc/modules/plans.rb +218 -0
  80. data/lib/rsmp/tlc/modules/signal_groups.rb +109 -0
  81. data/lib/rsmp/tlc/modules/startup_sequence.rb +22 -0
  82. data/lib/rsmp/tlc/modules/system.rb +140 -0
  83. data/lib/rsmp/tlc/modules/traffic_data.rb +49 -0
  84. data/lib/rsmp/tlc/signal_group.rb +37 -41
  85. data/lib/rsmp/tlc/signal_plan.rb +14 -11
  86. data/lib/rsmp/tlc/signal_priority.rb +39 -35
  87. data/lib/rsmp/tlc/startup_sequence.rb +59 -0
  88. data/lib/rsmp/tlc/traffic_controller.rb +38 -1010
  89. data/lib/rsmp/tlc/traffic_controller_site.rb +58 -57
  90. data/lib/rsmp/version.rb +1 -1
  91. data/lib/rsmp.rb +82 -48
  92. data/rsmp.gemspec +24 -31
  93. metadata +79 -139
  94. data/lib/rsmp/archive.rb +0 -76
  95. data/lib/rsmp/collect/message_matchers.rb +0 -0
  96. data/lib/rsmp/component_base.rb +0 -87
  97. data/lib/rsmp/component_proxy.rb +0 -57
  98. data/lib/rsmp/components.rb +0 -65
  99. data/lib/rsmp/error.rb +0 -71
  100. data/lib/rsmp/logger.rb +0 -216
  101. data/lib/rsmp/proxy.rb +0 -693
  102. data/lib/rsmp/site.rb +0 -188
  103. data/lib/rsmp/site_proxy.rb +0 -389
  104. data/lib/rsmp/supervisor.rb +0 -302
  105. data/lib/rsmp/supervisor_proxy.rb +0 -510
  106. data/lib/rsmp/tlc/inputs.rb +0 -134
@@ -0,0 +1,54 @@
1
+ module RSMP
2
+ class Logger
3
+ # Handles filtering logic for log output
4
+ module Filtering
5
+ def level_enabled?(item)
6
+ return false if @settings['info'] == false && item[:level] == :info
7
+ return false if @settings['debug'] != true && item[:level] == :debug
8
+ return false if @settings['statistics'] != true && item[:level] == :statistics
9
+ return false if @settings['test'] != true && item[:level] == :test
10
+
11
+ true
12
+ end
13
+
14
+ def message_ignored?(item)
15
+ return false unless item[:message]
16
+
17
+ type = item[:message].type
18
+ ack = %w[MessageAck MessageNotAck].include?(type)
19
+ return true unless ignorable?(type, ack, item)
20
+ return true unless acknowledgement_enabled?(ack, item)
21
+
22
+ false
23
+ end
24
+
25
+ def ignorable?(type, ack, item)
26
+ @ignorable.each_pair do |key, types|
27
+ ignore = [types].flatten
28
+ next unless @settings[key] == false
29
+ return false if ignore.include?(type)
30
+
31
+ return false if ack && item[:message].original && ignore.include?(item[:message].original.type)
32
+ end
33
+ true
34
+ end
35
+
36
+ def acknowledgement_enabled?(ack, item)
37
+ return true unless ack
38
+ return true if @settings['acknowledgements'] != false
39
+ return true if %i[not_acknowledged warning error].include?(item[:level])
40
+
41
+ false
42
+ end
43
+
44
+ def output?(item, force: false)
45
+ return false if muted?(item)
46
+ return false if @settings['active'] == false && force != true
47
+ return false unless level_enabled?(item)
48
+ return false if message_ignored?(item)
49
+
50
+ true
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,206 @@
1
+ module RSMP
2
+ class Logger
3
+ include Filtering
4
+ include Colorization
5
+
6
+ attr_accessor :settings
7
+
8
+ def default_output_settings
9
+ {
10
+ 'active' => true,
11
+ 'path' => nil,
12
+ 'stream' => nil,
13
+ 'color' => true,
14
+ 'debug' => false,
15
+ 'statistics' => false,
16
+ 'hide_ip_and_port' => false,
17
+ 'acknowledgements' => false,
18
+ 'watchdogs' => false,
19
+ 'alarms' => true,
20
+ 'json' => false,
21
+ 'tabs' => '-'
22
+ }
23
+ end
24
+
25
+ def default_field_settings
26
+ {
27
+ 'prefix' => false,
28
+ 'index' => false,
29
+ 'author' => false,
30
+ 'timestamp' => true,
31
+ 'ip' => false,
32
+ 'port' => false,
33
+ 'site_id' => true,
34
+ 'component' => true,
35
+ 'direction' => false,
36
+ 'level' => false,
37
+ 'id' => true,
38
+ 'text' => true
39
+ }
40
+ end
41
+
42
+ def default_logger_settings
43
+ default_output_settings.merge(default_field_settings)
44
+ end
45
+
46
+ def default_field_lengths
47
+ {
48
+ 'index' => 7,
49
+ 'author' => 13,
50
+ 'timestamp' => 24,
51
+ 'ip' => 22,
52
+ 'port' => 5,
53
+ 'site_id' => 19,
54
+ 'component' => 19,
55
+ 'direction' => 3,
56
+ 'level' => 7,
57
+ 'id' => 4
58
+ }
59
+ end
60
+
61
+ def ignorable_messages
62
+ {
63
+ 'versions' => ['Version'],
64
+ 'statuses' => %w[StatusRequest StatusSubscribe StatusUnsubscribe StatusResponse StatusUpdate],
65
+ 'commands' => %w[CommandRequest CommandResponse],
66
+ 'watchdogs' => 'Watchdog',
67
+ 'alarms' => ['Alarm'],
68
+ 'aggregated_status' => %w[AggregatedStatus AggregatedStatusRequest]
69
+ }
70
+ end
71
+
72
+ def apply_default_lengths(settings)
73
+ lengths = default_field_lengths
74
+ settings.to_h do |key, value|
75
+ if value == true && lengths[key]
76
+ [key, lengths[key]]
77
+ else
78
+ [key, value]
79
+ end
80
+ end
81
+ end
82
+
83
+ def initialize(settings = {})
84
+ @ignorable = ignorable_messages
85
+ @settings = settings ? default_logger_settings.merge(settings) : default_logger_settings
86
+ @settings = apply_default_lengths(@settings)
87
+ @muted = {}
88
+ setup_output_destination
89
+ end
90
+
91
+ def setup_output_destination
92
+ @stream = if @settings['stream']
93
+ @settings['stream']
94
+ elsif @settings['path']
95
+ File.open(@settings['path'], 'a') # appending
96
+ else
97
+ $stdout
98
+ end
99
+ end
100
+
101
+ def mute(ip, port)
102
+ @muted["#{ip}:#{port}"] = true
103
+ end
104
+
105
+ def unmute(ip, port)
106
+ @muted.delete "#{ip}:#{port}"
107
+ end
108
+
109
+ def unmute_all
110
+ @muted = {}
111
+ end
112
+
113
+ def muted?(item)
114
+ item[:ip] && item[:port] && @muted["#{item[:ip]}:#{item[:port]}"]
115
+ end
116
+
117
+ def level_enabled?(item)
118
+ return false if @settings['info'] == false && item[:level] == :info
119
+ return false if @settings['debug'] != true && item[:level] == :debug
120
+ return false if @settings['statistics'] != true && item[:level] == :statistics
121
+ return false if @settings['test'] != true && item[:level] == :test
122
+
123
+ true
124
+ end
125
+
126
+ def output(level, str)
127
+ return if str.empty? || /^\s+$/.match(str)
128
+
129
+ str = colorize level, str
130
+ @stream.puts str
131
+ @stream.flush
132
+ end
133
+
134
+ def log(item, force: false)
135
+ return unless output?(item, force: force)
136
+
137
+ output item[:level], build_output(item)
138
+ end
139
+
140
+ def self.shorten_message_id(m_id, length = 4)
141
+ if m_id
142
+ m_id[0..(length - 1)].ljust(length)
143
+ else
144
+ ' ' * length
145
+ end
146
+ end
147
+
148
+ def dump(archive, num: nil)
149
+ num ||= archive.items.size
150
+ log = archive.items.last(num).map do |item|
151
+ str = build_output item
152
+ colorize item[:level], str
153
+ end
154
+ log.join("\n")
155
+ end
156
+
157
+ def build_part(parts, item, key, &block)
158
+ skey = key.to_s
159
+ return unless @settings[skey]
160
+
161
+ part = item[key]
162
+ part = yield part if block
163
+ part = part.to_s
164
+ part = part.ljust @settings[skey] if @settings[skey].is_a?(Integer)
165
+
166
+ # replace the first char with a dash if string is all whitespace
167
+ part = @settings['tabs'].ljust(part.length) if @settings['tabs'] && part !~ /\S/
168
+ parts << part
169
+ end
170
+
171
+ def add_metadata_parts(parts, item)
172
+ build_part(parts, item, :prefix) { @settings['prefix'] if @settings['prefix'] != false }
173
+ build_part(parts, item, :index)
174
+ build_part(parts, item, :author)
175
+ build_part(parts, item, :timestamp) { |part| Clock.to_s part }
176
+ end
177
+
178
+ def add_connection_parts(parts, item)
179
+ build_part(parts, item, :ip)
180
+ build_part(parts, item, :port)
181
+ build_part(parts, item, :site_id)
182
+ build_part(parts, item, :component)
183
+ end
184
+
185
+ def add_message_parts(parts, item)
186
+ build_part(parts, item, :direction) { |part| { in: 'In', out: 'Out' }[part] }
187
+ build_part(parts, item, :level, &:capitalize)
188
+ build_part(parts, item, :id) { Logger.shorten_message_id(item[:message].m_id, 4) if item[:message] }
189
+ build_part(parts, item, :text)
190
+ build_part(parts, item, :json) { item[:message]&.json }
191
+ build_part(parts, item, :exception) { |e| [e.class, e.backtrace].flatten.join("\n") }
192
+ end
193
+
194
+ def add_output_parts(parts, item)
195
+ add_metadata_parts(parts, item)
196
+ add_connection_parts(parts, item)
197
+ add_message_parts(parts, item)
198
+ end
199
+
200
+ def build_output(item)
201
+ parts = []
202
+ add_output_parts(parts, item)
203
+ parts.join(' ').chomp(@settings['tabs'].to_s).rstrip
204
+ end
205
+ end
206
+ end
@@ -6,21 +6,19 @@ module RSMP
6
6
  module Logging
7
7
  attr_reader :archive, :logger
8
8
 
9
- def initialize_logging options
9
+ def initialize_logging(options)
10
10
  @archive = options[:archive] || RSMP::Archive.new
11
11
  @logger = options[:logger] || RSMP::Logger.new(options[:log_settings])
12
12
  end
13
13
 
14
- def author
15
- end
14
+ def author; end
16
15
 
17
- def log str, options={}
18
- default = { text:str, level: :log, author: author, ip: @ip, port: @port }
16
+ def log(str, options = {})
17
+ default = { text: str, level: :log, author: author, ip: @ip, port: @port }
19
18
  prepared = RSMP::Archive.prepare_item default.merge(options)
20
19
  @archive.add prepared
21
20
  @logger.log prepared
22
21
  prepared
23
22
  end
24
-
25
23
  end
26
- end
24
+ end