rsmp 0.7.5 → 0.8.3

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: ca0e580278192b1577388628e8a761a8b0fe61f175c40bdd6c40fc62ab61d700
4
- data.tar.gz: 0dd69084856cd0ba08acd74655c6a856bc6222a00bfbfb0031aff24c8df2c17a
3
+ metadata.gz: f54121873905da2e5ffa4914f4f454fc4b59c7283e482b6b89b4035d686b7779
4
+ data.tar.gz: 523d2e310ebec8f4df07592fcb501d91f604ba8ea1c4625482c7d8d011340a6f
5
5
  SHA512:
6
- metadata.gz: 4fa7f6e6f31e8d47369fb769a95d3a519262098d0821387ddfc29ef865e08ccd8f0cd49f65697eeb3ea28e0fb33783291feb2be9706784fc53891c4aaf8f6b66
7
- data.tar.gz: 10b21ec864bb578e281686f1926303741d3182f42a2d6a82bb7a90f744fd4b50cfd704eeb773da99d96cdc1796a1876ea2b7f9d0296f303c4644d132f1d46761
6
+ metadata.gz: 807d2283a18f4a9c4e45594d4ae85e75464cde3792eb941342a825e8765a00d21f7d541fac03191680e28eb7e4af4c6624cb6ce80486da191cf3bc2b3f2d6431
7
+ data.tar.gz: 6adc50becc91e2deab2c8099808a492a2440d072188227147742bd51ec1310f8a1075e3bed72f2989581ba11125b9beeda8134704d8a42e131ac1dac9a76eca1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.7.5)
4
+ rsmp (0.8.3)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.1)
7
7
  colorize (~> 0.8.1)
data/config/tlc.yaml CHANGED
@@ -21,10 +21,10 @@ signal_plans:
21
21
  1: 0
22
22
  2: 5
23
23
  states:
24
- A1: '11NBBB'
25
- A2: '1NBBBB'
26
- B1: 'BBB11N'
27
- B2: 'BBB1NB'
24
+ A1: '123efg'
25
+ A2: '123efg'
26
+ B1: '123efg'
27
+ B2: '123efg'
28
28
  2:
29
29
  states:
30
30
  A1: '111NBB'
@@ -19,9 +19,6 @@ Handle logging.
19
19
  ### Wait
20
20
  Handles waiting for an async condition and block.
21
21
 
22
- ### SiteProxyWait
23
- Handles waiting for different types of messages and responses from a remote site.
24
-
25
22
  ### Components
26
23
  Component handling.
27
24
 
@@ -38,7 +35,7 @@ A Site has one or more SupervisorProxies (connections to supervisor).
38
35
 
39
36
  A site has one of more components.
40
37
 
41
- ### Supervisor
38
+ ### Supervisor
42
39
  A Supervisor represents an RSMP supervisor, typically a central supervisor system. An RSMP supervisor can handle connections one or more sites.
43
40
 
44
41
  A Supervisor has one or more SiteProxies (connections to sites).
@@ -0,0 +1,196 @@
1
+ # Collection
2
+ You often need to collect messages or responses. The collector classes are used to collect message asyncronously. Other tasks continue until the collection completes, time outs or is cancelled.
3
+
4
+ A collector can collect ingoing and/or outgoing messages.
5
+
6
+ An object that includes the Notifier module (or implements the same functionality) must be provided when you construct a Collected. The collector will attach itself to this notifier when it starts collecting, to receive messages. The SiteProxy and SupervisorProxy classes both include the Notifier module, and can therefore be used as message sources.
7
+
8
+ Messages that match the relevant criteria are stored by the collector.
9
+
10
+ When the collection is done, the collector detaches from the notifier, and returns the status.
11
+
12
+
13
+ ## Collector
14
+ Class uses for collecting messages filtered by message type, direction and/or component id. A block can be used for custom filtering.
15
+
16
+ You can choose to collect a specific number of message and/or for a specific duration.
17
+
18
+ A collector has a status, which is `:ready` initialialy. When you start collecting, it changes to `:collecting`. It will be `:ok` once collection completes successfully, or `:cancel` if it was cancelled to to some error or by a filter block.
19
+
20
+ ### Initialization
21
+ When you create a collector, you specify the messages types you want to collect.
22
+ You can also specify ingoing and/or outgoing direction and the RSMP component.
23
+
24
+ ```ruby
25
+ collector = MessageCollector.new notifier, num: 10, ingoing: true, outgoing: true
26
+ ```
27
+
28
+ num: The number of messages to collect. If not provided, a timeout must be set instead.
29
+ timeout: The number of seconds to collect
30
+ ingoing: Whether to collect ingoing messages. Defaults to true
31
+ outgoing: Whether to collect outgoing messages. Defaults to true
32
+ component: An RSMP component id.
33
+
34
+ ### Collecting
35
+ Use collect() to start collecting and wait for completion or timeout. The status will be returned.
36
+
37
+ ```ruby
38
+ result = collector.collect # => :ok, :timeout or :cancelled
39
+ collector.messages # => collected messages
40
+ ```
41
+
42
+ If you want start collection, but not wait for the result, use `start()`. You can then later use `wait()` if you want:
43
+
44
+ ```ruby
45
+ result = collector.start # => nil
46
+ # do other stuff
47
+ result = collector.wait
48
+ ```
49
+
50
+ ### Custom filtering
51
+ You can use a block to do extra filtering. The block will be callled for each messages that fulfils the correct message type, direction and component id.
52
+
53
+ The block must return nil or a list of symbols to indicate whether the message should be kept, and whether collection should be cancelled.
54
+
55
+ ```ruby
56
+ result = collector.collect do |message|
57
+ :keep, :cancel # example of how to keep the message and cancel collection
58
+ end
59
+ ```
60
+
61
+ `:keep` keeps (collect) this message
62
+ `:cancel` cancel collection
63
+
64
+ Note that you cannot use `return` in a block. You can either simply provide the values as the last expresssion in the block, or use next().
65
+
66
+ Exceptions in the block will cause the collector to abort. If the collect! or wait! variants are used, the exception is propagated to the caller.
67
+
68
+ ### Bang version
69
+ The method collect!() will raise exceptions in case of errors, and will return the collect message directly.
70
+
71
+ ```ruby
72
+ message = collector.collect # => collected message.
73
+ ```
74
+
75
+ Similar, `wait!()` will raise an exception in case of timeouts or errors:
76
+
77
+ ```ruby
78
+ message = collector.wait! # => collected message.
79
+ ```
80
+
81
+
82
+ ### Schema Errors and Disconnects
83
+ The collector can optionally cancel collection in special cases, controlled by the `:cancel` option provided when contructing the collector.
84
+
85
+ ```ruby
86
+ options = {
87
+ cancel: {
88
+ disconnect: true,
89
+ schema_error: true
90
+ }
91
+ }
92
+ result = collector.collect options
93
+ ```
94
+
95
+ disconnect: If the proxy which provides messages experience a disconnect, the collector will cancel collection.
96
+
97
+ schema_error: If the proxy receives a message with a schema error, the collector will cancel collection, if the the invalid message has the correct message type.
98
+
99
+ ### NotAck
100
+ A typical scenaria is that you send a command or status request, and want to collect the response. But if the original message is rejected by the site, you will received a NotAck instead of a reply. The collector classes can handle this, as long as you provide the message id of the original request in the `m_id` key of teh options when you construct the collector.
101
+
102
+ If a NotAck is received with a matching `oMId` (original message id), the collection is cancelled.
103
+
104
+ ## StatusCollector
105
+ Waits for a set of status criteria to be met.
106
+
107
+ Note that a single RSMP status message can contain multiple status items. Unlike MessageCollector, a StatusCollector therefore operates on items, rather than messages, and you can't specify a number of messages to collect.
108
+
109
+
110
+ ### Criteria
111
+ You construct a StatusCollector with set of criteria, specifying the status codes, names, and optionally values that must be met.
112
+
113
+ ### Collecting
114
+ When you start collection, it will complete once all criteria are all fulfilled, the timeout is reached or a custom filtering block aborts the collection.
115
+
116
+ ```ruby
117
+ collector = StatusCollector.new(options)
118
+ result = matcher.collect(timeout: 5)
119
+ ```
120
+
121
+ ### Custom filtering
122
+ You can use a block to do extra filtering. The block will be called for each individual status item that fulfils all criteria, like status code and name, component, etc.
123
+
124
+ Like with MessageCollector, the block must return a hash specifing whether to keep the message and whether to continue collection.
125
+
126
+ ```ruby
127
+ matcher = StatusCollector.new(options)
128
+ result = matcher.collect(options) do |message,item|
129
+ next(:keep) if good_item?(item) # keep item
130
+ end
131
+ ```
132
+
133
+ ## Subscribing to status updates
134
+ The method `subscribe_to_status` can be used to subscribe to one of more status messages.
135
+
136
+ ### Without collection
137
+ The simple form sends an RSMP status subscription message to the site and then returns immediatly. To collect incoming status messages, you need to manually use e.g. a Collector.
138
+
139
+ A hash is returned, with `:sent` containing the send subscription messages.
140
+
141
+ ```ruby
142
+ options = {
143
+ list: [{'sCI'=>'S0001','n'=>'signalgroupstatus'}],
144
+ }
145
+ result = subscribe_to_status(options)
146
+ result.keys => # [:sent]
147
+ ```
148
+
149
+ Note: If you want to use this simple form and manually collect responses, it's best to start collection in an asyncronous task _before_ you subscribe, to make sure you don't miss early responses:
150
+
151
+ ```ruby
152
+ task = async do
153
+ MessageCollector.new(options).collect(num: 5, timeout:10) # start listening for status messages
154
+ end
155
+ result = subscribe_to_status(options) # subscribe
156
+ task.wait # wait for collection task to complete (or time out)
157
+ ```
158
+
159
+ ### With collection
160
+ If you provide `:collect` options, it will be used to construct a StatusCollector for collecting the relevant status messages. When collection completes the collector is returned in the `:collector` key:
161
+
162
+ ```ruby
163
+ options = {
164
+ list: [{'sCI'=>'S0001','n'=>'signalgroupstatus'}],
165
+ collect: {timeout: 5}
166
+ }
167
+ result = subscribe_to_status(options)
168
+ result.keys => # [:sent, :collector]
169
+ result[:collector].messages # => list of collected messages
170
+ ```
171
+
172
+ You can pass you own collector which will give you more control of how to collect the incoming status messages:
173
+
174
+ ```ruby
175
+ collector = Collector.new(options)
176
+ options = {collect: collector}
177
+ result = subscribe_to_status(options)
178
+ result.keys => # [:sent, :collector]
179
+ result[:collector].messages # => list of collected messages
180
+ ```
181
+
182
+ ### Processing responses
183
+ If you pass a block, the block will be used to construct a collector. The block will be called for each matching status item received.
184
+ Collection will continue until the block returns :cancel, or it times.
185
+
186
+ ```ruby
187
+ options = {
188
+ list: [{'sCI'=>'S0001','n'=>'signalgroupstatus'}]
189
+ }
190
+ result = subscribe_to_status(options) do |message|
191
+ # do something with message
192
+ :keep # or not
193
+ end
194
+ result.keys => # [:sent, :collector]
195
+ ```
196
+
@@ -0,0 +1,9 @@
1
+ module RSMP
2
+ # Class for waiting for an aggregated status response
3
+ class AggregatedStatusCollector < Collector
4
+ def initialize proxy, options={}
5
+ required = { type: ['AggregatedStatus','MessageNotAck'], title: 'aggregated status' }
6
+ super proxy, options.merge(required)
7
+ end
8
+ end
9
+ end
@@ -1,12 +1,13 @@
1
1
  module RSMP
2
2
 
3
- # Collects ingoing and/or outgoing messages from a notifier.
4
- # Can filter by message type and wakes up the client once the desired number of messages has been collected.
3
+ # Collects messages from a notifier.
4
+ # Can filter by message type, componet and direction.
5
+ # Wakes up the once the desired number of messages has been collected.
5
6
  class Collector < Listener
6
- attr_reader :condition, :messages, :done
7
+ attr_reader :condition, :messages, :status, :error, :task
7
8
 
8
- def initialize proxy, options={}
9
- super proxy, options
9
+ def initialize notifier, options={}
10
+ super notifier, options
10
11
  @options = {
11
12
  cancel: {
12
13
  schema_error: true,
@@ -17,16 +18,59 @@ module RSMP
17
18
  @outgoing = options[:outgoing] == nil ? false : options[:outgoing]
18
19
  @condition = Async::Notification.new
19
20
  @title = options[:title] || [@options[:type]].flatten.join('/')
20
- @options[:timeout] ||= 1
21
- @options[:num] ||= 1
21
+ if options[:task]
22
+ @task = options[:task]
23
+ else
24
+ # if notifier is a Proxy, or some other object that implements task(),
25
+ # then try to get the task that way
26
+ if notifier.respond_to? 'task'
27
+ @task = notifier.task
28
+ end
29
+ end
22
30
  reset
23
31
  end
24
32
 
33
+ def use_task task
34
+ @task = task
35
+ end
36
+
37
+ # Clear all query results
38
+ def reset
39
+ @messages = []
40
+ @error = nil
41
+ @status = :ready
42
+ end
43
+
25
44
  # Inspect formatter that shows the message we have collected
26
45
  def inspect
27
46
  "#<#{self.class.name}:#{self.object_id}, #{inspector(:@messages)}>"
28
47
  end
29
48
 
49
+ # Is collection active?
50
+ def collecting?
51
+ @status == :collecting
52
+ end
53
+
54
+ # Is collection active?
55
+ def ok?
56
+ @status == :ok
57
+ end
58
+
59
+ # Has collection time out?
60
+ def timeout?
61
+ @status == :timeout
62
+ end
63
+
64
+ # Is collection ready to start?
65
+ def ready?
66
+ @status == :ready
67
+ end
68
+
69
+ # Has collection been cancelled?
70
+ def cancelled?
71
+ @status == :cancelled
72
+ end
73
+
30
74
  # Want ingoing messages?
31
75
  def ingoing?
32
76
  @ingoing == true
@@ -37,91 +81,104 @@ module RSMP
37
81
  @outgoing == true
38
82
  end
39
83
 
40
- # Block until all messages have been collected
41
- def wait
42
- @condition.wait
84
+ # Collect message
85
+ # Will return once all messages have been collected, or timeout is reached
86
+ def collect &block
87
+ start &block
88
+ wait
89
+ @status
90
+ ensure
91
+ @notifier.remove_listener self if @notifier
43
92
  end
44
93
 
45
94
  # Collect message
46
- # Will block until all messages have been collected,
47
- # or we time out
48
- def collect task, options={}, &block
49
- @options.merge! options
50
- @block = block
51
- unless @done
52
- listen do
53
- task.with_timeout(@options[:timeout]) do
54
- @condition.wait
55
- end
56
- end
95
+ # Returns the collected messages, or raise an exception in case of a time out.
96
+ def collect! &block
97
+ if collect(&block) == :timeout
98
+ raise RSMP::TimeoutError.new describe_progress
57
99
  end
58
- return @error if @error
59
- self
60
- rescue Async::TimeoutError
61
- str = "#{@title.capitalize} collection"
62
- str << " in response to #{options[:m_id]}" if options[:m_id]
63
- str << " didn't complete within #{@options[:timeout]}s"
64
- reached = progress
65
- str << ", reached #{progress[:reached]}/#{progress[:need]}"
66
- raise RSMP::TimeoutError.new str
100
+ @messages
67
101
  end
68
102
 
69
- # Return progress as collected vs. number requested
70
- def progress
71
- need = @options[:num]
72
- reached = @messages.size
73
- { need: need, got: reached }
103
+ # If collection is not active, return status immeditatly. Otherwise wait until
104
+ # the desired messages have been collected, or timeout is reached.
105
+ def wait
106
+ if collecting?
107
+ if @options[:timeout]
108
+ @task.with_timeout(@options[:timeout]) { @condition.wait }
109
+ else
110
+ @condition.wait
111
+ end
112
+ end
113
+ @status
114
+ rescue Async::TimeoutError
115
+ @status = :timeout
74
116
  end
75
117
 
76
- # Get the collected message.
77
- def message
78
- @messages.first
118
+ # If collection is not active, raise an error. Otherwise wait until
119
+ # the desired messages have been collected.
120
+ # If timeout is reached, an exceptioin is raised.
121
+ def wait!
122
+ wait
123
+ raise RSMP::TimeoutError.new(describe_progress) if timeout?
124
+ @messages
79
125
  end
80
126
 
81
- # Get the collected messages.
82
- def messages
83
- @messages
127
+ # Start collection and return immediately
128
+ # You can later use wait() to wait for completion
129
+ def start &block
130
+ raise RuntimeError.new("Can't begin unless ready (currenty #{@status})") unless ready?
131
+ @block = block
132
+ raise ArgumentError.new("Num, timeout or block must be provided") unless @options[:num] || @options[:timeout] || @block
133
+ reset
134
+ @status = :collecting
135
+ @notifier.add_listener self if @notifier
84
136
  end
85
137
 
86
- # Clear all query results
87
- def reset
88
- @messages = []
89
- @error = nil
90
- @done = false
138
+ # Build a string describing how how progress reached before timeout
139
+ def describe_progress
140
+ str = "#{@title.capitalize} collection "
141
+ str << "in response to #{@options[:m_id]} " if @options[:m_id]
142
+ str << "didn't complete within #{@options[:timeout]}s, "
143
+ str << "reached #{@messages.size}/#{@options[:num]}"
144
+ str
91
145
  end
92
146
 
93
147
  # Check if we receive a NotAck related to initiating request, identified by @m_id.
94
- def check_not_ack message
148
+ def reject_not_ack message
95
149
  return unless @options[:m_id]
96
150
  if message.is_a?(MessageNotAck)
97
151
  if message.attribute('oMId') == @options[:m_id]
98
152
  m_id_short = RSMP::Message.shorten_m_id @options[:m_id], 8
99
- @error = RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected with '#{message.attribute('rea')}'")
100
- complete
153
+ cancel RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected with '#{message.attribute('rea')}'")
154
+ true
101
155
  end
102
- false
103
156
  end
104
157
  end
105
158
 
106
159
  # Handle message. and return true when we're done collecting
107
160
  def notify message
108
161
  raise ArgumentError unless message
109
- raise RuntimeError.new("can't process message when already done") if @done
110
- check_not_ack(message)
111
- return true if @done
112
- check_match message
113
- complete if done?
114
- @done
162
+ raise RuntimeError.new("can't process message when status is :#{@status}, title: #{@title}, desc: #{describe}") unless ready? || collecting?
163
+ perform_match message
164
+ @status
165
+ end
166
+
167
+ def describe
115
168
  end
116
169
 
117
170
  # Match message against our collection criteria
118
- def check_match message
119
- matched = match? message
120
- if matched == true
171
+ def perform_match message
172
+ return false if reject_not_ack(message)
173
+ return false unless type_match?(message)
174
+ if @block
175
+ status = [@block.call(message)].flatten
176
+ return unless collecting?
177
+ keep message if status.include?(:keep)
178
+ else
121
179
  keep message
122
- elsif matched == false
123
- forget message
124
180
  end
181
+ complete if done?
125
182
  end
126
183
 
127
184
  # Have we collected the required number of messages?
@@ -132,18 +189,24 @@ module RSMP
132
189
  # Called when we're done collecting. Remove ourself as a listener,
133
190
  # se we don't receive message notifications anymore
134
191
  def complete
135
- @done = true
136
- @proxy.remove_listener self
192
+ @status = :ok
193
+ do_stop
194
+ end
195
+
196
+ # Remove ourself as a listener, so we don't receive message notifications anymore,
197
+ # and wake up the async condition
198
+ def do_stop
199
+ @notifier.remove_listener self
137
200
  @condition.signal
138
201
  end
139
202
 
140
- # The proxy experienced some error.
141
- # Check if this should cause us to cancel.
203
+ # An error occured upstream.
204
+ # Check if we should cancel.
142
205
  def notify_error error, options={}
143
206
  case error
144
207
  when RSMP::SchemaError
145
208
  notify_schema_error error, options
146
- when RSMP::ConnectionError
209
+ when RSMP::DisconnectError
147
210
  notify_disconnect error, options
148
211
  end
149
212
  end
@@ -154,24 +217,23 @@ module RSMP
154
217
  message = options[:message]
155
218
  return unless message
156
219
  klass = message.class.name.split('::').last
157
- return unless [@options[:type]].flatten.include? klass
158
- @proxy.log "Collect cancelled due to schema error in #{klass} #{message.m_id_short}", level: :debug
220
+ return unless @options[:type] == nil || [@options[:type]].flatten.include?(klass)
221
+ @notifier.log "Collection cancelled due to schema error in #{klass} #{message.m_id_short}", level: :debug
159
222
  cancel error
160
223
  end
161
224
 
162
225
  # Cancel if we received e notificaiton about a disconnect
163
226
  def notify_disconnect error, options
164
227
  return unless @options.dig(:cancel,:disconnect)
165
- @proxy.log "Collect cancelled due to a connection error: #{error.to_s}", level: :debug
228
+ @notifier.log "Collection cancelled due to a connection error: #{error.to_s}", level: :debug
166
229
  cancel error
167
230
  end
168
231
 
169
232
  # Abort collection
170
- def cancel error
171
- @error = error if error
172
- @done = false
173
- @proxy.remove_listener self
174
- @condition.signal
233
+ def cancel error=nil
234
+ @error = error
235
+ @status = :cancelled
236
+ do_stop
175
237
  end
176
238
 
177
239
  # Store a message in the result array
@@ -179,30 +241,20 @@ module RSMP
179
241
  @messages << message
180
242
  end
181
243
 
182
- # Remove a message from the result array
183
- def forget message
184
- @messages.delete message
185
- end
186
-
187
244
  # Check a message against our match criteria
188
- # Return true if there's a match
189
- def match? message
190
- raise ArgumentError unless message
191
- return if message.direction == :in && @ingoing == false
192
- return if message.direction == :out && @outgoing == false
245
+ # Return true if there's a match, false if not
246
+ def type_match? message
247
+ return false if message.direction == :in && @ingoing == false
248
+ return false if message.direction == :out && @outgoing == false
193
249
  if @options[:type]
194
- return if message == nil
195
250
  if @options[:type].is_a? Array
196
- return unless @options[:type].include? message.type
251
+ return false unless @options[:type].include? message.type
197
252
  else
198
- return unless message.type == @options[:type]
253
+ return false unless message.type == @options[:type]
199
254
  end
200
255
  end
201
256
  if @options[:component]
202
- return if message.attributes['cId'] && message.attributes['cId'] != @options[:component]
203
- end
204
- if @block
205
- return if @block.call(message) == false
257
+ return false if message.attributes['cId'] && message.attributes['cId'] != @options[:component]
206
258
  end
207
259
  true
208
260
  end
@@ -0,0 +1,16 @@
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
+ end
@@ -0,0 +1,20 @@
1
+ module RSMP
2
+ # Class for waiting for specific command responses
3
+ class CommandResponseCollector < StateCollector
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
+ end
@@ -0,0 +1,31 @@
1
+ module RSMP
2
+
3
+ # Filter messages based on type, direction and component id.
4
+ # Used by Collectors.
5
+ class Filter
6
+ def initialize ingoing:true, outgoing:true, type:, component:nil
7
+ @ingoing = ingoing
8
+ @outgoing = outgoing
9
+ @type = type
10
+ @component = component
11
+ end
12
+
13
+ # Check a message against our match criteria
14
+ # Return true if there's a match, false if not
15
+ def accept? message
16
+ return false if message.direction == :in && @ingoing == false
17
+ return false if message.direction == :out && @outgoing == false
18
+ if @type
19
+ if @type.is_a? Array
20
+ return false unless @type.include? message.type
21
+ else
22
+ return false unless message.type == @type
23
+ end
24
+ end
25
+ if @component
26
+ return false if message.attributes['cId'] && message.attributes['cId'] != @component
27
+ end
28
+ true
29
+ end
30
+ end
31
+ end