rsmp 0.4.6 → 0.5.3

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: c975252bdf622f3e6bd545e2eca8f4fcf2c9c5a5f04acf159cd162882bf4f491
4
- data.tar.gz: ec26cc377c14611389a8f0c9b82cf2137a76523cca3ce445513bc7e2ea5466d6
3
+ metadata.gz: b6d24a7240bcac60427bcbbe4743142db412338e847c08e35803401092dd162b
4
+ data.tar.gz: 264711c071e36998292d2fad4ece08bb79938ec3a7fc997016c7ca46f7f14ad1
5
5
  SHA512:
6
- metadata.gz: 243e70433cafb8573fc9e4ffcd6a55ece6d369df6201041e6481f88810ffdf907830197854330a28c91cfc2075b767cf379590bd7f80214189a94d4a0b3c03e9
7
- data.tar.gz: ac86a77b8685491c0f08fb14bd4e15552eabf73d177b7f5415b809628bab2684a71e4df3aad451fc2822c808b44d036d4c4910998b369cb373f0a4b8b2294ece
6
+ metadata.gz: a5cd2cd0d6afacb699c5c2e1da799356e33b0bfaa207ff7496221039c83143c572b2d5088a225cf9bec92036f890ad54bc099511d2344961a26742f69dec332d
7
+ data.tar.gz: 47d1c8569e07a5603cb8622f19f042d9bf637da0c30e08e8dd706c1b2b61efbba9d2f74f4de91e93ea969f89048dbb890ca5cc1718870708c6811a4ee6c3bd52
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.4.6)
4
+ rsmp (0.5.3)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.1)
7
7
  colorize (~> 0.8.1)
@@ -19,6 +19,7 @@ log:
19
19
  text: true
20
20
  direction: true
21
21
  level: false
22
+ debug: true
22
23
  json: true
23
24
  acknowledgements: false
24
25
  watchdogs: false
data/config/tlc.yaml CHANGED
@@ -38,6 +38,7 @@ log:
38
38
  ip: false
39
39
  site_id: true
40
40
  level: false
41
+ debug: true
41
42
  text: true
42
43
  direction: true
43
44
  json: true
@@ -7,7 +7,12 @@ module RSMP
7
7
 
8
8
  def initialize proxy, options={}
9
9
  super proxy, options
10
- @options = options.clone
10
+ @options = {
11
+ cancel: {
12
+ schema_error: true,
13
+ disconnect: false,
14
+ }
15
+ }.deep_merge options
11
16
  @ingoing = options[:ingoing] == nil ? true : options[:ingoing]
12
17
  @outgoing = options[:outgoing] == nil ? false : options[:outgoing]
13
18
  @condition = Async::Notification.new
@@ -82,7 +87,7 @@ module RSMP
82
87
  if message.is_a?(MessageNotAck)
83
88
  if message.attribute('oMId') == @options[:m_id]
84
89
  m_id_short = RSMP::Message.shorten_m_id @options[:m_id], 8
85
- @error = RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected: #{message.attribute('rea')}")
90
+ @error = RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected with '#{message.attribute('rea')}'")
86
91
  complete
87
92
  end
88
93
  false
@@ -123,6 +128,43 @@ module RSMP
123
128
  @condition.signal
124
129
  end
125
130
 
131
+ # The proxy experienced some error.
132
+ # Check if this should cause us to cancel.
133
+ def notify_error error, options={}
134
+ case error
135
+ when RSMP::SchemaError
136
+ notify_schema_error error, options
137
+ when RSMP::ConnectionError
138
+ notify_disconnect error, options
139
+ end
140
+ end
141
+
142
+ # Cancel if we received e schema error for a message type we're collecting
143
+ def notify_schema_error error, options
144
+ return unless @options.dig(:cancel,:schema_error)
145
+ message = options[:message]
146
+ return unless message
147
+ klass = message.class.name.split('::').last
148
+ return unless [@options[:type]].flatten.include? klass
149
+ @proxy.log "Collect cancelled due to schema error in #{klass} #{message.m_id_short}", level: :debug
150
+ cancel error
151
+ end
152
+
153
+ # Cancel if we received e notificaiton about a disconnect
154
+ def notify_disconnect error, options
155
+ return unless @options.dig(:cancel,:disconnect)
156
+ @proxy.log "Collect cancelled due to a connection error: #{error.to_s}", level: :debug
157
+ cancel error
158
+ end
159
+
160
+ # Abort collection
161
+ def cancel error
162
+ @error = error if error
163
+ @done = false
164
+ @proxy.remove_listener self
165
+ @condition.signal
166
+ end
167
+
126
168
  # Store a message in the result array
127
169
  def keep message
128
170
  @messages << message
@@ -12,6 +12,9 @@ module RSMP
12
12
  def notify message
13
13
  end
14
14
 
15
+ def notify_error error, options={}
16
+ end
17
+
15
18
  def listen &block
16
19
  @proxy.add_listener self
17
20
  yield
@@ -102,6 +102,5 @@ module RSMP
102
102
  end
103
103
  @proxy.log "#{@title.capitalize} collect reached #{summary}", level: :debug
104
104
  end
105
-
106
105
  end
107
106
  end
@@ -12,6 +12,26 @@ module RSMP
12
12
 
13
13
  def initialize_distributor
14
14
  @listeners = []
15
+ @defer_notify = false
16
+ @notify_queue = []
17
+ end
18
+
19
+ def clear_deferred_notify &block
20
+ @notify_queue = []
21
+ end
22
+
23
+ def deferred_notify &block
24
+ was, @defer_notify = @defer_notify, true
25
+ yield
26
+ dequeue_notify
27
+ ensure
28
+ @defer_notify = was
29
+ end
30
+
31
+ def dequeue_notify
32
+ @notify_queue.each { |message| notify_without_defer message }
33
+ ensure
34
+ @notify_queue = []
15
35
  end
16
36
 
17
37
  def add_listener listener
@@ -25,7 +45,20 @@ module RSMP
25
45
  end
26
46
 
27
47
  def notify message
48
+ raise ArgumentError unless message
49
+ if @defer_notify
50
+ @notify_queue << message
51
+ else
52
+ notify_without_defer message
53
+ end
54
+ end
55
+
56
+ def notify_without_defer message
28
57
  @listeners.each { |listener| listener.notify message }
29
58
  end
59
+
60
+ def distribute_error error, options={}
61
+ @listeners.each { |listener| listener.notify_error error, options }
62
+ end
30
63
  end
31
64
  end
@@ -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
@@ -32,6 +32,9 @@ module RSMP
32
32
  class FatalError < Error
33
33
  end
34
34
 
35
+ class HandshakeError < FatalError
36
+ end
37
+
35
38
  class NotReady < Error
36
39
  end
37
40
 
@@ -55,4 +58,7 @@ module RSMP
55
58
 
56
59
  class RepeatedAlarmError < Error
57
60
  end
61
+
62
+ class RepeatedStatusError < Error
63
+ end
58
64
  end
data/lib/rsmp/logger.rb CHANGED
@@ -5,6 +5,7 @@ module RSMP
5
5
 
6
6
  def initialize settings={}
7
7
  defaults = {
8
+ 'prefix'=>nil,
8
9
  'active'=>false,
9
10
  'path'=>nil,
10
11
  'stream'=>nil,
@@ -20,7 +21,8 @@ module RSMP
20
21
  'json'=>false,
21
22
  'debug'=>false,
22
23
  'statistics'=>false,
23
- 'hide_ip_and_port' => false
24
+ 'hide_ip_and_port' => false,
25
+ 'acknowledgements' => false
24
26
  }
25
27
  if settings
26
28
  @settings = defaults.merge settings
@@ -139,6 +141,7 @@ module RSMP
139
141
 
140
142
  def build_output item
141
143
  parts = []
144
+ parts << "#{@settings['prefix']} " if @settings['prefix']
142
145
  parts << item[:index].to_s.ljust(7) if @settings["index"] == true
143
146
  parts << item[:author].to_s.ljust(13) if @settings["author"] == true
144
147
  parts << Clock.to_s(item[:timestamp]).ljust(24) unless @settings["timestamp"] == false
data/lib/rsmp/message.rb CHANGED
@@ -142,7 +142,7 @@ module RSMP
142
142
  def validate schemas
143
143
  errors = RSMP::Schemer.validate attributes, schemas
144
144
  if errors
145
- error_string = errors.compact.join(', ').strip
145
+ error_string = errors.map {|item| item.reject {|e| e=='' } }.compact.join(', ').strip
146
146
  raise SchemaError.new error_string
147
147
  end
148
148
  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
@@ -86,6 +86,7 @@ module RSMP
86
86
  return if @state == :stopped
87
87
  set_state :stopping
88
88
  stop_tasks
89
+ notify_error ConnectionError.new("Connection was closed")
89
90
  ensure
90
91
  close_socket
91
92
  clear
@@ -237,6 +238,7 @@ module RSMP
237
238
  if now > latest
238
239
  log "No acknowledgements for #{message.type} #{message.m_id_short} within #{timeout} seconds", level: :error
239
240
  stop
241
+ notify_error MissingAcknowledgment.new('No ack')
240
242
  end
241
243
  end
242
244
  end
@@ -315,13 +317,23 @@ module RSMP
315
317
  !skip.include?(klass)
316
318
  end
317
319
 
320
+ def process_deferred
321
+ node.process_deferred
322
+ end
323
+
324
+ def verify_sequence message
325
+ expect_version_message(message) unless @version_determined
326
+ end
327
+
318
328
  def process_packet json
319
329
  attributes = Message.parse_attributes json
320
330
  message = Message.build attributes, json
321
331
  message.validate(get_schemas) if should_validate_ingoing_message?(message)
322
- notify message
323
- expect_version_message(message) unless @version_determined
324
- process_message message
332
+ verify_sequence message
333
+ deferred_notify do
334
+ notify message
335
+ process_message message
336
+ end
325
337
  process_deferred
326
338
  message
327
339
  rescue InvalidPacket => e
@@ -338,20 +350,23 @@ module RSMP
338
350
  rescue SchemaError, RSMP::Schemer::Error => e
339
351
  str = "Received invalid #{message.type}, schema errors: #{e.message}"
340
352
  log str, message: message, level: :warning
341
- notify_error e.exception("#{str} #{message.json}")
353
+ notify_error e.exception("#{str} #{message.json}"), message: message
342
354
  dont_acknowledge message, str
343
355
  message
344
356
  rescue InvalidMessage => e
345
357
  str = "Received", "invalid #{message.type}, #{e.message}"
346
- notify_error e.exception("#{str} #{message.json}")
358
+ notify_error e.exception("#{str} #{message.json}"), message: message
347
359
  dont_acknowledge message, str
348
360
  message
349
361
  rescue FatalError => e
350
362
  str = "Rejected #{message.type},"
351
- notify_error e.exception("#{str} #{message.json}")
363
+ notify_error e.exception("#{str} #{message.json}"), message: message
352
364
  dont_acknowledge message, str, "#{e.message}"
353
365
  stop
354
366
  message
367
+ ensure
368
+ clear_deferred_notify
369
+ node.clear_deferred
355
370
  end
356
371
 
357
372
  def process_message message
@@ -402,7 +417,7 @@ module RSMP
402
417
  if candidates.any?
403
418
  @rsmp_version = candidates.sort_by { |v| Gem::Version.new(v) }.last # pick latest version
404
419
  else
405
- raise FatalError.new "RSMP versions [#{message.versions.join(',')}] requested, but only [#{versions.join(',')}] supported."
420
+ raise HandshakeError.new "RSMP versions [#{message.versions.join(',')}] requested, but only [#{versions.join(',')}] supported."
406
421
  end
407
422
  end
408
423
 
@@ -546,7 +561,7 @@ module RSMP
546
561
 
547
562
  def expect_version_message message
548
563
  unless message.is_a?(Version) || message.is_a?(MessageAck) || message.is_a?(MessageNotAck)
549
- raise FatalError.new "Version must be received first"
564
+ raise HandshakeError.new "Version must be received first"
550
565
  end
551
566
  end
552
567
 
@@ -578,7 +593,7 @@ module RSMP
578
593
  # will be raised in the parent task, and caught by rspec.
579
594
  # rspec will then show the error and record the test as failed
580
595
  m_id_short = RSMP::Message.shorten_m_id m_id, 8
581
- result = RSMP::MessageRejected.new "Aggregated status request #{m_id_short} was rejected: #{message.attribute('rea')}"
596
+ result = RSMP::MessageRejected.new "Aggregated status request #{m_id_short} was rejected with '#{message.attribute('rea')}'"
582
597
  next true # done, no more messages wanted
583
598
  end
584
599
  elsif message.is_a?(MessageAck)
@@ -587,6 +602,5 @@ module RSMP
587
602
  false
588
603
  end
589
604
  end
590
-
591
605
  end
592
606
  end
@@ -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
@@ -75,10 +79,6 @@ module RSMP
75
79
  acknowledge message
76
80
  end
77
81
 
78
- def process_deferred
79
- supervisor.process_deferred
80
- end
81
-
82
82
  def version_accepted message
83
83
  log "Received Version message for site #{@site_id}", message: message, level: :log
84
84
  start_timer
@@ -149,10 +149,6 @@ module RSMP
149
149
  asp = message.attribute("aSp")
150
150
  log "Received #{message.type}, #{alarm_code} #{asp} [#{status}]", message: message, level: :log
151
151
  acknowledge message
152
- rescue RSMP::RepeatedAlarmError => e
153
- str = "Rejected #{message.type} message, "
154
- dont_acknowledge message, str, "#{e}"
155
- notify_error e.exception("#{str}#{e.message} #{message.json}")
156
152
  end
157
153
 
158
154
  def version_acknowledged
@@ -191,6 +187,8 @@ module RSMP
191
187
  end
192
188
 
193
189
  def process_status_response message
190
+ component = find_component message.attribute("cId")
191
+ component.handle_status_response message
194
192
  log "Received #{message.type}", message: message, level: :log
195
193
  acknowledge message
196
194
  end
@@ -202,7 +200,7 @@ module RSMP
202
200
  message
203
201
  end
204
202
 
205
- def subscribe_to_status component, status_list, options={}
203
+ def subscribe_to_status component_id, status_list, options={}
206
204
  validate_ready 'subscribe to status'
207
205
  m_id = options[:m_id] || RSMP::Message.make_m_id
208
206
 
@@ -210,10 +208,13 @@ module RSMP
210
208
  # but must to remove from the subscribe message
211
209
  subscribe_list = status_list.map { |item| item.slice('sCI','n','uRt') }
212
210
 
211
+ component = find_component component_id
212
+ component.handle_status_subscribe subscribe_list
213
+
213
214
  message = RSMP::StatusSubscribe.new({
214
215
  "ntsOId" => '',
215
216
  "xNId" => '',
216
- "cId" => component,
217
+ "cId" => component_id,
217
218
  "sS" => subscribe_list,
218
219
  'mId' => m_id
219
220
  })
@@ -222,12 +223,15 @@ module RSMP
222
223
  end
223
224
  end
224
225
 
225
- 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
+
226
230
  validate_ready 'unsubscribe to status'
227
231
  message = RSMP::StatusUnsubscribe.new({
228
232
  "ntsOId" => '',
229
233
  "xNId" => '',
230
- "cId" => component,
234
+ "cId" => component_id,
231
235
  "sS" => status_list
232
236
  })
233
237
  send_message message, validate: options[:validate]
@@ -235,6 +239,8 @@ module RSMP
235
239
  end
236
240
 
237
241
  def process_status_update message
242
+ component = find_component message.attribute("cId")
243
+ component.handle_status_update message
238
244
  log "Received #{message.type}", message: message, level: :log
239
245
  acknowledge message
240
246
  end
@@ -333,6 +339,7 @@ module RSMP
333
339
 
334
340
  def notify_error e, options={}
335
341
  @supervisor.notify_error e, options if @supervisor
342
+ distribute_error e, options
336
343
  end
337
344
 
338
345
  def collect_alarms parent_task, options={}
@@ -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
@@ -246,7 +250,7 @@ module RSMP
246
250
 
247
251
  def check_site_already_connected site_id
248
252
  site = find_site(site_id)
249
- raise FatalError.new "Site '#{site_id}' already connected" if site != nil && site != self
253
+ raise HandshakeError.new "Site '#{site_id}' already connected" if site != nil && site != self
250
254
  end
251
255
 
252
256
  def site_id_to_site_setting site_id
@@ -256,7 +260,7 @@ module RSMP
256
260
  return settings
257
261
  end
258
262
  end
259
- raise FatalError.new "site id #{site_id} unknown"
263
+ raise HandshakeError.new "site id #{site_id} unknown"
260
264
  end
261
265
 
262
266
  def ip_to_site_settings ip
@@ -86,10 +86,6 @@ module RSMP
86
86
  dont_acknowledge message, '', e.to_s
87
87
  end
88
88
 
89
- def process_deferred
90
- site.process_deferred
91
- end
92
-
93
89
  def acknowledged_first_ingoing message
94
90
  # TODO
95
91
  # aggregateds status should only be send for later version of rsmp
@@ -229,7 +225,6 @@ module RSMP
229
225
  def process_status_subcribe message
230
226
  log "Received #{message.type}", message: message, level: :log
231
227
 
232
-
233
228
  # @status_subscriptions is organized by component/code/name, for example:
234
229
  #
235
230
  # {"AA+BBCCC=DDDEE002"=>{"S001"=>["number"]}}
@@ -238,21 +233,14 @@ module RSMP
238
233
  # for each component, containing all the requested statuses
239
234
 
240
235
  update_list = {}
241
-
242
236
  component = message.attributes["cId"]
243
-
244
237
  @status_subscriptions[component] ||= {}
245
238
  update_list[component] ||= {}
246
-
247
- subs = @status_subscriptions[component]
248
239
  now = Time.now # internal timestamp
249
240
 
250
241
  message.attributes["sS"].each do |arg|
251
242
  sCI = arg["sCI"]
252
243
  subcription = {interval: arg["uRt"].to_i, last_sent_at: now}
253
- subs[sCI] ||= {}
254
- subs[sCI][arg["n"]] = subcription
255
-
256
244
  update_list[component][sCI] ||= []
257
245
  update_list[component][sCI] << arg["n"]
258
246
  end
@@ -291,11 +279,15 @@ module RSMP
291
279
  end
292
280
  end
293
281
 
294
- def store_last_sent_status component, code, name, value
282
+ def store_last_sent_status message
283
+ component_id = message.attribute('cId')
295
284
  @last_status_sent ||= {}
296
- @last_status_sent[component] ||= {}
297
- @last_status_sent[component][code] ||= {}
298
- @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
299
291
  end
300
292
 
301
293
  def status_update_timer now
@@ -316,7 +308,6 @@ module RSMP
316
308
  last_sent = fetch_last_sent_status component, code, name
317
309
  if current != last_sent
318
310
  should_send = true
319
- store_last_sent_status component, code, name, current
320
311
  end
321
312
  else
322
313
  # send at regular intervals
@@ -360,6 +351,7 @@ module RSMP
360
351
  "sS"=>sS
361
352
  })
362
353
  send_message update
354
+ store_last_sent_status update
363
355
  end
364
356
  end
365
357
 
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.4.6"
2
+ VERSION = "0.5.3"
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.4.6
4
+ version: 0.5.3
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-01 00:00:00.000000000 Z
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async