rsmp 0.5.0 → 0.5.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: 7290ac834b3609265b8e74ecc1d03a10c08b7e0f81411516ffa7dca1c3101bfb
4
- data.tar.gz: 8a81e821c60fd148da62222724cd038eb85a69251e0e52603403edcb5a1256bf
3
+ metadata.gz: 7d5f4cf2cac16a579cca8eb8e81d84ff60cd94e294bba6caf3c3d450fc71e202
4
+ data.tar.gz: c99aade3e55837ee0502e0b3b3e8120ad5f488fcc78b5cdc7d412534012fa72d
5
5
  SHA512:
6
- metadata.gz: f2989f8d80113ebfdbde28c669d5255787b353949e3dc75c704ccfae54f2e579424426b1fa1144a616f087238c0f76350bdf009665b25514eacc115ed1ef1247
7
- data.tar.gz: fc674e02fed369f00c56c3152494dee25d7da66733971345550c8846df191b732d6cc3a60df7502ab7168b7ad2b66ba01d4195eb654e2d45c04b987ea932b9be
6
+ metadata.gz: 37ce6e272ccb1265865000d35fb5fb473f426c725786a89b8f7cf52871f40dc82a5f90fb860c7aa5a9662fc1c2554cef31a68e15583d949e19c6732ae4b47289
7
+ data.tar.gz: 738d271c31fe5d968c9a24e983ce66758891b46cc3c83bcdce374c20603dd54b68ce47a0d0686b3967b4ffcc45c4830c14535464f8094cdab9d483687d3355c0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.5.0)
4
+ rsmp (0.5.4)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.1)
7
7
  colorize (~> 0.8.1)
@@ -61,9 +61,18 @@ module RSMP
61
61
  str = "#{@title.capitalize} collection"
62
62
  str << " in response to #{options[:m_id]}" if options[:m_id]
63
63
  str << " didn't complete within #{@options[:timeout]}s"
64
+ reached = progress
65
+ str << ", reached #{progress[:reached]}/#{progress[:need]}"
64
66
  raise RSMP::TimeoutError.new str
65
67
  end
66
68
 
69
+ # Return progress as collected vs. number requested
70
+ def progress
71
+ need = @options[:num]
72
+ reached = @messages.size
73
+ { need: need, got: reached }
74
+ end
75
+
67
76
  # Get the collected message.
68
77
  def message
69
78
  @messages.first
@@ -70,6 +70,13 @@ module RSMP
70
70
  @queries.map { |query| query.message }.uniq
71
71
  end
72
72
 
73
+ # Return progress as completes queries vs. total number of queries
74
+ def progress
75
+ need = @queries.size
76
+ reached = @queries.count { |query| query.done? }
77
+ { need: need, reached: reached }
78
+ end
79
+
73
80
  # Are there queries left to match?
74
81
  def done?
75
82
  @queries.all? { |query| query.done? }
@@ -16,12 +16,17 @@ module RSMP
16
16
  @notify_queue = []
17
17
  end
18
18
 
19
+ def clear_deferred_notify &block
20
+ @notify_queue = []
21
+ end
22
+
19
23
  def deferred_notify &block
20
24
  was, @defer_notify = @defer_notify, true
21
25
  yield
22
26
  dequeue_notify
23
27
  ensure
24
28
  @defer_notify = was
29
+ @notify_queue = []
25
30
  end
26
31
 
27
32
  def dequeue_notify
@@ -1,4 +1,9 @@
1
1
  module RSMP
2
+
3
+ # Class that represents an RMSP component.
4
+ # Currently this class is used by both SiteProxy and SupervisorProxy, and can
5
+ # therefore represent either a local or remote (proxy) component.
6
+
2
7
  class Component
3
8
  include Inspect
4
9
 
@@ -19,6 +24,7 @@ module RSMP
19
24
  @grouped = grouped
20
25
  @alarms = {}
21
26
  @statuses = {}
27
+ @subscribes = {}
22
28
  clear_aggregated_status
23
29
  end
24
30
 
@@ -83,5 +89,74 @@ module RSMP
83
89
  @alarms[code] = message
84
90
  end
85
91
  end
92
+
93
+ # Handle an incoming status respone, by storing the values
94
+ def handle_status_response message
95
+ store_status message, check_repeated: false
96
+ end
97
+
98
+ # Handle an incoming status update, by storing the values
99
+ def handle_status_update message
100
+ store_status message, check_repeated: true
101
+ end
102
+
103
+ # Our proxy subscribed to status updates
104
+ # Store update rates, so we can check for repeated alarm if we asked for updates only
105
+ # when there's a change, not on a regular interval.
106
+ # After subscribing, an update status us send regarless of whether values changes,
107
+ # and we store that.
108
+ def handle_status_subscribe status_list
109
+ status_list.each do |item|
110
+ sCI, n, uRt = item['sCI'], item['n'], item['uRt']
111
+
112
+ # record the update rate, so we can check for repeated status values if rate is zero
113
+ @subscribes[sCI] ||= {}
114
+ @subscribes[sCI][n] = {'uRt'=>uRt}
115
+
116
+ # record that we expect an upeate, even though the value might not change
117
+ @statuses[sCI] ||= {}
118
+ @statuses[sCI][n] ||= {}
119
+ @statuses[sCI][n][:initial] = true
120
+ end
121
+ #pp @subscribes
122
+ end
123
+
124
+ # Our proxy unsubscribed to status updates.
125
+ # Update our list of update rates.
126
+ def handle_status_unsubscribe status_list
127
+ status_list.each do |item|
128
+ sCI, n = item['sCI'], item['n']
129
+ if @subscribes[sCI]
130
+ @subscribes[sCI].delete n
131
+ end
132
+ if @subscribes[sCI].empty?
133
+ @subscribes.delete sCI
134
+ end
135
+
136
+ # remove any mark that would allow the next update to be a repeat
137
+ item = @statuses.dig sCI, n
138
+ item.delete(:initial) if item
139
+ end
140
+ end
141
+
142
+ # Store the latest status update values, optionally
143
+ # checking that we're not receiving unchanged values if we're subscribed
144
+ # wit updates only on change
145
+ def store_status message, check_repeated:
146
+ message.attribute('sS').each do |item|
147
+ sCI, n, s, q = item['sCI'], item['n'], item['s'], item['q']
148
+ uRt = @subscribes.dig(sCI,n,'uRt')
149
+ new_values = {'s'=>s,'q'=>q}
150
+ old_values = @statuses.dig(sCI,n)
151
+ if check_repeated && uRt.to_i == 0
152
+ if new_values == old_values
153
+ raise RSMP::RepeatedStatusError.new "no change for #{sCI} '#{n}'"
154
+ end
155
+ end
156
+ @statuses[sCI] ||= {}
157
+ @statuses[sCI][n] = new_values
158
+ end
159
+ end
160
+
86
161
  end
87
162
  end
data/lib/rsmp/error.rb CHANGED
@@ -58,4 +58,7 @@ module RSMP
58
58
 
59
59
  class RepeatedAlarmError < Error
60
60
  end
61
+
62
+ class RepeatedStatusError < Error
63
+ end
61
64
  end
data/lib/rsmp/node.rb CHANGED
@@ -38,6 +38,10 @@ module RSMP
38
38
  def do_deferred item
39
39
  end
40
40
 
41
+ def clear_deferred
42
+ @deferred.clear
43
+ end
44
+
41
45
  def do_start task
42
46
  task.annotate self.class.to_s
43
47
  @task = task
data/lib/rsmp/proxy.rb CHANGED
@@ -350,7 +350,7 @@ module RSMP
350
350
  rescue SchemaError, RSMP::Schemer::Error => e
351
351
  str = "Received invalid #{message.type}, schema errors: #{e.message}"
352
352
  log str, message: message, level: :warning
353
- notify_error e.exception("#{str} #{message.json}"), message: message
353
+ notify_error e.exception(str), message: message
354
354
  dont_acknowledge message, str
355
355
  message
356
356
  rescue InvalidMessage => e
@@ -360,10 +360,12 @@ module RSMP
360
360
  message
361
361
  rescue FatalError => e
362
362
  str = "Rejected #{message.type},"
363
- notify_error e.exception("#{str} #{message.json}"), message: message
363
+ notify_error e.exception(str), message: message
364
364
  dont_acknowledge message, str, "#{e.message}"
365
365
  stop
366
366
  message
367
+ ensure
368
+ node.clear_deferred
367
369
  end
368
370
 
369
371
  def process_message message
@@ -68,6 +68,10 @@ module RSMP
68
68
  else
69
69
  super message
70
70
  end
71
+ rescue RSMP::RepeatedAlarmError, RSMP::RepeatedStatusError => e
72
+ str = "Rejected #{message.type} message,"
73
+ dont_acknowledge message, str, "#{e}"
74
+ notify_error e.exception("#{str}#{e.message} #{message.json}")
71
75
  end
72
76
 
73
77
  def process_command_response message
@@ -145,10 +149,6 @@ module RSMP
145
149
  asp = message.attribute("aSp")
146
150
  log "Received #{message.type}, #{alarm_code} #{asp} [#{status}]", message: message, level: :log
147
151
  acknowledge message
148
- rescue RSMP::RepeatedAlarmError => e
149
- str = "Rejected #{message.type} message, "
150
- dont_acknowledge message, str, "#{e}"
151
- notify_error e.exception("#{str}#{e.message} #{message.json}")
152
152
  end
153
153
 
154
154
  def version_acknowledged
@@ -187,6 +187,8 @@ module RSMP
187
187
  end
188
188
 
189
189
  def process_status_response message
190
+ component = find_component message.attribute("cId")
191
+ component.handle_status_response message
190
192
  log "Received #{message.type}", message: message, level: :log
191
193
  acknowledge message
192
194
  end
@@ -198,7 +200,7 @@ module RSMP
198
200
  message
199
201
  end
200
202
 
201
- def subscribe_to_status component, status_list, options={}
203
+ def subscribe_to_status component_id, status_list, options={}
202
204
  validate_ready 'subscribe to status'
203
205
  m_id = options[:m_id] || RSMP::Message.make_m_id
204
206
 
@@ -206,10 +208,13 @@ module RSMP
206
208
  # but must to remove from the subscribe message
207
209
  subscribe_list = status_list.map { |item| item.slice('sCI','n','uRt') }
208
210
 
211
+ component = find_component component_id
212
+ component.handle_status_subscribe subscribe_list
213
+
209
214
  message = RSMP::StatusSubscribe.new({
210
215
  "ntsOId" => '',
211
216
  "xNId" => '',
212
- "cId" => component,
217
+ "cId" => component_id,
213
218
  "sS" => subscribe_list,
214
219
  'mId' => m_id
215
220
  })
@@ -218,12 +223,15 @@ module RSMP
218
223
  end
219
224
  end
220
225
 
221
- def unsubscribe_to_status component, status_list, options={}
226
+ def unsubscribe_to_status component_id, status_list, options={}
227
+ component = find_component component_id
228
+ component.handle_status_subscribe status_list
229
+
222
230
  validate_ready 'unsubscribe to status'
223
231
  message = RSMP::StatusUnsubscribe.new({
224
232
  "ntsOId" => '',
225
233
  "xNId" => '',
226
- "cId" => component,
234
+ "cId" => component_id,
227
235
  "sS" => status_list
228
236
  })
229
237
  send_message message, validate: options[:validate]
@@ -231,6 +239,8 @@ module RSMP
231
239
  end
232
240
 
233
241
  def process_status_update message
242
+ component = find_component message.attribute("cId")
243
+ component.handle_status_update message
234
244
  log "Received #{message.type}", message: message, level: :log
235
245
  acknowledge message
236
246
  end
@@ -172,7 +172,11 @@ module RSMP
172
172
  id = peek_version_message protocol
173
173
  proxy = find_site id
174
174
  if proxy
175
- proxy.revive settings
175
+ if proxy.connected?
176
+ raise ConnectionError.new("Site #{id} alredy connected from port #{proxy.port}")
177
+ else
178
+ proxy.revive settings
179
+ end
176
180
  else
177
181
  check_max_sites
178
182
  proxy = build_proxy settings.merge(site_id:id) # keep the id learned by peeking above
@@ -225,7 +225,6 @@ module RSMP
225
225
  def process_status_subcribe message
226
226
  log "Received #{message.type}", message: message, level: :log
227
227
 
228
-
229
228
  # @status_subscriptions is organized by component/code/name, for example:
230
229
  #
231
230
  # {"AA+BBCCC=DDDEE002"=>{"S001"=>["number"]}}
@@ -234,21 +233,14 @@ module RSMP
234
233
  # for each component, containing all the requested statuses
235
234
 
236
235
  update_list = {}
237
-
238
236
  component = message.attributes["cId"]
239
-
240
237
  @status_subscriptions[component] ||= {}
241
238
  update_list[component] ||= {}
242
-
243
- subs = @status_subscriptions[component]
244
239
  now = Time.now # internal timestamp
245
240
 
246
241
  message.attributes["sS"].each do |arg|
247
242
  sCI = arg["sCI"]
248
243
  subcription = {interval: arg["uRt"].to_i, last_sent_at: now}
249
- subs[sCI] ||= {}
250
- subs[sCI][arg["n"]] = subcription
251
-
252
244
  update_list[component][sCI] ||= []
253
245
  update_list[component][sCI] << arg["n"]
254
246
  end
@@ -287,11 +279,15 @@ module RSMP
287
279
  end
288
280
  end
289
281
 
290
- def store_last_sent_status component, code, name, value
282
+ def store_last_sent_status message
283
+ component_id = message.attribute('cId')
291
284
  @last_status_sent ||= {}
292
- @last_status_sent[component] ||= {}
293
- @last_status_sent[component][code] ||= {}
294
- @last_status_sent[component][code][name] = value
285
+ @last_status_sent[component_id] ||= {}
286
+ message.attribute('sS').each do |item|
287
+ sCI, n, s = item['sCI'], item['n'], item['s']
288
+ @last_status_sent[component_id][sCI] ||= {}
289
+ @last_status_sent[component_id][sCI][n] = s
290
+ end
295
291
  end
296
292
 
297
293
  def status_update_timer now
@@ -312,7 +308,6 @@ module RSMP
312
308
  last_sent = fetch_last_sent_status component, code, name
313
309
  if current != last_sent
314
310
  should_send = true
315
- store_last_sent_status component, code, name, current
316
311
  end
317
312
  else
318
313
  # send at regular intervals
@@ -356,6 +351,7 @@ module RSMP
356
351
  "sS"=>sS
357
352
  })
358
353
  send_message update
354
+ store_last_sent_status update
359
355
  end
360
356
  end
361
357
 
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.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.5.0
4
+ version: 0.5.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-11-05 00:00:00.000000000 Z
11
+ date: 2021-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -258,7 +258,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
258
258
  - !ruby/object:Gem::Version
259
259
  version: '0'
260
260
  requirements: []
261
- rubygems_version: 3.2.15
261
+ rubygems_version: 3.2.26
262
262
  signing_key:
263
263
  specification_version: 4
264
264
  summary: RoadSide Message Protocol (RSMP) library.