rsmp 0.51.4 → 0.52.0
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/documentation/collecting_message.md +112 -0
- data/lib/rsmp/collect/collector.rb +6 -0
- data/lib/rsmp/collect/queue.rb +4 -0
- data/lib/rsmp/collect/status_collector.rb +2 -2
- data/lib/rsmp/proxy/proxy.rb +8 -2
- data/lib/rsmp/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cfba3255efe256eae701725584e74d80a7ba66fe94708ef9bdc76cbd678c7700
|
|
4
|
+
data.tar.gz: b0aebcd26383d1ed77fbcdd18351fecc0a7afcc962d582f17a3f488a53aaeb22
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7796d54dbed77a9d230a4e49f3ddadd22b3833b29fa05c882f9d7a6c540ed64ae55745f5b8dbe38a9fe095fa49b45684f9ebaf0a954d9fa021d892f2bdc5cec
|
|
7
|
+
data.tar.gz: 5bf194b21059fd35d82e41093c68658585fe083cc061f5759e98d95df1f45e5fbd0958051cb3dbac8b771f915fc0511c056f72c887339f1b5df6c60f73d6a57f
|
data/CHANGELOG.md
CHANGED
|
@@ -729,3 +729,9 @@ Initial release.
|
|
|
729
729
|
## 0.51.4
|
|
730
730
|
- don't update subscription list until unsubscribe is acknowledged
|
|
731
731
|
|
|
732
|
+
## 0.52.0
|
|
733
|
+
- allow the proxy's `collect:` option to accept a Proc that builds a collector or queue before the handshake
|
|
734
|
+
- add optional `predicate:` filtering to collectors, including status collectors
|
|
735
|
+
- add `start` and `stop` aliases to queues for use with proxy collection factories
|
|
736
|
+
- fix status collectors to honor `component:` and `responses:`; the misspelled `reponses:` option is no longer used
|
|
737
|
+
|
data/Gemfile.lock
CHANGED
|
@@ -112,6 +112,118 @@ result = collector.collect do |message|
|
|
|
112
112
|
end
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
### Message predicates
|
|
116
|
+
|
|
117
|
+
Use `predicate:` for conditions beyond the message type, direction, and component
|
|
118
|
+
handled by `RSMP::Filter`. The Proc receives a whole message after the filter
|
|
119
|
+
accepts it. Returning `false` or `nil` skips the message before collection
|
|
120
|
+
callbacks or state-item matching; earlier item matches remain intact.
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
collector = RSMP::Collector.new(
|
|
124
|
+
proxy,
|
|
125
|
+
filter: RSMP::Filter.new(type: 'StatusUpdate', ingoing: true, outgoing: false),
|
|
126
|
+
predicate: ->(message) { message.is_a?(RSMP::StatusUpdate) && message.attribute('sS').any? },
|
|
127
|
+
num: 1,
|
|
128
|
+
timeout: 5
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Predicates also work with `StatusCollector`. They do not suppress failures such
|
|
133
|
+
as a rejection of the initiating request or an invalid peer message. `Filter`
|
|
134
|
+
admits `MessageNotAck` even when a different message type is requested, so a
|
|
135
|
+
predicate that accesses type-specific attributes should check the message type.
|
|
136
|
+
|
|
137
|
+
### Status collection
|
|
138
|
+
|
|
139
|
+
`StatusCollector` matches wanted status items within incoming messages. Both
|
|
140
|
+
`StatusUpdate` and `StatusResponse` are accepted by default. Set `responses: false`
|
|
141
|
+
to accept updates only, or `updates: false` to accept responses only.
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
want = [{ 'sCI' => 'S0001', 'n' => 'signalgroupstatus' }]
|
|
145
|
+
collector = RSMP::StatusCollector.new(
|
|
146
|
+
proxy, want, component: 'C1', responses: false, timeout: 5
|
|
147
|
+
)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`component:` filters the message's `cId`; the wanted items describe entries in
|
|
151
|
+
`sS`, which do not have their own component ID. Collection completes when all
|
|
152
|
+
wanted items match, rather than after a fixed number of messages.
|
|
153
|
+
|
|
154
|
+
### Collection during proxy setup
|
|
155
|
+
|
|
156
|
+
The proxy's `collect:` option accepts the existing collector options hash:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
proxy_options = {
|
|
160
|
+
collect: {
|
|
161
|
+
filter: RSMP::Filter.new(type: 'StatusUpdate', ingoing: true, outgoing: false),
|
|
162
|
+
num: 1,
|
|
163
|
+
timeout: 5
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
It also accepts a Proc that receives the new proxy and returns a collector or
|
|
169
|
+
queue. The proxy calls `start` on the returned object and exposes it through
|
|
170
|
+
`proxy.collector`. This starts receiving before the handshake can deliver
|
|
171
|
+
messages. Return an unstarted object; the factory runs before version negotiation
|
|
172
|
+
and should not rely on the proxy being fully initialized or connected.
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
proxy_options = {
|
|
176
|
+
collect: proc do |proxy|
|
|
177
|
+
RSMP::StatusCollector.new(
|
|
178
|
+
proxy,
|
|
179
|
+
[{ 'sCI' => 'S0001', 'n' => 'signalgroupstatus' }],
|
|
180
|
+
component: 'C1', responses: false, timeout: 5
|
|
181
|
+
)
|
|
182
|
+
end
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Pass these options when creating the proxy. Use `proxy.collector.wait` or
|
|
187
|
+
`wait!` for a collector, or `wait_for_message` or `wait_for_message!` for a queue.
|
|
188
|
+
|
|
189
|
+
## Queues
|
|
190
|
+
|
|
191
|
+
`RSMP::Queue` retains accepted messages until consumed, including messages that
|
|
192
|
+
arrive before the caller starts waiting. Each wait returns one message, rather
|
|
193
|
+
than a collection. `start` and `stop` are aliases for `start_receiving` and
|
|
194
|
+
`stop_receiving`, so a queue can also be returned by a proxy's `collect:` factory.
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
queue = RSMP::Queue.new(proxy, filter: RSMP::Filter.new(type: 'StatusUpdate'))
|
|
198
|
+
queue.start
|
|
199
|
+
begin
|
|
200
|
+
result = queue.wait_for_message(timeout: 5)
|
|
201
|
+
puts result.value if result.success?
|
|
202
|
+
ensure
|
|
203
|
+
queue.stop
|
|
204
|
+
end
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
A queue stays registered until stopped. Its `timeout:` applies to an individual
|
|
208
|
+
wait: expiry returns a failure with code `:timeout`, or raises
|
|
209
|
+
`RSMP::OperationError` through `wait_for_message!`.
|
|
210
|
+
|
|
211
|
+
An enclosing Async timeout raised while waiting in the queue is converted in
|
|
212
|
+
the same way, even when no queue timeout is supplied:
|
|
213
|
+
|
|
214
|
+
```ruby
|
|
215
|
+
begin
|
|
216
|
+
message = Async::Task.current.with_timeout(5) { queue.wait_for_message! }
|
|
217
|
+
rescue RSMP::OperationError => error
|
|
218
|
+
raise unless error.failure.code == :timeout
|
|
219
|
+
|
|
220
|
+
warn 'The caller deadline expired'
|
|
221
|
+
end
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
This example assumes the queue is already started. Both timeout sources use the
|
|
225
|
+
same failure code; `failure.cause` retains the original Async exception.
|
|
226
|
+
|
|
115
227
|
## Sending and collecting atomically
|
|
116
228
|
|
|
117
229
|
High-level send methods follow the same non-bang/bang convention:
|
|
@@ -7,6 +7,9 @@ module RSMP
|
|
|
7
7
|
|
|
8
8
|
attr_reader :messages, :m_id, :initiator
|
|
9
9
|
|
|
10
|
+
# :predicate optionally receives each message accepted by the filter. A falsey
|
|
11
|
+
# result skips the message before collection callbacks or item matching.
|
|
12
|
+
# Rejection and invalid-message failures are handled independently of it.
|
|
10
13
|
def initialize(distributor, options = {})
|
|
11
14
|
initialize_receiver distributor, filter: options[:filter]
|
|
12
15
|
@options = {
|
|
@@ -17,6 +20,7 @@ module RSMP
|
|
|
17
20
|
}.deep_merge(options)
|
|
18
21
|
@timeout = options[:timeout]
|
|
19
22
|
@num = options[:num]
|
|
23
|
+
@predicate = options[:predicate]
|
|
20
24
|
@initiator = options[:initiator]
|
|
21
25
|
@m_id = options[:m_id] || @initiator&.attributes&.dig('mId')
|
|
22
26
|
make_title(options[:title])
|
|
@@ -131,6 +135,8 @@ module RSMP
|
|
|
131
135
|
def perform_match?(message)
|
|
132
136
|
return false if reject_not_ack?(message)
|
|
133
137
|
return false unless acceptable?(message)
|
|
138
|
+
return false if @predicate && !@predicate.call(message)
|
|
139
|
+
return false unless active?
|
|
134
140
|
|
|
135
141
|
if @block
|
|
136
142
|
status = Array(@block.call(message))
|
data/lib/rsmp/collect/queue.rb
CHANGED
|
@@ -7,6 +7,10 @@ module RSMP
|
|
|
7
7
|
|
|
8
8
|
attr_reader :messages
|
|
9
9
|
|
|
10
|
+
# Allow queues to be started by a proxy's collect factory, like collectors.
|
|
11
|
+
alias start start_receiving
|
|
12
|
+
alias stop stop_receiving
|
|
13
|
+
|
|
10
14
|
def initialize(distributor, filter: nil)
|
|
11
15
|
initialize_receiver distributor, filter: filter
|
|
12
16
|
@condition = Async::Notification.new
|
|
@@ -4,11 +4,11 @@ module RSMP
|
|
|
4
4
|
def initialize(proxy, want, options = {})
|
|
5
5
|
type = []
|
|
6
6
|
type << 'StatusUpdate' unless options[:updates] == false
|
|
7
|
-
type << 'StatusResponse' unless options[:
|
|
7
|
+
type << 'StatusResponse' unless options[:responses] == false
|
|
8
8
|
|
|
9
9
|
super(proxy, want, options.merge(
|
|
10
10
|
title: 'status response',
|
|
11
|
-
filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: type)
|
|
11
|
+
filter: RSMP::Filter.new(ingoing: true, outgoing: false, type: type, component: options[:component])
|
|
12
12
|
))
|
|
13
13
|
end
|
|
14
14
|
|
data/lib/rsmp/proxy/proxy.rb
CHANGED
|
@@ -106,9 +106,15 @@ module RSMP
|
|
|
106
106
|
@rejected_sxls = []
|
|
107
107
|
@receive_alarms = true
|
|
108
108
|
@site_settings = nil # can't pick until we know the site id
|
|
109
|
-
|
|
109
|
+
collect = options[:collect]
|
|
110
|
+
return unless collect
|
|
111
|
+
|
|
112
|
+
@collector = if collect.is_a?(Proc)
|
|
113
|
+
collect.call(self)
|
|
114
|
+
else
|
|
115
|
+
RSMP::Collector.new self, collect
|
|
116
|
+
end
|
|
110
117
|
|
|
111
|
-
@collector = RSMP::Collector.new self, options[:collect]
|
|
112
118
|
@collector.start
|
|
113
119
|
end
|
|
114
120
|
|
data/lib/rsmp/version.rb
CHANGED