rsmp 0.7.5 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,22 +5,19 @@ module RSMP
5
5
  class Listener
6
6
  include Inspect
7
7
 
8
- def initialize proxy, options={}
9
- @proxy = proxy
8
+ def initialize notifier, options={}
9
+ @notifier = notifier
10
10
  end
11
11
 
12
- def notify message
12
+ def change_notifier notifier
13
+ @notifier.remove_listener self if @notifier
14
+ @notifier = notifier
13
15
  end
14
16
 
15
- def notify_error error, options={}
17
+ def notify message
16
18
  end
17
19
 
18
- def listen &block
19
- @proxy.add_listener self
20
- yield
21
- ensure
22
- @proxy.remove_listener self
20
+ def notify_error error, options={}
23
21
  end
24
-
25
22
  end
26
23
  end
@@ -1,64 +0,0 @@
1
- module RSMP
2
- # Class for waiting for specific command responses
3
- class CommandResponseMatcher < Matcher
4
- def initialize proxy, want, options={}
5
- super proxy, want, options.merge(
6
- type: ['CommandResponse','MessageNotAck'],
7
- title:'command response'
8
- )
9
- end
10
-
11
- def build_query want
12
- CommandQuery.new want
13
- end
14
-
15
- # Get items, in our case the return values
16
- def get_items message
17
- message.attributes['rvs']
18
- end
19
- end
20
-
21
- # Base class for waiting for status updates or responses
22
- class StatusUpdateOrResponseMatcher < Matcher
23
- def initialize proxy, want, options={}
24
- super proxy, want, options.merge
25
- end
26
-
27
- def build_query want
28
- StatusQuery.new want
29
- end
30
-
31
- # Get items, in our case status values
32
- def get_items message
33
- message.attributes['sS']
34
- end
35
- end
36
-
37
- # Class for waiting for specific status responses
38
- class StatusResponseMatcher < StatusUpdateOrResponseMatcher
39
- def initialize proxy, want, options={}
40
- super proxy, want, options.merge(
41
- type: ['StatusResponse','MessageNotAck'],
42
- title: 'status response'
43
- )
44
- end
45
- end
46
-
47
- # Class for waiting for specific status responses
48
- class StatusUpdateMatcher < StatusUpdateOrResponseMatcher
49
- def initialize proxy, want, options={}
50
- super proxy, want, options.merge(
51
- type: ['StatusUpdate','MessageNotAck'],
52
- title:'status update'
53
- )
54
- end
55
- end
56
-
57
- # Class for waiting for an aggregated status response
58
- class AggregatedStatusMatcher < Collector
59
- def initialize proxy, options={}
60
- required = { type: ['AggregatedStatus','MessageNotAck'], title: 'aggregated status' }
61
- super proxy, options.merge(required)
62
- end
63
- end
64
- end
@@ -1,5 +1,5 @@
1
1
  module RSMP
2
-
2
+
3
3
  # Class that matches a single status or command item
4
4
  class Query
5
5
  attr_reader :want, :got, :message
@@ -8,26 +8,36 @@ module RSMP
8
8
  @want = want
9
9
  @got = nil
10
10
  @message = nil
11
- @done = false
12
11
  end
13
12
 
14
13
  # Are we done, i.e. did the last checked item match?
15
14
  def done?
16
- @done
15
+ @got != nil
17
16
  end
18
17
 
19
18
  # Check an item and set @done to true if it matches
20
19
  # Store the item and corresponding message if there's a positive or negative match
21
- def check_match item, message
20
+ def perform_match item, message, block
22
21
  matched = match? item
23
22
  if matched != nil
24
- @message = message
25
- @got = item
26
- @done = matched
23
+ if block
24
+ status = block.call(nil,item)
25
+ matched = status if status == true || status == false
26
+ end
27
27
  end
28
28
  matched
29
29
  end
30
30
 
31
+ def keep message, item
32
+ @message = message
33
+ @got = item
34
+ end
35
+
36
+ def forget
37
+ @message = nil
38
+ @got = nil
39
+ end
40
+
31
41
  def match? item
32
42
  end
33
43
  end
@@ -31,15 +31,14 @@ module RSMP
31
31
  # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/} =>
32
32
  # { <StatusResponse message>, {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>"9"} }
33
33
  # }
34
-
35
- class Matcher < Collector
34
+ class StateCollector < Collector
36
35
  attr_reader :queries
37
36
 
38
37
  # Initialize with a list of wanted statuses
39
38
  def initialize proxy, want, options={}
39
+ raise ArgumentError.new("num option cannot be used") if options[:num]
40
40
  super proxy, options.merge( ingoing: true, outgoing: false)
41
41
  @queries = want.map { |item| build_query item }
42
- @want = want
43
42
  end
44
43
 
45
44
  # Build a query object.
@@ -60,14 +59,9 @@ module RSMP
60
59
  @queries.map { |query| query.got }.compact
61
60
  end
62
61
 
63
- # get the first message. Useful when you only collect one mesage
64
- def message
65
- @queries.first.message
66
- end
67
-
68
62
  # Get messages from results
69
63
  def messages
70
- @queries.map { |query| query.message }.uniq
64
+ @queries.map { |query| query.message }.uniq.compact
71
65
  end
72
66
 
73
67
  # Return progress as completes queries vs. total number of queries
@@ -77,14 +71,14 @@ module RSMP
77
71
  { need: need, reached: reached }
78
72
  end
79
73
 
80
- # Are there queries left to match?
74
+ # Are there queries left to type_match?
81
75
  def done?
82
76
  @queries.all? { |query| query.done? }
83
77
  end
84
78
 
85
79
  # Get a simplified hash of queries, with values set to either true or false,
86
80
  # indicating which queries have been matched.
87
- def status
81
+ def query_status
88
82
  @queries.map { |query| [query.want, query.done?] }.to_h
89
83
  end
90
84
 
@@ -95,19 +89,34 @@ module RSMP
95
89
 
96
90
  # Check if a messages matches our criteria.
97
91
  # Match each query against each item in the message
98
- def check_match message
99
- return unless match?(message)
92
+ def perform_match message
93
+ return false if super(message) == false
94
+ return unless collecting?
100
95
  @queries.each do |query| # look through queries
101
96
  get_items(message).each do |item| # look through items in message
102
- matched = query.check_match(item,message)
97
+ matched = query.perform_match(item,message,@block)
98
+ return unless collecting?
103
99
  if matched != nil
104
100
  type = {true=>'match',false=>'mismatch'}[matched]
105
- @proxy.log "#{@title.capitalize} #{message.m_id_short} collect #{type} #{query.want}, item #{item}", level: :debug
106
- break
101
+ @notifier.log "#{@title.capitalize} #{message.m_id_short} collect #{type} #{query.want}, item #{item}", level: :debug
102
+ if matched == true
103
+ query.keep message, item
104
+ elsif matched == false
105
+ query.forget
106
+ end
107
107
  end
108
108
  end
109
109
  end
110
- @proxy.log "#{@title.capitalize} collect reached #{summary}", level: :debug
110
+ complete if done?
111
+ @notifier.log "#{@title.capitalize} collect reached #{summary}", level: :debug
112
+ end
113
+
114
+ # don't collect anything. Query will collect them instead
115
+ def keep message
116
+ end
117
+
118
+ def describe
119
+ @queries.map {|q| q.want.to_s }
111
120
  end
112
121
  end
113
122
  end
@@ -0,0 +1,20 @@
1
+ module RSMP
2
+ # Base class for waiting for status updates or responses
3
+ class StatusCollector < StateCollector
4
+ def initialize proxy, want, options={}
5
+ super proxy, want, options.merge(title: 'status response', type:['MessageNotAck'])
6
+
7
+ @options[:type] << 'StatusUpdate' unless options[:updates] == false
8
+ @options[:type] << 'StatusResponse' unless options[:reponses] == false
9
+ end
10
+
11
+ def build_query want
12
+ RSMP::StatusQuery.new want
13
+ end
14
+
15
+ # Get items, in our case status values
16
+ def get_items message
17
+ message.attributes['sS'] || []
18
+ end
19
+ end
20
+ end
@@ -1,20 +1,5 @@
1
1
  module RSMP
2
- # Match a specific command responses
3
- class CommandQuery < Query
4
- # Match a return value item against a query
5
- def match? item
6
- return nil if @want['cCI'] && @want['cCI'] != item['cCI']
7
- return nil if @want['n'] && @want['n'] != item['n']
8
- if @want['v'].is_a? Regexp
9
- return false if @want['v'] && item['v'] !~ @want['v']
10
- else
11
- return false if @want['v'] && item['v'] != @want['v']
12
- end
13
- true
14
- end
15
- end
16
-
17
- # Match a specific status response or update
2
+ # Match a specific status response or update
18
3
  class StatusQuery < Query
19
4
  # Match a status value against a query
20
5
  def match? item
data/lib/rsmp/error.rb CHANGED
@@ -41,7 +41,7 @@ module RSMP
41
41
  class TimeoutError < Error
42
42
  end
43
43
 
44
- class DisonnectError < Error
44
+ class DisconnectError < Error
45
45
  end
46
46
 
47
47
  class ConnectionError < Error
data/lib/rsmp/node.rb CHANGED
@@ -6,7 +6,7 @@ module RSMP
6
6
  include Wait
7
7
  include Inspect
8
8
 
9
- attr_reader :archive, :logger, :task, :deferred, :error_queue, :clock
9
+ attr_reader :archive, :logger, :task, :deferred, :error_queue, :clock, :collector
10
10
 
11
11
  def initialize options
12
12
  initialize_logging options
@@ -15,6 +15,7 @@ module RSMP
15
15
  @clock = Clock.new
16
16
  @error_queue = Async::Queue.new
17
17
  @ignore_errors = []
18
+ @collect = options[:collect]
18
19
  end
19
20
 
20
21
  def ignore_errors classes, &block
data/lib/rsmp/proxy.rb CHANGED
@@ -15,9 +15,8 @@ module RSMP
15
15
 
16
16
  def initialize options
17
17
  initialize_logging options
18
- setup options
19
18
  initialize_distributor
20
- prepare_collection @settings['collect']
19
+ setup options
21
20
  clear
22
21
  end
23
22
 
@@ -37,6 +36,10 @@ module RSMP
37
36
  @sxl = nil
38
37
  @site_settings = nil # can't pick until we know the site id
39
38
  @state = :stopped
39
+ if options[:collect]
40
+ @collector = RSMP::Collector.new self, options[:collect]
41
+ @collector.start
42
+ end
40
43
  end
41
44
 
42
45
  def inspect
@@ -49,19 +52,6 @@ module RSMP
49
52
  node.clock
50
53
  end
51
54
 
52
- def prepare_collection num
53
- if num
54
- @collector = RSMP::Collector.new self, num: num, ingoing: true, outgoing: true
55
- add_listener @collector
56
- end
57
- end
58
-
59
- def collect task, options, &block
60
- collector = RSMP::Collector.new self, options
61
- collector.collect task, &block
62
- collector
63
- end
64
-
65
55
  def run
66
56
  start
67
57
  @reader.wait if @reader
@@ -86,7 +76,7 @@ module RSMP
86
76
  return if @state == :stopped
87
77
  set_state :stopping
88
78
  stop_tasks
89
- notify_error DisonnectError.new("Connection was closed")
79
+ notify_error DisconnectError.new("Connection was closed")
90
80
  ensure
91
81
  close_socket
92
82
  clear
@@ -583,25 +573,27 @@ module RSMP
583
573
  end
584
574
 
585
575
  def wait_for_acknowledgement parent_task, options={}, m_id
586
- collect(parent_task,options.merge({
587
- type: ['MessageAck','MessageNotAck'],
588
- num: 1
589
- })) do |message|
576
+ collector = Collector.new self, options.merge(task: parent_task, type: ['MessageAck','MessageNotAck'])
577
+ collector.collect do |message|
590
578
  if message.is_a?(MessageNotAck)
591
579
  if message.attribute('oMId') == m_id
592
- # set result to an exception, but don't raise it.
593
- # this will be returned by the task and stored as the task result
594
- # when the parent task call wait() on the task, the exception
595
- # will be raised in the parent task, and caught by rspec.
596
- # rspec will then show the error and record the test as failed
597
580
  m_id_short = RSMP::Message.shorten_m_id m_id, 8
598
- result = RSMP::MessageRejected.new "Aggregated status request #{m_id_short} was rejected with '#{message.attribute('rea')}'"
599
- next true # done, no more messages wanted
581
+ raise RSMP::MessageRejected.new "Aggregated status request #{m_id_short} was rejected with '#{message.attribute('rea')}'"
600
582
  end
601
583
  elsif message.is_a?(MessageAck)
602
- next true if message.attribute('oMId') == m_id
584
+ collector.complete if message.attribute('oMId') == m_id
603
585
  end
604
- false
586
+ end
587
+ end
588
+
589
+ def send_and_optionally_collect message, options, &block
590
+ if options[:collect]
591
+ task = @task.async { |task| yield task }
592
+ send_message message, validate: options[:validate]
593
+ { sent: message, collector: task.wait }
594
+ else
595
+ send_message message, validate: options[:validate]
596
+ return { sent: message }
605
597
  end
606
598
  end
607
599
  end
data/lib/rsmp/site.rb CHANGED
@@ -95,7 +95,8 @@ module RSMP
95
95
  ip: supervisor_settings['ip'],
96
96
  port: supervisor_settings['port'],
97
97
  logger: @logger,
98
- archive: @archive
98
+ archive: @archive,
99
+ collect: @collect
99
100
  })
100
101
  @proxies << proxy
101
102
  @proxies_condition.signal
@@ -101,15 +101,13 @@ module RSMP
101
101
  "cId" => component,
102
102
  "mId" => m_id
103
103
  })
104
- if options[:collect]
105
- task = @task.async do |task|
106
- collect_aggregated_status task, options[:collect].merge(m_id: m_id)
107
- end
108
- send_message message, validate: options[:validate]
109
- return message, task.wait
110
- else
111
- send_message message, validate: options[:validate]
112
- message
104
+ send_and_optionally_collect message, options do |task|
105
+ collector = AggregatedStatusCollector.new(
106
+ self,
107
+ options[:collect].merge(task:@task,m_id: m_id, num:1)
108
+ )
109
+ collector.collect
110
+ collector
113
111
  end
114
112
  end
115
113
 
@@ -181,8 +179,14 @@ module RSMP
181
179
  "sS" => request_list,
182
180
  "mId" => m_id
183
181
  })
184
- send_while_collecting message, options do |task|
185
- collect_status_responses task, status_list, options[:collect].merge(m_id: m_id)
182
+ send_and_optionally_collect message, options do |task|
183
+ collector = StatusCollector.new(
184
+ self,
185
+ status_list,
186
+ options[:collect].merge(task:@task,m_id: m_id)
187
+ )
188
+ collector.collect
189
+ collector
186
190
  end
187
191
  end
188
192
 
@@ -193,13 +197,6 @@ module RSMP
193
197
  acknowledge message
194
198
  end
195
199
 
196
- def send_while_collecting message, options, &block
197
- task = @task.async { |task| yield task } if options[:collect]
198
- send_message message, validate: options[:validate]
199
- return message, task.wait if task
200
- message
201
- end
202
-
203
200
  def subscribe_to_status component_id, status_list, options={}
204
201
  validate_ready 'subscribe to status'
205
202
  m_id = options[:m_id] || RSMP::Message.make_m_id
@@ -218,8 +215,14 @@ module RSMP
218
215
  "sS" => subscribe_list,
219
216
  'mId' => m_id
220
217
  })
221
- send_while_collecting message, options do |task|
222
- collect_status_updates task, status_list, options[:collect].merge(m_id: m_id)
218
+ send_and_optionally_collect message, options do |task|
219
+ collector = StatusCollector.new(
220
+ self,
221
+ status_list,
222
+ options[:collect].merge(task:@task,m_id: m_id)
223
+ )
224
+ collector.collect
225
+ collector
223
226
  end
224
227
  end
225
228
 
@@ -264,8 +267,14 @@ module RSMP
264
267
  "arg" => command_list,
265
268
  "mId" => m_id
266
269
  })
267
- send_while_collecting message, options do |task|
268
- collect_command_responses task, command_list, options[:collect].merge(m_id: m_id)
270
+ send_and_optionally_collect message, options do |task|
271
+ collector = CommandResponseCollector.new(
272
+ self,
273
+ command_list,
274
+ options[:collect].merge(task:@task,m_id: m_id)
275
+ )
276
+ collector.collect
277
+ collector
269
278
  end
270
279
  end
271
280
 
@@ -342,29 +351,13 @@ module RSMP
342
351
  distribute_error e, options
343
352
  end
344
353
 
345
- def collect_alarms parent_task, options={}
346
- collect(parent_task,options.merge(type: "Alarm")) do |alarm|
354
+ def collect_alarms options={}
355
+ collect(@task,options.merge(type: "Alarm")) do |alarm|
347
356
  next if options[:aCId] && options[:aCId] != alarm.attribute("aCId")
348
357
  next if options[:aSp] && options[:aSp] != alarm.attribute("aSp")
349
358
  next if options[:aS] && options[:aS] != alarm.attribute("aS")
350
- true
359
+ :keep
351
360
  end
352
361
  end
353
-
354
- def collect_status_updates task, status_list, options
355
- StatusUpdateMatcher.new(self, status_list, options).collect task
356
- end
357
-
358
- def collect_status_responses task, status_list, options
359
- StatusResponseMatcher.new(self, status_list, options).collect task
360
- end
361
-
362
- def collect_command_responses task, command_list, options
363
- CommandResponseMatcher.new(self, command_list, options).collect task
364
- end
365
-
366
- def collect_aggregated_status task, options
367
- AggregatedStatusMatcher.new(self, options).collect task
368
- end
369
362
  end
370
363
  end
@@ -7,7 +7,6 @@ module RSMP
7
7
  attr_reader :rsmp_versions, :site_id, :supervisor_settings, :proxies, :logger
8
8
 
9
9
  def initialize options={}
10
-
11
10
  handle_supervisor_settings( options[:supervisor_settings] || {} )
12
11
  super options
13
12
  @proxies = []
@@ -161,7 +160,7 @@ module RSMP
161
160
  ip: info[:ip],
162
161
  port: info[:port],
163
162
  task: @task,
164
- settings: {'collect'=>@supervisor_settings['collect']},
163
+ collect: @collect,
165
164
  socket: socket,
166
165
  stream: stream,
167
166
  protocol: protocol,
@@ -138,16 +138,8 @@ module RSMP
138
138
  "mId" => m_id,
139
139
  })
140
140
 
141
- if options[:collect]
142
- result = nil
143
- task = @task.async do |task|
144
- wait_for_acknowledgement task, options[:collect], m_id
145
- end
146
- send_message message, validate: options[:validate]
147
- return message, task.wait
148
- else
149
- send_message message, validate: options[:validate]
150
- message
141
+ send_and_optionally_collect message, options do |task|
142
+ wait_for_acknowledgement task, options[:collect], m_id
151
143
  end
152
144
  end
153
145
 
@@ -282,7 +274,7 @@ module RSMP
282
274
  end
283
275
 
284
276
  def fetch_last_sent_status component, code, name
285
- @last_status_sent.dig component, code, name
277
+ @last_status_sent.dig component, code, name if @last_status_sent
286
278
  end
287
279
 
288
280
  def store_last_sent_status message
@@ -16,7 +16,7 @@ module RSMP
16
16
  return default unless plan.states
17
17
  states = plan.states[c_id]
18
18
  return default unless states
19
- state =states[pos]
19
+ state = states[pos]
20
20
  return default unless state =~ /[a-hA-G0-9N-P]/ # valid signal group states
21
21
  state
22
22
  end
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.7.5"
2
+ VERSION = "0.8.3"
3
3
  end
data/lib/rsmp.rb CHANGED
@@ -20,10 +20,14 @@ require 'rsmp/components'
20
20
  require 'rsmp/collect/notifier'
21
21
  require 'rsmp/collect/listener'
22
22
  require 'rsmp/collect/collector'
23
+ require 'rsmp/collect/state_collector'
24
+ require 'rsmp/collect/filter'
23
25
  require 'rsmp/collect/query'
24
- require 'rsmp/collect/matcher'
25
- require 'rsmp/collect/message_queries'
26
- require 'rsmp/collect/message_matchers'
26
+ require 'rsmp/collect/status_query'
27
+ require 'rsmp/collect/command_query'
28
+ require 'rsmp/collect/status_collector'
29
+ require 'rsmp/collect/command_response_collector'
30
+ require 'rsmp/collect/aggregated_status_collector'
27
31
  require 'rsmp/component'
28
32
  require 'rsmp/site'
29
33
  require 'rsmp/proxy'
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.7.5
4
+ version: 0.8.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: 2022-01-04 00:00:00.000000000 Z
11
+ date: 2022-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -201,18 +201,24 @@ files:
201
201
  - config/supervisor.yaml
202
202
  - config/tlc.yaml
203
203
  - documentation/classes_and_modules.md
204
+ - documentation/collecting_message.md
204
205
  - documentation/message_distribution.md
205
206
  - exe/rsmp
206
207
  - lib/rsmp.rb
207
208
  - lib/rsmp/archive.rb
208
209
  - lib/rsmp/cli.rb
210
+ - lib/rsmp/collect/aggregated_status_collector.rb
209
211
  - lib/rsmp/collect/collector.rb
212
+ - lib/rsmp/collect/command_query.rb
213
+ - lib/rsmp/collect/command_response_collector.rb
214
+ - lib/rsmp/collect/filter.rb
210
215
  - lib/rsmp/collect/listener.rb
211
- - lib/rsmp/collect/matcher.rb
212
216
  - lib/rsmp/collect/message_matchers.rb
213
- - lib/rsmp/collect/message_queries.rb
214
217
  - lib/rsmp/collect/notifier.rb
215
218
  - lib/rsmp/collect/query.rb
219
+ - lib/rsmp/collect/state_collector.rb
220
+ - lib/rsmp/collect/status_collector.rb
221
+ - lib/rsmp/collect/status_query.rb
216
222
  - lib/rsmp/component.rb
217
223
  - lib/rsmp/components.rb
218
224
  - lib/rsmp/convert/export/json_schema.rb