rsmp 0.1.17 → 0.1.30

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # Receives items from a Notifier, as long as it's
2
+ # installed as a listener.
3
+
4
+ module RSMP
5
+ class Listener
6
+ include Inspect
7
+
8
+ def initialize proxy, options={}
9
+ @proxy = proxy
10
+ end
11
+
12
+ def notify message
13
+ end
14
+
15
+ def listen &block
16
+ @proxy.add_listener self
17
+ yield
18
+ ensure
19
+ @proxy.remove_listener self
20
+ end
21
+
22
+ end
23
+ end
data/lib/rsmp/logger.rb CHANGED
@@ -13,6 +13,7 @@ module RSMP
13
13
  'component'=>false,
14
14
  'level'=>false,
15
15
  'ip'=>false,
16
+ 'port'=>false,
16
17
  'index'=>false,
17
18
  'timestamp'=>true,
18
19
  'json'=>false,
@@ -82,7 +83,6 @@ module RSMP
82
83
  end
83
84
 
84
85
  def colorize level, str
85
- #p String.color_samples
86
86
  if @settings["color"] == false || @settings["color"] == nil
87
87
  str
88
88
  elsif @settings["color"] == true
@@ -125,8 +125,9 @@ module RSMP
125
125
  end
126
126
  end
127
127
 
128
- def dump archive, force:false
129
- log = archive.items.map do |item|
128
+ def dump archive, force:false, num:nil
129
+ num ||= archive.items.size
130
+ log = archive.items.last(num).map do |item|
130
131
  str = build_output item
131
132
  str = colorize item[:level], str
132
133
  end
@@ -137,8 +138,9 @@ module RSMP
137
138
  parts = []
138
139
  parts << item[:index].to_s.ljust(7) if @settings["index"] == true
139
140
  parts << item[:author].to_s.ljust(13) if @settings["author"] == true
140
- parts << item[:timestamp].to_s.ljust(24) unless @settings["timestamp"] == false
141
+ parts << Clock.to_s(item[:timestamp]).ljust(24) unless @settings["timestamp"] == false
141
142
  parts << item[:ip].to_s.ljust(22) unless @settings["ip"] == false
143
+ parts << item[:port].to_s.ljust(8) unless @settings["port"] == false
142
144
  parts << item[:site_id].to_s.ljust(13) unless @settings["site_id"] == false
143
145
  parts << item[:component_id].to_s.ljust(18) unless @settings["component"] == false
144
146
 
@@ -3,10 +3,10 @@
3
3
  #
4
4
 
5
5
  module RSMP
6
- class Base
6
+ module Logging
7
7
  attr_reader :archive, :logger
8
8
 
9
- def initialize 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
@@ -15,7 +15,7 @@ module RSMP
15
15
  end
16
16
 
17
17
  def log str, options={}
18
- default = { str:str, level: :log, author: author }
18
+ default = { str:str, level: :log, author: author, ip: @ip, port: @port }
19
19
  prepared = RSMP::Archive.prepare_item default.merge(options)
20
20
  @archive.add prepared
21
21
  @logger.log prepared
data/lib/rsmp/message.rb CHANGED
@@ -1,33 +1,18 @@
1
+ require 'rsmp_schemer'
2
+
1
3
  # rsmp messages
2
4
  module RSMP
3
5
  class Message
6
+ include Inspect
4
7
 
5
- attr_reader :now, :attributes, :out, :timestamp
8
+ attr_reader :now, :attributes, :out
9
+ attr_reader :timestamp # this is an internal timestamp recording when we receive/send
6
10
  attr_accessor :json, :direction
7
11
 
8
- def self.load_schemas
9
- # path to files in submodule folder
10
- schema_path = File.join(File.dirname(__dir__),'rsmp_schema','schema')
11
- @@schemas = {}
12
-
13
- core_schema_path = File.join(schema_path,'core','rsmp.json')
14
- @@schemas[nil] = JSONSchemer.schema( Pathname.new(core_schema_path) )
15
-
16
- tlc_schema_path = File.join(schema_path,'tlc','sxl.json')
17
- @@schemas['traffic_light_controller'] = JSONSchemer.schema( Pathname.new(tlc_schema_path) )
18
-
19
- @@schemas
20
- end
21
-
22
- def self.get_schema sxl=nil
23
- schema = @@schemas[sxl]
24
- raise SchemaError.new("Unknown schema #{sxl}") unless schema
25
- schema
12
+ def self.make_m_id
13
+ SecureRandom.uuid()
26
14
  end
27
15
 
28
- @@schemas = load_schemas
29
-
30
-
31
16
  def self.parse_attributes json
32
17
  raise ArgumentError unless json
33
18
  JSON.parse json
@@ -46,6 +31,8 @@ module RSMP
46
31
  message = Version.new attributes
47
32
  when "AggregatedStatus"
48
33
  message = AggregatedStatus.new attributes
34
+ when "AggregatedStatusRequest"
35
+ message = AggregatedStatusRequest.new attributes
49
36
  when "Watchdog"
50
37
  message = Watchdog.new attributes
51
38
  when "Alarm"
@@ -80,8 +67,12 @@ module RSMP
80
67
  @attributes["mId"]
81
68
  end
82
69
 
70
+ def self.shorten_m_id m_id, length=4
71
+ m_id[0..length-1]
72
+ end
73
+
83
74
  def m_id_short
84
- @attributes["mId"][0..3]
75
+ Message.shorten_m_id @attributes["mId"]
85
76
  end
86
77
 
87
78
  def attribute key
@@ -118,7 +109,9 @@ module RSMP
118
109
  end
119
110
 
120
111
  def initialize attributes = {}
121
- @timestamp = RSMP.now_object
112
+ @timestamp = Time.now # this timestamp is for internal use, and does not the clock
113
+ # in the node, which can be set by an rsmp supervisor
114
+
122
115
  @attributes = { "mType"=> "rSMsg" }.merge attributes
123
116
 
124
117
  ensure_message_id
@@ -126,16 +119,13 @@ module RSMP
126
119
 
127
120
  def ensure_message_id
128
121
  # if message id is empty, generate a new one
129
- @attributes["mId"] ||= SecureRandom.uuid()
122
+ @attributes["mId"] ||= Message.make_m_id
130
123
  end
131
124
 
132
- def validate sxl=nil
133
- schema = Message.get_schema(sxl)
134
- unless schema.valid? attributes
135
- errors = schema.validate attributes
136
- error_string = errors.map do |item|
137
- [item['data_pointer'],item['type'],item['details']].compact.join(' ')
138
- end.join(", ")
125
+ def validate schemas
126
+ errors = RSMP::Schemer.validate attributes, schemas
127
+ if errors
128
+ error_string = errors.compact.join(', ').strip
139
129
  raise SchemaError.new error_string
140
130
  end
141
131
  end
@@ -189,6 +179,14 @@ module RSMP
189
179
  end
190
180
  end
191
181
 
182
+ class AggregatedStatusRequest < Message
183
+ def initialize attributes = {}
184
+ super({
185
+ "type" => "AggregatedStatusRequest",
186
+ }.merge attributes)
187
+ end
188
+ end
189
+
192
190
  class Alarm < Message
193
191
  def initialize attributes = {}
194
192
  super({
@@ -197,6 +195,22 @@ module RSMP
197
195
  end
198
196
  end
199
197
 
198
+ class AlarmRequest < Message
199
+ def initialize attributes = {}
200
+ super({
201
+ "type" => "Alarm",
202
+ }.merge attributes)
203
+ end
204
+ end
205
+
206
+ class AlarmAcknowledged < Message
207
+ def initialize attributes = {}
208
+ super({
209
+ "type" => "Alarm",
210
+ }.merge attributes)
211
+ end
212
+ end
213
+
200
214
  class Watchdog < Message
201
215
  def initialize attributes = {}
202
216
  super({
data/lib/rsmp/node.rb CHANGED
@@ -1,23 +1,58 @@
1
- # RSMP site
2
- #
3
- # Handles a single connection to a supervisor.
4
- # We connect to the supervisor.
1
+ # Base class for sites and supervisors
5
2
 
6
3
  module RSMP
7
- class Node < Base
8
- attr_reader :archive, :logger, :task
4
+ class Node
5
+ include Logging
6
+ include Wait
7
+ include Inspect
8
+
9
+ attr_reader :archive, :logger, :task, :deferred, :error_condition, :clock
9
10
 
10
11
  def initialize options
11
- super options
12
+ initialize_logging options
13
+ @task = options[:task]
14
+ @deferred = []
15
+ @clock = Clock.new
16
+ @error_condition = Async::Notification.new
17
+ end
18
+
19
+ def notify_error e, options={}
20
+ if options[:level] == :internal
21
+ log ["#{e.to_s} in task: #{Async::Task.current.to_s}",e.backtrace].flatten.join("\n"), level: :error
22
+ end
23
+ @error_condition.signal e
24
+ end
25
+
26
+ def defer item
27
+ @deferred << item
28
+ end
29
+
30
+ def process_deferred
31
+ cloned = @deferred.clone # clone in case do_deferred restarts the current task
32
+ @deferred.clear
33
+ cloned.each do |item|
34
+ do_deferred item
35
+ end
36
+ end
37
+
38
+ def do_deferred item
39
+ end
40
+
41
+ def do_start task
42
+ task.annotate self.class.to_s
43
+ @task = task
44
+ start_action
45
+ idle
12
46
  end
13
47
 
14
48
  def start
15
49
  starting
16
- Async do |task|
17
- task.annotate self.class
18
- @task = task
19
- start_action
20
- idle
50
+ if @task
51
+ do_start @task
52
+ else
53
+ Async do |task|
54
+ do_start task
55
+ end
21
56
  end
22
57
  rescue Errno::EADDRINUSE => e
23
58
  log "Cannot start: #{e.to_s}", level: :error
@@ -0,0 +1,29 @@
1
+ # Distributes messages to listeners
2
+
3
+ module RSMP
4
+ module Notifier
5
+ include Inspect
6
+
7
+ def inspect
8
+ "#<#{self.class.name}:#{self.object_id}, #{inspector(:@listeners)}>"
9
+ end
10
+
11
+ def initialize_distributor
12
+ @listeners = []
13
+ end
14
+
15
+ def add_listener listener
16
+ raise ArgumentError unless listener
17
+ @listeners << listener unless @listeners.include? listener
18
+ end
19
+
20
+ def remove_listener listener
21
+ raise ArgumentError unless listener
22
+ @listeners.delete listener
23
+ end
24
+
25
+ def notify message
26
+ @listeners.each { |listener| listener.notify message }
27
+ end
28
+ end
29
+ end
data/lib/rsmp/proxy.rb CHANGED
@@ -1,24 +1,61 @@
1
- # Base class for a connection to a remote site or supervisor.
1
+ # Logging class for a connection to a remote site or supervisor.
2
+
3
+ require 'rubygems'
2
4
 
3
5
  module RSMP
4
- class Proxy < Base
5
- attr_reader :state, :archive, :connection_info, :sxl
6
+ class Proxy
7
+ WRAPPING_DELIMITER = "\f"
8
+
9
+ include Logging
10
+ include Wait
11
+ include Notifier
12
+ include Inspect
13
+
14
+ attr_reader :state, :archive, :connection_info, :sxl, :task, :collector
6
15
 
7
16
  def initialize options
8
- super options
17
+ initialize_logging options
9
18
  @settings = options[:settings]
10
19
  @task = options[:task]
11
20
  @socket = options[:socket]
12
21
  @ip = options[:ip]
22
+ @port = options[:port]
13
23
  @connection_info = options[:info]
14
24
  @sxl = nil
25
+ @site_settings = nil # can't pick until we know the site id
26
+ initialize_distributor
27
+
28
+ prepare_collection @settings['collect']
15
29
  clear
16
30
  end
17
31
 
32
+ def inspect
33
+ "#<#{self.class.name}:#{self.object_id}, #{inspector(
34
+ :@acknowledgements,:@settings,:@site_settings
35
+ )}>"
36
+ end
37
+
38
+ def clock
39
+ node.clock
40
+ end
41
+
42
+ def prepare_collection num
43
+ if num
44
+ @collector = RSMP::Collector.new self, num: num, ingoing: true, outgoing: true
45
+ add_listener @collector
46
+ end
47
+ end
48
+
49
+ def collect task, options, &block
50
+ collector = RSMP::Collector.new self, options
51
+ collector.collect task, &block
52
+ end
53
+
18
54
  def run
19
55
  start
20
56
  @reader.wait if @reader
21
- stop
57
+ ensure
58
+ stop unless [:stopped, :stopping].include? @state
22
59
  end
23
60
 
24
61
  def ready?
@@ -69,7 +106,7 @@ module RSMP
69
106
  @reader = @task.async do |task|
70
107
  task.annotate "reader"
71
108
  @stream = Async::IO::Stream.new(@socket)
72
- @protocol = Async::IO::Protocol::Line.new(@stream,RSMP::WRAPPING_DELIMITER) # rsmp messages are json terminated with a form-feed
109
+ @protocol = Async::IO::Protocol::Line.new(@stream,WRAPPING_DELIMITER) # rsmp messages are json terminated with a form-feed
73
110
 
74
111
  while json = @protocol.read_line
75
112
  beginning = Time.now
@@ -97,33 +134,45 @@ module RSMP
97
134
  log "Connection reset by peer", level: :warning
98
135
  rescue Errno::EPIPE
99
136
  log "Broken pipe", level: :warning
100
- rescue SystemCallError => e # all ERRNO errors
101
- log "Proxy exception: #{e.to_s}", level: :error
102
137
  rescue StandardError => e
103
- log ["Proxy exception: #{e.inspect}",e.backtrace].flatten.join("\n"), level: :error
138
+ notify_error e, level: :internal
104
139
  end
105
140
  end
106
141
 
142
+ def notify_error e, options={}
143
+ node.notify_error e, options
144
+ end
145
+
107
146
  def start_watchdog
108
- log "Starting watchdog with interval #{@settings["watchdog_interval"]} seconds", level: :debug
147
+ log "Starting watchdog with interval #{@site_settings['intervals']['watchdog']} seconds", level: :debug
109
148
  send_watchdog
110
149
  @watchdog_started = true
111
150
  end
112
151
 
113
152
  def start_timer
114
153
  name = "timer"
115
- interval = @settings["timer_interval"] || 1
154
+ interval = @site_settings['intervals']['timer'] || 1
116
155
  log "Starting #{name} with interval #{interval} seconds", level: :debug
117
- @latest_watchdog_received = RSMP.now_object
156
+ @latest_watchdog_received = Clock.now
118
157
 
119
158
  @timer = @task.async do |task|
120
159
  task.annotate "timer"
121
160
  next_time = Time.now.to_f
122
161
  loop do
123
- now = RSMP.now_object
124
- break if timer(now) == false
125
- rescue StandardError => e
126
- log ["#{name} exception: #{e}",e.backtrace].flatten.join("\n"), level: :error
162
+ begin
163
+ now = Clock.now
164
+ timer(now)
165
+ rescue EOFError => e
166
+ log "Timer: Connection closed: #{e}", level: :warning
167
+ rescue IOError => e
168
+ log "Timer: IOError", level: :warning
169
+ rescue Errno::ECONNRESET
170
+ log "Timer: Connection reset by peer", level: :warning
171
+ rescue Errno::EPIPE => e
172
+ log "Timer: Broken pipe", level: :warning
173
+ rescue StandardError => e
174
+ notify_error e, level: :internal
175
+ end
127
176
  ensure
128
177
  next_time += interval
129
178
  duration = next_time - Time.now.to_f
@@ -133,14 +182,14 @@ module RSMP
133
182
  end
134
183
 
135
184
  def timer now
136
- check_watchdog_send_time now
137
- return false if check_ack_timeout now
138
- return false if check_watchdog_timeout now
185
+ watchdog_send_timer now
186
+ check_ack_timeout now
187
+ check_watchdog_timeout now
139
188
  end
140
189
 
141
- def check_watchdog_send_time now
190
+ def watchdog_send_timer now
142
191
  return unless @watchdog_started
143
- return if @settings["watchdog_interval"] == :never
192
+ return if @site_settings['intervals']['watchdog'] == :never
144
193
 
145
194
  if @latest_watchdog_send_at == nil
146
195
  send_watchdog now
@@ -148,47 +197,38 @@ module RSMP
148
197
  # we add half the timer interval to pick the timer
149
198
  # event closes to the wanted wathcdog interval
150
199
  diff = now - @latest_watchdog_send_at
151
- if (diff + 0.5*@settings["timer_interval"]) >= (@settings["watchdog_interval"])
200
+ if (diff + 0.5*@site_settings['intervals']['timer']) >= (@site_settings['intervals']['watchdog'])
152
201
  send_watchdog now
153
202
  end
154
203
  end
155
- rescue StandardError => e
156
- log ["Watchdog error: #{e}",e.backtrace].flatten.join("\n"), level: :error
157
204
  end
158
205
 
159
- def send_watchdog now=nil
160
- now = RSMP.now_object unless nil
161
- message = Watchdog.new( {"wTs" => RSMP.now_object_to_string(now)})
206
+ def send_watchdog now=Clock.now
207
+ message = Watchdog.new( {"wTs" => clock.to_s})
162
208
  send_message message
163
209
  @latest_watchdog_send_at = now
164
210
  end
165
211
 
166
212
  def check_ack_timeout now
167
- timeout = @settings["acknowledgement_timeout"]
213
+ timeout = @site_settings['timeouts']['acknowledgement']
168
214
  # hash cannot be modify during iteration, so clone it
169
215
  @awaiting_acknowledgement.clone.each_pair do |m_id, message|
170
216
  latest = message.timestamp + timeout
171
217
  if now > latest
172
218
  log "No acknowledgements for #{message.type} #{message.m_id_short} within #{timeout} seconds", level: :error
173
219
  stop
174
- return true
175
220
  end
176
221
  end
177
- false
178
222
  end
179
223
 
180
224
  def check_watchdog_timeout now
181
-
182
- timeout = @settings["watchdog_timeout"]
225
+ timeout = @site_settings['timeouts']['watchdog']
183
226
  latest = @latest_watchdog_received + timeout
184
227
  left = latest - now
185
- #log "Check watchdog, time:#{timeout}, last:#{@latest_watchdog_received}, now: #{now}, latest:#{latest}, left #{left}, fail:#{left<0}", level: :debug
186
228
  if left < 0
187
229
  log "No Watchdog within #{timeout} seconds", level: :error
188
230
  stop
189
- return true
190
231
  end
191
- false
192
232
  end
193
233
 
194
234
  def stop_tasks
@@ -200,23 +240,36 @@ module RSMP
200
240
  super str, options.merge(ip: @ip, port: @port, site_id: @site_id)
201
241
  end
202
242
 
203
- def send_message message, reason=nil
243
+ def get_schemas
244
+ # normally we have an sxl, but during connection, it hasn't been established yet
245
+ # at these times we only validate against the core schema
246
+ # TODO
247
+ # what schema should we use to validate the intial Version and MessageAck messages?
248
+ schemas = { core: '3.1.5' }
249
+ schemas[sxl] = sxl_version if sxl
250
+ schemas
251
+ end
252
+
253
+ def send_message message, reason=nil, validate: true
204
254
  raise IOError unless @protocol
205
- message.generate_json
206
- message.validate sxl
207
255
  message.direction = :out
256
+ message.generate_json
257
+ message.validate get_schemas unless validate==false
208
258
  expect_acknowledgement message
209
259
  @protocol.write_lines message.json
260
+ notify message
210
261
  log_send message, reason
211
262
  rescue EOFError, IOError
212
263
  buffer_message message
213
264
  rescue SchemaError => e
214
- log "Error sending #{message.type}, schema validation failed: #{e.message}", message: message, level: :error
265
+ str = "Could not send #{message.type} because schema validation failed: #{e.message}"
266
+ log str, message: message, level: :error
267
+ notify_error e.exception("#{str} #{message.json}")
215
268
  end
216
269
 
217
270
  def buffer_message message
218
271
  # TODO
219
- log "Cannot send #{message.type} because the connection is closed.", message: message, level: :error
272
+ #log "Cannot send #{message.type} because the connection is closed.", message: message, level: :error
220
273
  end
221
274
 
222
275
  def log_send message, reason=nil
@@ -236,25 +289,38 @@ module RSMP
236
289
  def process_packet json
237
290
  attributes = Message.parse_attributes json
238
291
  message = Message.build attributes, json
239
- message.validate sxl
292
+ message.validate get_schemas
293
+ notify message
240
294
  expect_version_message(message) unless @version_determined
241
295
  process_message message
296
+ process_deferred
242
297
  message
243
298
  rescue InvalidPacket => e
244
- warning "Received invalid package, must be valid JSON but got #{json.size} bytes: #{e.message}"
299
+ str = "Received invalid package, must be valid JSON but got #{json.size} bytes: #{e.message}"
300
+ notify_error e.exception(str)
301
+ log str, level: :warning
245
302
  nil
246
303
  rescue MalformedMessage => e
247
- warning "Received malformed message, #{e.message}", Malformed.new(attributes)
304
+ str = "Received malformed message, #{e.message}"
305
+ notify_error e.exception(str)
306
+ log str, message: Malformed.new(attributes), level: :warning
248
307
  # cannot send NotAcknowledged for a malformed message since we can't read it, just ignore it
249
308
  nil
250
309
  rescue SchemaError => e
251
- dont_acknowledge message, "Received", "invalid #{message.type}, schema errors: #{e.message}"
310
+ str = "Received invalid #{message.type}, schema errors: #{e.message}"
311
+ log str, message: message, level: :warning
312
+ notify_error e.exception("#{str} #{message.json}")
313
+ dont_acknowledge message, str
252
314
  message
253
315
  rescue InvalidMessage => e
254
- dont_acknowledge message, "Received", "invalid #{message.type}, #{e.message}"
316
+ str = "Received", "invalid #{message.type}, #{e.message}"
317
+ notify_error e.exception("#{str} #{message.json}")
318
+ dont_acknowledge message, str
255
319
  message
256
320
  rescue FatalError => e
257
- dont_acknowledge message, "Rejected #{message.type},", "#{e.message}"
321
+ str = "Rejected #{message.type},"
322
+ notify_error e.exception("#{str} #{message.json}")
323
+ dont_acknowledge message, str, "#{e.message}"
258
324
  stop
259
325
  message
260
326
  end
@@ -294,13 +360,20 @@ module RSMP
294
360
  dont_acknowledge message, "Received", "extraneous Version message"
295
361
  end
296
362
 
363
+ def rsmp_versions
364
+ return ['3.1.5'] if @site_settings["rsmp_versions"] == 'latest'
365
+ return ['3.1.1','3.1.2','3.1.3','3.1.4','3.1.5'] if @site_settings["rsmp_versions"] == 'all'
366
+ @site_settings["rsmp_versions"]
367
+ end
368
+
297
369
  def check_rsmp_version message
370
+ versions = rsmp_versions
298
371
  # find versions that both we and the client support
299
- candidates = message.versions & @settings["rsmp_versions"]
372
+ candidates = message.versions & versions
300
373
  if candidates.any?
301
- @rsmp_version = candidates.sort.last # pick latest version
374
+ @rsmp_version = candidates.sort_by { |v| Gem::Version.new(v) }.last # pick latest version
302
375
  else
303
- raise FatalError.new "RSMP versions [#{message.versions.join(',')}] requested, but only [#{@settings["rsmp_versions"].join(',')}] supported."
376
+ raise FatalError.new "RSMP versions [#{message.versions.join(',')}] requested, but only [#{versions.join(',')}] supported."
304
377
  end
305
378
  end
306
379
 
@@ -335,14 +408,24 @@ module RSMP
335
408
  def wait_for_state state, timeout
336
409
  states = [state].flatten
337
410
  return if states.include?(@state)
338
- RSMP::Wait.wait_for(@task,@state_condition,timeout) do |s|
411
+ wait_for(@state_condition,timeout) do
339
412
  states.include?(@state)
340
413
  end
341
414
  @state
415
+ rescue Async::TimeoutError
416
+ raise RSMP::TimeoutError.new "Did not reach state #{state} within #{timeout}s"
342
417
  end
343
418
 
344
419
  def send_version site_id, rsmp_versions
345
- versions_array = [rsmp_versions].flatten.map {|v| {"vers" => v} }
420
+ if rsmp_versions=='latest'
421
+ versions = ['3.1.5']
422
+ elsif rsmp_versions=='all'
423
+ versions = ['3.1.1','3.1.2','3.1.3','3.1.4','3.1.5']
424
+ else
425
+ versions = [rsmp_versions].flatten
426
+ end
427
+ versions_array = versions.map {|v| {"vers" => v} }
428
+
346
429
  site_id_array = [site_id].flatten.map {|id| {"sId" => id} }
347
430
 
348
431
  version_response = Version.new({
@@ -428,7 +511,7 @@ module RSMP
428
511
 
429
512
  def process_watchdog message
430
513
  log "Received #{message.type}", message: message, level: :log
431
- @latest_watchdog_received = RSMP.now_object
514
+ @latest_watchdog_received = Clock.now
432
515
  acknowledge message
433
516
  end
434
517
 
@@ -445,27 +528,16 @@ module RSMP
445
528
  def version_acknowledged
446
529
  end
447
530
 
448
- def wait_for_acknowledgement original, timeout, options={}
449
- raise ArgumentError unless original
450
- RSMP::Wait.wait_for(@task,@acknowledgement_condition,timeout) do |message|
451
- message.is_a?(MessageAck) &&
452
- message.attributes["oMId"] == original.m_id
453
- end
454
- end
455
-
456
- def wait_for_not_acknowledged original, timeout
531
+ def wait_for_acknowledgement original, timeout
457
532
  raise ArgumentError unless original
458
- RSMP::Wait.wait_for(@task,@acknowledgement_condition,timeout) do |message|
459
- message.is_a?(MessageNotAck) &&
460
- message.attributes["oMId"] == original.m_id
461
- end
462
- end
463
-
464
- def wait_for_acknowledgements timeout
465
- return if @awaiting_acknowledgement.empty?
466
- RSMP::Wait.wait_for(@task,@acknowledgement_condition,timeout) do |message|
467
- @awaiting_acknowledgement.empty?
533
+ wait_for(@acknowledgement_condition,timeout) do |message|
534
+ if message.is_a?(MessageNotAck) && message.attributes["oMId"] == original.m_id
535
+ raise RSMP::MessageRejected.new(message.attributes['rea'])
536
+ end
537
+ message.is_a?(MessageAck) && message.attributes["oMId"] == original.m_id
468
538
  end
539
+ rescue Async::TimeoutError
540
+ raise RSMP::TimeoutError.new("Acknowledgement for #{original.type} #{original.m_id} not received within #{timeout}s")
469
541
  end
470
542
 
471
543
  def node