rsmp 0.3.0 → 0.3.4

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: 9a3b1b8a67bdc7a3c8887ea606d3539d934121d99597f1a77f697d8259daba97
4
- data.tar.gz: 03f420b48a4eff2f3b6978eed5053a838a87da4f507eb2ddb2f0c15cb0e3e7b4
3
+ metadata.gz: f529bfbfcdd5fc6b0854c294e2412c5e7da10e2595a6a20ab0f6c65b7eb28964
4
+ data.tar.gz: c8fb86566e623a27ec78784e3d0299f16d082edc87ad9438f2335a0c33657b39
5
5
  SHA512:
6
- metadata.gz: 9fef0b5ea4b2e5481d3be7992e76c7cddb1d20db49df06c86d9b90faa37b56d458fde9cba36e14ea085e96e67f61dbe67f1a82a49401d360cb48900c6138b27d
7
- data.tar.gz: a14a735fccf39e8584e3d9ab43a1fdb727c279f395c138d9c7c50f7a8d491265c0aeb3aa67ee071642195bd7a15e0339de4785b5230bbed624965ef3619a231e
6
+ metadata.gz: 58c5d44cb5d8a1f87b77d91823eaa76adfd437df955412ba42950e359d1b08b47acec78034f42524b72d474a6c7870e2e22f418973d634fc938650b13f95fc47
7
+ data.tar.gz: 6006f41562af7ce3419c50895040fc0682026fa3c5b0db113875645fdd1de5286e25b73edc22f1d547a1daac50059532e7c4061cc5e3789d3a92c18c5e502aca
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.3.0)
4
+ rsmp (0.3.3)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.1)
7
7
  colorize (~> 0.8.1)
@@ -13,6 +13,7 @@ module RSMP
13
13
  @condition = Async::Notification.new
14
14
  @title = options[:title] || [@options[:type]].flatten.join('/')
15
15
  @options[:timeout] ||= 1
16
+ @options[:num] ||= 1
16
17
  reset
17
18
  end
18
19
 
@@ -51,21 +52,21 @@ module RSMP
51
52
  raise RSMP::TimeoutError.new str
52
53
  end
53
54
 
55
+ # Get the collected messages.
56
+ # If one message was requested, return it as a plain object instead of array
54
57
  def result
55
- return @messages.first if @options[:num] == 1 # if one message was requested, return it instead of array
56
- @messages.first @options[:num] # return array, but ensure we never return more than requested
58
+ return @messages.first if @options[:num] == 1
59
+ @messages.first @options[:num]
57
60
  end
58
61
 
62
+ # Clear all query results
59
63
  def reset
60
64
  @messages = []
61
65
  @error = nil
62
66
  @done = false
63
67
  end
64
68
 
65
- # Check for MessageNotAck
66
- # If the original request identified by @m_id is rejected, set the result to an exception,
67
- # which will be returned by the async task and stored as the task result.
68
- # When the parent task call wait() on the task, the exception will be raised in the parent task.
69
+ # Check if we receive a NotAck related to initiating request, identified by @m_id.
69
70
  def check_not_ack message
70
71
  return unless @options[:m_id]
71
72
  if message.is_a?(MessageNotAck)
@@ -81,6 +82,7 @@ module RSMP
81
82
  # Handle message. and return true when we're done collecting
82
83
  def notify message
83
84
  raise ArgumentError unless message
85
+ raise RuntimeError.new("can't process message when already done") if @done
84
86
  check_not_ack(message)
85
87
  return true if @done
86
88
  check_match message
@@ -98,24 +100,31 @@ module RSMP
98
100
  end
99
101
  end
100
102
 
103
+ # Have we collected the required number of messages?
101
104
  def done?
102
105
  @options[:num] && @messages.size >= @options[:num]
103
106
  end
104
107
 
108
+ # Called when we're done collecting. Remove ourself as a listener,
109
+ # se we don't receive message notifications anymore
105
110
  def complete
106
111
  @done = true
107
112
  @proxy.remove_listener self
108
113
  @condition.signal
109
114
  end
110
115
 
116
+ # Store a message in the result array
111
117
  def keep message
112
118
  @messages << message
113
119
  end
114
120
 
121
+ # Remove a message from the result array
115
122
  def forget message
116
123
  @messages.delete message
117
124
  end
118
125
 
126
+ # Check a message against our match criteria
127
+ # Return true if there's a match
119
128
  def match? message
120
129
  raise ArgumentError unless message
121
130
  return if message.direction == :in && @ingoing == false
@@ -13,6 +13,7 @@ module RSMP
13
13
 
14
14
  def setup_components settings
15
15
  return unless settings
16
+ check_main_component settings
16
17
  settings.each_pair do |type,components_by_type|
17
18
  components_by_type.each_pair do |id,settings|
18
19
  @components[id] = build_component(id:id, type:type, settings:settings)
@@ -20,6 +21,15 @@ module RSMP
20
21
  end
21
22
  end
22
23
 
24
+ def check_main_component settings
25
+ unless settings['main'] && settings['main'].size >= 1
26
+ raise ConfigurationError.new("main component must be defined")
27
+ end
28
+ if settings['main'].size > 1
29
+ raise ConfigurationError.new("only one main component can be defined, found #{settings['main'].keys.join(', ')}")
30
+ end
31
+ end
32
+
23
33
  def add_component component
24
34
  @components[component.c_id] = component
25
35
  end
data/lib/rsmp/matcher.rb CHANGED
@@ -35,6 +35,7 @@ module RSMP
35
35
  #
36
36
  #
37
37
  class Matcher < Collector
38
+ attr_reader :queries
38
39
 
39
40
  # Initialize with a list a wanted statuses
40
41
  def initialize proxy, want, options={}
@@ -55,16 +56,27 @@ module RSMP
55
56
  @queries.map { |query,result| result[:message] }.uniq
56
57
  end
57
58
 
58
- # get items from results
59
+ # Get items from results
59
60
  def items
60
61
  @queries.map { |query,result| result[:item] }.uniq
61
62
  end
62
63
 
63
- # Queries left to match?
64
+ # Are there queries left to match?
64
65
  def done?
65
66
  @queries.values.all? { |result| result != nil }
66
67
  end
67
68
 
69
+ # Get a simplified hash of queries, with values set to either true or false,
70
+ # indicating which queries have been matched.
71
+ def status
72
+ @queries.transform_values{ |v| v != nil }
73
+ end
74
+
75
+ # Get a simply array of bools, showing which queries ahve been matched.
76
+ def summary
77
+ @queries.values.map { |v| v != nil }
78
+ end
79
+
68
80
  # Mark a query as matched, by linking it to the matched item and message
69
81
  def keep query, message, item
70
82
  @queries[query] = { message:message, item:item }
@@ -75,11 +87,12 @@ module RSMP
75
87
  @queries[query] = nil
76
88
  end
77
89
 
78
- # Check if a messages is wanted.
79
- # Returns true when we found all that we want.
90
+ # Check if a messages matches our criteria.
91
+ # We iterate through each of the status items or return values in the message
92
+ # Breaks as soon as where done matching all queries
80
93
  def check_match message
81
94
  return unless match?(message)
82
- @queries.keys.each do |query| # look through queries
95
+ @queries.keys.each do |query| # look through queries
83
96
  get_items(message).each do |item| # look through status items in message
84
97
  break if check_item_match message, query, item
85
98
  end
@@ -104,15 +117,16 @@ module RSMP
104
117
  def initialize proxy, want, options={}
105
118
  super proxy, want, options.merge(
106
119
  type: ['CommandResponse','MessageNotAck'],
107
- title:'command request'
120
+ title:'command response'
108
121
  )
109
122
  end
110
123
 
124
+ # Get items, in our case the return values
111
125
  def get_items message
112
126
  message.attributes['rvs']
113
127
  end
114
128
 
115
- # Match an item against a query
129
+ # Match a return value item against a query
116
130
  def match_item? query, item
117
131
  return nil if query['cCI'] && query['cCI'] != item['cCI']
118
132
  return nil if query['n'] && query['n'] != item['n']
@@ -131,11 +145,12 @@ module RSMP
131
145
  super proxy, want, options.merge
132
146
  end
133
147
 
148
+ # Get items, in our case status values
134
149
  def get_items message
135
150
  message.attributes['sS']
136
151
  end
137
152
 
138
- # Match an item against a query
153
+ # Match a status value against a query
139
154
  def match_item? query, item
140
155
  return nil if query['sCI'] && query['sCI'] != item['sCI']
141
156
  return nil if query['cO'] && query['cO'] != item['cO']
@@ -155,7 +170,7 @@ module RSMP
155
170
  def initialize proxy, want, options={}
156
171
  super proxy, want, options.merge(
157
172
  type: ['StatusResponse','MessageNotAck'],
158
- title: 'status request'
173
+ title: 'status response'
159
174
  )
160
175
  end
161
176
  end
@@ -165,7 +180,7 @@ module RSMP
165
180
  def initialize proxy, want, options={}
166
181
  super proxy, want, options.merge(
167
182
  type: ['StatusUpdate','MessageNotAck'],
168
- title:'status subscription'
183
+ title:'status update'
169
184
  )
170
185
  end
171
186
  end
@@ -173,11 +188,8 @@ module RSMP
173
188
  # Class for waiting for an aggregated status response
174
189
  class AggregatedStatusMatcher < Collector
175
190
  def initialize proxy, options={}
176
- super proxy, options.merge(
177
- num: 1,
178
- type: ['AggregatedStatus','MessageNotAck'],
179
- title: 'aggregated status request'
180
- )
191
+ required = { type: ['AggregatedStatus','MessageNotAck'], title: 'aggregated status' }
192
+ super proxy, options.merge(required)
181
193
  end
182
194
  end
183
195
  end
data/lib/rsmp/proxy.rb CHANGED
@@ -124,7 +124,11 @@ module RSMP
124
124
  message = process_packet json
125
125
  duration = Time.now - beginning
126
126
  ms = (duration*1000).round(4)
127
- per_second = (1.0 / duration).round
127
+ if duration > 0
128
+ per_second = (1.0 / duration).round
129
+ else
130
+ per_second = Float::INFINITY
131
+ end
128
132
  if message
129
133
  type = message.type
130
134
  m_id = Logger.shorten_message_id(message.m_id)
@@ -203,7 +207,6 @@ module RSMP
203
207
  def watchdog_send_timer now
204
208
  return unless @watchdog_started
205
209
  return if @site_settings['intervals']['watchdog'] == :never
206
-
207
210
  if @latest_watchdog_send_at == nil
208
211
  send_watchdog now
209
212
  else
@@ -299,10 +302,18 @@ module RSMP
299
302
  end
300
303
  end
301
304
 
305
+ def should_validate_ingoing_message? message
306
+ return false unless @site_settings
307
+ skip = @site_settings.dig('skip_validation')
308
+ return false unless skip
309
+ klass = message.class.name.split('::').last
310
+ !skip.include?(klass)
311
+ end
312
+
302
313
  def process_packet json
303
314
  attributes = Message.parse_attributes json
304
315
  message = Message.build attributes, json
305
- message.validate get_schemas
316
+ message.validate(get_schemas) if should_validate_ingoing_message?(message)
306
317
  notify message
307
318
  expect_version_message(message) unless @version_determined
308
319
  process_message message
data/lib/rsmp/site.rb CHANGED
@@ -41,10 +41,16 @@ module RSMP
41
41
  },
42
42
  'send_after_connect' => true,
43
43
  'components' => {
44
- 'C1' => {}
44
+ 'main' => {
45
+ 'C1' => {}
46
+ }
45
47
  }
46
48
  }
47
-
49
+ # only one main component can be defined, so replace the default if options define one
50
+ if options.dig(:site_settings,'components','main')
51
+ defaults['components']['main'] = options[:site_settings]['components']['main']
52
+ end
53
+
48
54
  @site_settings = defaults.deep_merge options[:site_settings]
49
55
  check_sxl_version
50
56
  setup_components @site_settings['components']
@@ -11,7 +11,7 @@ module RSMP
11
11
  initialize_components
12
12
  @supervisor = options[:supervisor]
13
13
  @settings = @supervisor.supervisor_settings.clone
14
- @site_id = nil
14
+ @site_id = options[:site_id]
15
15
  end
16
16
 
17
17
  def revive options
@@ -103,7 +103,7 @@ module RSMP
103
103
  })
104
104
  if options[:collect]
105
105
  task = @task.async do |task|
106
- wait_for_aggregated_status task, options[:collect].merge(m_id: m_id)
106
+ collect_aggregated_status task, options[:collect].merge(m_id: m_id)
107
107
  end
108
108
  send_message message, validate: options[:validate]
109
109
  return message, task.wait
@@ -369,7 +369,7 @@ module RSMP
369
369
  CommandResponseMatcher.new(self, command_list, options).collect task
370
370
  end
371
371
 
372
- def wait_for_aggregated_status task, options
372
+ def collect_aggregated_status task, options
373
373
  AggregatedStatusMatcher.new(self, options).collect task
374
374
  end
375
375
  end
@@ -175,7 +175,7 @@ module RSMP
175
175
  proxy.revive settings
176
176
  else
177
177
  check_max_sites
178
- proxy = build_proxy settings
178
+ proxy = build_proxy settings.merge(site_id:id) # keep the id learned by peeking above
179
179
  @proxies.push proxy
180
180
  end
181
181
  proxy.run # will run until the site disconnects
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsmp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Tin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-14 00:00:00.000000000 Z
11
+ date: 2021-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -255,7 +255,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
255
255
  - !ruby/object:Gem::Version
256
256
  version: '0'
257
257
  requirements: []
258
- rubygems_version: 3.2.26
258
+ rubygems_version: 3.2.15
259
259
  signing_key:
260
260
  specification_version: 4
261
261
  summary: RoadSide Message Protocol (RSMP) library.