rsmp 0.5.0 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
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.