rsmp 0.7.2 → 0.8.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/.ruby-version +1 -0
- data/Gemfile.lock +5 -4
- data/lib/rsmp/cli.rb +4 -0
- data/lib/rsmp/collect/collector.rb +103 -84
- data/lib/rsmp/collect/listener.rb +9 -4
- data/lib/rsmp/collect/matcher.rb +12 -13
- data/lib/rsmp/collect/message_collector.rb +209 -0
- data/lib/rsmp/collect/message_queries.rb +1 -1
- data/lib/rsmp/collect/query.rb +2 -2
- data/lib/rsmp/error.rb +1 -1
- data/lib/rsmp/logger.rb +2 -4
- data/lib/rsmp/node.rb +3 -1
- data/lib/rsmp/proxy.rb +6 -10
- data/lib/rsmp/site_proxy.rb +26 -21
- data/lib/rsmp/supervisor.rb +1 -2
- data/lib/rsmp/supervisor_proxy.rb +6 -5
- data/lib/rsmp/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9614e6db6381449fa893901766de8239b7bc025c4454724709dc32b75551b5f3
|
4
|
+
data.tar.gz: fce1a7fb067481f5ca199301bbd91953d0dd8d13f07e66ad365a5ffa24e58966
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b942ee93f8185051dadac06576087ca8b27b11f8e3c653cb9638a72464941dd72c82c566ede50a46d2bffeb16c809345ef78b3edef7174a74d8ea75e963fa8f1
|
7
|
+
data.tar.gz: 0052cb6afefed493e4ac4e2d48f4c587afe3f377ddabd2492fbeb3c223ff78e39b23ac7b01cd5e564abc3474a5f8f0b35b6edc93c24c453876597c478365ac2a
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.3
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rsmp (0.
|
4
|
+
rsmp (0.8.0)
|
5
5
|
async (~> 1.29.1)
|
6
6
|
async-io (~> 1.32.1)
|
7
7
|
colorize (~> 0.8.1)
|
@@ -34,7 +34,7 @@ GEM
|
|
34
34
|
childprocess (4.1.0)
|
35
35
|
colorize (0.8.1)
|
36
36
|
concurrent-ruby (1.1.9)
|
37
|
-
console (1.
|
37
|
+
console (1.14.0)
|
38
38
|
fiber-local
|
39
39
|
contracts (0.17)
|
40
40
|
cucumber (6.1.0)
|
@@ -95,7 +95,7 @@ GEM
|
|
95
95
|
thor
|
96
96
|
thread_safe
|
97
97
|
rake (13.0.3)
|
98
|
-
regexp_parser (2.
|
98
|
+
regexp_parser (2.2.0)
|
99
99
|
rsmp_schemer (0.3.2)
|
100
100
|
json_schemer (~> 0.2.18)
|
101
101
|
rspec (3.10.0)
|
@@ -124,6 +124,7 @@ GEM
|
|
124
124
|
|
125
125
|
PLATFORMS
|
126
126
|
x86_64-darwin-20
|
127
|
+
x86_64-darwin-21
|
127
128
|
|
128
129
|
DEPENDENCIES
|
129
130
|
aruba (~> 1.1.2)
|
@@ -136,4 +137,4 @@ DEPENDENCIES
|
|
136
137
|
timecop (~> 0.9.4)
|
137
138
|
|
138
139
|
BUNDLED WITH
|
139
|
-
2.2.
|
140
|
+
2.2.32
|
data/lib/rsmp/cli.rb
CHANGED
@@ -3,7 +3,7 @@ module RSMP
|
|
3
3
|
# Collects ingoing and/or outgoing messages from a notifier.
|
4
4
|
# Can filter by message type and wakes up the client once the desired number of messages has been collected.
|
5
5
|
class Collector < Listener
|
6
|
-
attr_reader :condition, :messages, :
|
6
|
+
attr_reader :condition, :messages, :status, :error
|
7
7
|
|
8
8
|
def initialize proxy, options={}
|
9
9
|
super proxy, options
|
@@ -17,11 +17,17 @@ module RSMP
|
|
17
17
|
@outgoing = options[:outgoing] == nil ? false : options[:outgoing]
|
18
18
|
@condition = Async::Notification.new
|
19
19
|
@title = options[:title] || [@options[:type]].flatten.join('/')
|
20
|
-
@options[:timeout] ||= 1
|
21
|
-
@options[:num] ||= 1
|
22
20
|
reset
|
23
21
|
end
|
24
22
|
|
23
|
+
# Clear all query results
|
24
|
+
def reset
|
25
|
+
@messages = []
|
26
|
+
@error = nil
|
27
|
+
@status = :ready
|
28
|
+
@why = nil
|
29
|
+
end
|
30
|
+
|
25
31
|
# Inspect formatter that shows the message we have collected
|
26
32
|
def inspect
|
27
33
|
"#<#{self.class.name}:#{self.object_id}, #{inspector(:@messages)}>"
|
@@ -37,90 +43,108 @@ module RSMP
|
|
37
43
|
@outgoing == true
|
38
44
|
end
|
39
45
|
|
40
|
-
#
|
41
|
-
|
42
|
-
|
46
|
+
# If collection is complete, return immeditatly. Otherwise wait until
|
47
|
+
# the desired messages have been collected, or timeout is reached.
|
48
|
+
def wait task
|
49
|
+
wait! task
|
50
|
+
rescue RSMP::TimeoutError
|
51
|
+
@status
|
43
52
|
end
|
44
53
|
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
def
|
49
|
-
@
|
50
|
-
@
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@condition.wait
|
55
|
-
end
|
56
|
-
end
|
54
|
+
# If collection is complete, return immeditatly. Otherwise wait until
|
55
|
+
# the desired messages have been collected.
|
56
|
+
# If timeout is reached, an exceptioin is raised.
|
57
|
+
def wait! task
|
58
|
+
return @status unless @status == :collecting
|
59
|
+
if @options[:timeout]
|
60
|
+
task.with_timeout(@options[:timeout]) { @condition.wait }
|
61
|
+
else
|
62
|
+
@condition.wait
|
57
63
|
end
|
58
|
-
|
59
|
-
self
|
64
|
+
@status
|
60
65
|
rescue Async::TimeoutError
|
61
|
-
|
62
|
-
|
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
|
66
|
+
@status = :timeout
|
67
|
+
raise RSMP::TimeoutError.new(describe_progress)
|
67
68
|
end
|
68
69
|
|
69
|
-
#
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
# Start collection and return immediately
|
71
|
+
# You can later use wait() to wait for completion
|
72
|
+
def start options={}, &block
|
73
|
+
raise RuntimeError.new("Can't begin unless ready (currenty #{@status})") unless @status == :ready
|
74
|
+
@options.merge! options
|
75
|
+
@block = block
|
76
|
+
raise ArgumentError.new("Num, timeout or block must be provided") unless @options[:num] || @options[:timeout] || @block
|
77
|
+
reset
|
78
|
+
@status = :collecting
|
79
|
+
@notifier.add_listener self if @notifier
|
74
80
|
end
|
75
81
|
|
76
|
-
#
|
77
|
-
|
78
|
-
|
82
|
+
# Collect message
|
83
|
+
# Will return once all messages have been collected, or timeout is reached
|
84
|
+
def collect task, options={}, &block
|
85
|
+
start options, &block
|
86
|
+
wait task
|
87
|
+
@status
|
88
|
+
ensure
|
89
|
+
@notifier.remove_listener self
|
79
90
|
end
|
80
91
|
|
81
|
-
#
|
82
|
-
def
|
83
|
-
@
|
92
|
+
# Build a string describing how how progress reached before timeout
|
93
|
+
def describe_progress
|
94
|
+
str = "#{@title.capitalize} collection "
|
95
|
+
str << "in response to #{@options[:m_id]} " if @options[:m_id]
|
96
|
+
str << "didn't complete within #{@options[:timeout]}s, "
|
97
|
+
str << "reached #{@messages.size}/#{@options[:num]}"
|
98
|
+
str
|
84
99
|
end
|
85
100
|
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
101
|
+
# Collect message
|
102
|
+
# Returns the collected messages, or raise an exception in case of a time out.
|
103
|
+
def collect! task, options={}, &block
|
104
|
+
case collect(task, options, &block)
|
105
|
+
when :timeout
|
106
|
+
raise RSMP::TimeoutError.new @why
|
107
|
+
else
|
108
|
+
@messages
|
109
|
+
end
|
91
110
|
end
|
92
111
|
|
93
112
|
# Check if we receive a NotAck related to initiating request, identified by @m_id.
|
94
|
-
def
|
113
|
+
def reject_not_ack message
|
95
114
|
return unless @options[:m_id]
|
96
115
|
if message.is_a?(MessageNotAck)
|
97
116
|
if message.attribute('oMId') == @options[:m_id]
|
98
117
|
m_id_short = RSMP::Message.shorten_m_id @options[:m_id], 8
|
99
|
-
|
100
|
-
|
118
|
+
cancel RSMP::MessageRejected.new("#{@title} #{m_id_short} was rejected with '#{message.attribute('rea')}'")
|
119
|
+
true
|
101
120
|
end
|
102
|
-
false
|
103
121
|
end
|
104
122
|
end
|
105
123
|
|
106
124
|
# Handle message. and return true when we're done collecting
|
107
125
|
def notify message
|
108
126
|
raise ArgumentError unless message
|
109
|
-
raise RuntimeError.new("can't process message when
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
@done
|
127
|
+
raise RuntimeError.new("can't process message when done") unless @status == :ready || @status == :collecting
|
128
|
+
unless reject_not_ack(message)
|
129
|
+
perform_match message
|
130
|
+
end
|
131
|
+
@status
|
115
132
|
end
|
116
133
|
|
117
134
|
# Match message against our collection criteria
|
118
|
-
def
|
119
|
-
|
120
|
-
if
|
135
|
+
def perform_match message
|
136
|
+
return unless type_match?(message)
|
137
|
+
if @block
|
138
|
+
status = [@block.call(message)].flatten
|
139
|
+
keep message if status.include?(:keep)
|
140
|
+
if status.include?(:cancel)
|
141
|
+
cancel('Cancelled by block')
|
142
|
+
else
|
143
|
+
complete if done?
|
144
|
+
end
|
145
|
+
else
|
121
146
|
keep message
|
122
|
-
|
123
|
-
forget message
|
147
|
+
complete if done?
|
124
148
|
end
|
125
149
|
end
|
126
150
|
|
@@ -132,8 +156,14 @@ module RSMP
|
|
132
156
|
# Called when we're done collecting. Remove ourself as a listener,
|
133
157
|
# se we don't receive message notifications anymore
|
134
158
|
def complete
|
135
|
-
@
|
136
|
-
|
159
|
+
@status = :ok
|
160
|
+
do_stop
|
161
|
+
end
|
162
|
+
|
163
|
+
# Remove ourself as a listener, so we don't receive message notifications anymore,
|
164
|
+
# and wake up the async condition
|
165
|
+
def do_stop
|
166
|
+
@notifier.remove_listener self
|
137
167
|
@condition.signal
|
138
168
|
end
|
139
169
|
|
@@ -143,7 +173,7 @@ module RSMP
|
|
143
173
|
case error
|
144
174
|
when RSMP::SchemaError
|
145
175
|
notify_schema_error error, options
|
146
|
-
when RSMP::
|
176
|
+
when RSMP::DisconnectError
|
147
177
|
notify_disconnect error, options
|
148
178
|
end
|
149
179
|
end
|
@@ -154,24 +184,23 @@ module RSMP
|
|
154
184
|
message = options[:message]
|
155
185
|
return unless message
|
156
186
|
klass = message.class.name.split('::').last
|
157
|
-
return unless [@options[:type]].flatten.include?
|
158
|
-
@
|
187
|
+
return unless @options[:type] == nil || [@options[:type]].flatten.include?(klass)
|
188
|
+
@notifier.log "Collection cancelled due to schema error in #{klass} #{message.m_id_short}", level: :debug
|
159
189
|
cancel error
|
160
190
|
end
|
161
191
|
|
162
192
|
# Cancel if we received e notificaiton about a disconnect
|
163
193
|
def notify_disconnect error, options
|
164
194
|
return unless @options.dig(:cancel,:disconnect)
|
165
|
-
@
|
195
|
+
@notifier.log "Collection cancelled due to a connection error: #{error.to_s}", level: :debug
|
166
196
|
cancel error
|
167
197
|
end
|
168
198
|
|
169
199
|
# Abort collection
|
170
200
|
def cancel error
|
171
|
-
@error = error
|
172
|
-
@
|
173
|
-
|
174
|
-
@condition.signal
|
201
|
+
@error = error
|
202
|
+
@status = :cancelled
|
203
|
+
do_stop
|
175
204
|
end
|
176
205
|
|
177
206
|
# Store a message in the result array
|
@@ -179,30 +208,20 @@ module RSMP
|
|
179
208
|
@messages << message
|
180
209
|
end
|
181
210
|
|
182
|
-
# Remove a message from the result array
|
183
|
-
def forget message
|
184
|
-
@messages.delete message
|
185
|
-
end
|
186
|
-
|
187
211
|
# Check a message against our match criteria
|
188
|
-
# Return true if there's a match
|
189
|
-
def
|
190
|
-
|
191
|
-
return if message.direction == :
|
192
|
-
return if message.direction == :out && @outgoing == false
|
212
|
+
# Return true if there's a match, false if not
|
213
|
+
def type_match? message
|
214
|
+
return false if message.direction == :in && @ingoing == false
|
215
|
+
return false if message.direction == :out && @outgoing == false
|
193
216
|
if @options[:type]
|
194
|
-
return if message == nil
|
195
217
|
if @options[:type].is_a? Array
|
196
|
-
return unless @options[:type].include? message.type
|
218
|
+
return false unless @options[:type].include? message.type
|
197
219
|
else
|
198
|
-
return unless message.type == @options[:type]
|
220
|
+
return false unless message.type == @options[:type]
|
199
221
|
end
|
200
222
|
end
|
201
223
|
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
|
224
|
+
return false if message.attributes['cId'] && message.attributes['cId'] != @options[:component]
|
206
225
|
end
|
207
226
|
true
|
208
227
|
end
|
@@ -5,8 +5,13 @@ module RSMP
|
|
5
5
|
class Listener
|
6
6
|
include Inspect
|
7
7
|
|
8
|
-
def initialize
|
9
|
-
@
|
8
|
+
def initialize notifier, options={}
|
9
|
+
@notifier = notifier
|
10
|
+
end
|
11
|
+
|
12
|
+
def change_notifier notifier
|
13
|
+
@notifier.remove_listener self if @notifier
|
14
|
+
@notifier = notifier
|
10
15
|
end
|
11
16
|
|
12
17
|
def notify message
|
@@ -16,10 +21,10 @@ module RSMP
|
|
16
21
|
end
|
17
22
|
|
18
23
|
def listen &block
|
19
|
-
@
|
24
|
+
@notifier.add_listener self
|
20
25
|
yield
|
21
26
|
ensure
|
22
|
-
@
|
27
|
+
@notifier.remove_listener self
|
23
28
|
end
|
24
29
|
|
25
30
|
end
|
data/lib/rsmp/collect/matcher.rb
CHANGED
@@ -37,9 +37,9 @@ module RSMP
|
|
37
37
|
|
38
38
|
# Initialize with a list of wanted statuses
|
39
39
|
def initialize proxy, want, options={}
|
40
|
+
raise ArgumentError.new("num option cannot be used") if options[:num]
|
40
41
|
super proxy, options.merge( ingoing: true, outgoing: false)
|
41
42
|
@queries = want.map { |item| build_query item }
|
42
|
-
@want = want
|
43
43
|
end
|
44
44
|
|
45
45
|
# Build a query object.
|
@@ -60,11 +60,6 @@ module RSMP
|
|
60
60
|
@queries.map { |query| query.got }.compact
|
61
61
|
end
|
62
62
|
|
63
|
-
# get the first message. Useful when you only collect one mesage
|
64
|
-
def message
|
65
|
-
@queries.first.message
|
66
|
-
end
|
67
|
-
|
68
63
|
# Get messages from results
|
69
64
|
def messages
|
70
65
|
@queries.map { |query| query.message }.uniq
|
@@ -77,14 +72,14 @@ module RSMP
|
|
77
72
|
{ need: need, reached: reached }
|
78
73
|
end
|
79
74
|
|
80
|
-
# Are there queries left to
|
75
|
+
# Are there queries left to type_match?
|
81
76
|
def done?
|
82
77
|
@queries.all? { |query| query.done? }
|
83
78
|
end
|
84
79
|
|
85
80
|
# Get a simplified hash of queries, with values set to either true or false,
|
86
81
|
# indicating which queries have been matched.
|
87
|
-
def
|
82
|
+
def query_status
|
88
83
|
@queries.map { |query| [query.want, query.done?] }.to_h
|
89
84
|
end
|
90
85
|
|
@@ -95,19 +90,23 @@ module RSMP
|
|
95
90
|
|
96
91
|
# Check if a messages matches our criteria.
|
97
92
|
# Match each query against each item in the message
|
98
|
-
def
|
99
|
-
return unless
|
93
|
+
def perform_match message
|
94
|
+
return unless type_match?(message)
|
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.
|
97
|
+
matched = query.perform_match(item,message)
|
98
|
+
if matched == true
|
99
|
+
matched = @block.call(message,item) if @block
|
100
|
+
end
|
103
101
|
if matched != nil
|
104
102
|
type = {true=>'match',false=>'mismatch'}[matched]
|
105
|
-
@
|
103
|
+
@notifier.log "#{@title.capitalize} #{message.m_id_short} collect #{type} #{query.want}, item #{item}", level: :debug
|
106
104
|
break
|
107
105
|
end
|
108
106
|
end
|
109
107
|
end
|
110
|
-
|
108
|
+
complete if done?
|
109
|
+
@notifier.log "#{@title.capitalize} collect reached #{summary}", level: :debug
|
111
110
|
end
|
112
111
|
end
|
113
112
|
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module RSMP
|
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.
|
5
|
+
class MessageCollector < Collector
|
6
|
+
attr_reader :condition, :messages, :done
|
7
|
+
|
8
|
+
def initialize proxy, options={}
|
9
|
+
super proxy, options
|
10
|
+
@options = {
|
11
|
+
cancel: {
|
12
|
+
schema_error: true,
|
13
|
+
disconnect: false,
|
14
|
+
}
|
15
|
+
}.deep_merge options
|
16
|
+
@ingoing = options[:ingoing] == nil ? true : options[:ingoing]
|
17
|
+
@outgoing = options[:outgoing] == nil ? false : options[:outgoing]
|
18
|
+
@condition = Async::Notification.new
|
19
|
+
@title = options[:title] || [@options[:type]].flatten.join('/')
|
20
|
+
@options[:timeout] ||= 1
|
21
|
+
@options[:num] ||= 1
|
22
|
+
reset
|
23
|
+
end
|
24
|
+
|
25
|
+
# Inspect formatter that shows the message we have collected
|
26
|
+
def inspect
|
27
|
+
"#<#{self.class.name}:#{self.object_id}, #{inspector(:@messages)}>"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Want ingoing messages?
|
31
|
+
def ingoing?
|
32
|
+
@ingoing == true
|
33
|
+
end
|
34
|
+
|
35
|
+
# Want outgoing messages?
|
36
|
+
def outgoing?
|
37
|
+
@outgoing == true
|
38
|
+
end
|
39
|
+
|
40
|
+
# Block until all messages have been collected
|
41
|
+
def wait
|
42
|
+
@condition.wait
|
43
|
+
end
|
44
|
+
|
45
|
+
# 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
|
57
|
+
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
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return progress as collected vs. number requested
|
70
|
+
def progress
|
71
|
+
need = @options[:num]
|
72
|
+
reached = @messages.size
|
73
|
+
{ need: need, got: reached }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get the collected message.
|
77
|
+
def message
|
78
|
+
@messages.first
|
79
|
+
end
|
80
|
+
|
81
|
+
# Get the collected messages.
|
82
|
+
def messages
|
83
|
+
@messages
|
84
|
+
end
|
85
|
+
|
86
|
+
# Clear all query results
|
87
|
+
def reset
|
88
|
+
@messages = []
|
89
|
+
@error = nil
|
90
|
+
@done = false
|
91
|
+
end
|
92
|
+
|
93
|
+
# Check if we receive a NotAck related to initiating request, identified by @m_id.
|
94
|
+
def check_not_ack message
|
95
|
+
return unless @options[:m_id]
|
96
|
+
if message.is_a?(MessageNotAck)
|
97
|
+
if message.attribute('oMId') == @options[:m_id]
|
98
|
+
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
|
101
|
+
end
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Handle message. and return true when we're done collecting
|
107
|
+
def notify message
|
108
|
+
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
|
+
perform_match message
|
113
|
+
complete if done?
|
114
|
+
@done
|
115
|
+
end
|
116
|
+
|
117
|
+
# Match message against our collection criteria
|
118
|
+
def perform_match message
|
119
|
+
matched = type_match?(message) && block_match?(message)
|
120
|
+
if matched == true
|
121
|
+
keep message
|
122
|
+
elsif matched == false
|
123
|
+
forget message
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Have we collected the required number of messages?
|
128
|
+
def done?
|
129
|
+
@options[:num] && @messages.size >= @options[:num]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Called when we're done collecting. Remove ourself as a listener,
|
133
|
+
# se we don't receive message notifications anymore
|
134
|
+
def complete
|
135
|
+
@done = true
|
136
|
+
@proxy.remove_listener self
|
137
|
+
@condition.signal
|
138
|
+
end
|
139
|
+
|
140
|
+
# The proxy experienced some error.
|
141
|
+
# Check if this should cause us to cancel.
|
142
|
+
def notify_error error, options={}
|
143
|
+
case error
|
144
|
+
when RSMP::SchemaError
|
145
|
+
notify_schema_error error, options
|
146
|
+
when RSMP::ConnectionError
|
147
|
+
notify_disconnect error, options
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Cancel if we received e schema error for a message type we're collecting
|
152
|
+
def notify_schema_error error, options
|
153
|
+
return unless @options.dig(:cancel,:schema_error)
|
154
|
+
message = options[:message]
|
155
|
+
return unless message
|
156
|
+
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
|
159
|
+
cancel error
|
160
|
+
end
|
161
|
+
|
162
|
+
# Cancel if we received e notificaiton about a disconnect
|
163
|
+
def notify_disconnect error, options
|
164
|
+
return unless @options.dig(:cancel,:disconnect)
|
165
|
+
@proxy.log "Collect cancelled due to a connection error: #{error.to_s}", level: :debug
|
166
|
+
cancel error
|
167
|
+
end
|
168
|
+
|
169
|
+
# Abort collection
|
170
|
+
def cancel error
|
171
|
+
@error = error if error
|
172
|
+
@done = false
|
173
|
+
@proxy.remove_listener self
|
174
|
+
@condition.signal
|
175
|
+
end
|
176
|
+
|
177
|
+
# Store a message in the result array
|
178
|
+
def keep message
|
179
|
+
@messages << message
|
180
|
+
end
|
181
|
+
|
182
|
+
# Remove a message from the result array
|
183
|
+
def forget message
|
184
|
+
@messages.delete message
|
185
|
+
end
|
186
|
+
|
187
|
+
# Check a message against our match criteria
|
188
|
+
# Return true if there's a match, false if not
|
189
|
+
def type_match? message
|
190
|
+
return false if message.direction == :in && @ingoing == false
|
191
|
+
return false if message.direction == :out && @outgoing == false
|
192
|
+
if @options[:type]
|
193
|
+
if @options[:type].is_a? Array
|
194
|
+
return false unless @options[:type].include? message.type
|
195
|
+
else
|
196
|
+
return false unless message.type == @options[:type]
|
197
|
+
end
|
198
|
+
end
|
199
|
+
if @options[:component]
|
200
|
+
return false if message.attributes['cId'] && message.attributes['cId'] != @options[:component]
|
201
|
+
end
|
202
|
+
true
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def block_match? message
|
207
|
+
@block.call(message) == true
|
208
|
+
end
|
209
|
+
end
|
data/lib/rsmp/collect/query.rb
CHANGED
@@ -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
|
@@ -18,7 +18,7 @@ module RSMP
|
|
18
18
|
|
19
19
|
# Check an item and set @done to true if it matches
|
20
20
|
# Store the item and corresponding message if there's a positive or negative match
|
21
|
-
def
|
21
|
+
def perform_match item, message
|
22
22
|
matched = match? item
|
23
23
|
if matched != nil
|
24
24
|
@message = message
|
data/lib/rsmp/error.rb
CHANGED
data/lib/rsmp/logger.rb
CHANGED
@@ -50,7 +50,7 @@ module RSMP
|
|
50
50
|
'statuses' => ['StatusRequest','StatusSubscribe','StatusUnsubscribe','StatusResponse','StatusUpdate'],
|
51
51
|
'commands' => ['CommandRequest','CommandResponse'],
|
52
52
|
'watchdogs' => 'Watchdog',
|
53
|
-
'alarms' => ['
|
53
|
+
'alarms' => ['Alarm'],
|
54
54
|
'aggregated_status' => ['AggregatedStatus','AggregatedStatusRequest']
|
55
55
|
}
|
56
56
|
|
@@ -105,12 +105,10 @@ module RSMP
|
|
105
105
|
|
106
106
|
if item[:message]
|
107
107
|
type = item[:message].type
|
108
|
-
ack = type == "MessageAck" || type == "MessageNotAck"
|
108
|
+
ack = (type == "MessageAck" || type == "MessageNotAck")
|
109
109
|
@ignorable.each_pair do |key,types|
|
110
|
-
next unless types
|
111
110
|
ignore = [types].flatten
|
112
111
|
if @settings[key] == false
|
113
|
-
#p [type,ignore_type, [ignore_type].flatten.include?(type)]
|
114
112
|
return false if ignore.include?(type)
|
115
113
|
if ack
|
116
114
|
return false if item[:message].original && ignore.include?(item[:message].original.type)
|
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,8 @@ module RSMP
|
|
15
15
|
@clock = Clock.new
|
16
16
|
@error_queue = Async::Queue.new
|
17
17
|
@ignore_errors = []
|
18
|
+
options[:collector]
|
19
|
+
@collect = options[:collect]
|
18
20
|
end
|
19
21
|
|
20
22
|
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
|
-
|
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,13 +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
55
|
def collect task, options, &block
|
60
56
|
collector = RSMP::Collector.new self, options
|
61
57
|
collector.collect task, &block
|
@@ -86,7 +82,7 @@ module RSMP
|
|
86
82
|
return if @state == :stopped
|
87
83
|
set_state :stopping
|
88
84
|
stop_tasks
|
89
|
-
notify_error
|
85
|
+
notify_error DisconnectError.new("Connection was closed")
|
90
86
|
ensure
|
91
87
|
close_socket
|
92
88
|
clear
|
data/lib/rsmp/site_proxy.rb
CHANGED
@@ -101,15 +101,8 @@ module RSMP
|
|
101
101
|
"cId" => component,
|
102
102
|
"mId" => m_id
|
103
103
|
})
|
104
|
-
|
105
|
-
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_collect_if_needed message, options do |task|
|
105
|
+
collect_aggregated_status task, options[:collect].merge(m_id: m_id, num:1)
|
113
106
|
end
|
114
107
|
end
|
115
108
|
|
@@ -181,7 +174,7 @@ module RSMP
|
|
181
174
|
"sS" => request_list,
|
182
175
|
"mId" => m_id
|
183
176
|
})
|
184
|
-
|
177
|
+
send_and_collect_if_needed message, options do |task|
|
185
178
|
collect_status_responses task, status_list, options[:collect].merge(m_id: m_id)
|
186
179
|
end
|
187
180
|
end
|
@@ -193,11 +186,15 @@ module RSMP
|
|
193
186
|
acknowledge message
|
194
187
|
end
|
195
188
|
|
196
|
-
def
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
189
|
+
def send_and_collect_if_needed message, options, &block
|
190
|
+
if options[:collect]
|
191
|
+
task = @task.async { |task| yield task }
|
192
|
+
send_message message, validate: options[:validate]
|
193
|
+
{ sent: message, collector: task.wait }
|
194
|
+
else
|
195
|
+
send_message message, validate: options[:validate]
|
196
|
+
return { sent: message }
|
197
|
+
end
|
201
198
|
end
|
202
199
|
|
203
200
|
def subscribe_to_status component_id, status_list, options={}
|
@@ -218,7 +215,7 @@ module RSMP
|
|
218
215
|
"sS" => subscribe_list,
|
219
216
|
'mId' => m_id
|
220
217
|
})
|
221
|
-
|
218
|
+
send_and_collect_if_needed message, options do |task|
|
222
219
|
collect_status_updates task, status_list, options[:collect].merge(m_id: m_id)
|
223
220
|
end
|
224
221
|
end
|
@@ -264,7 +261,7 @@ module RSMP
|
|
264
261
|
"arg" => command_list,
|
265
262
|
"mId" => m_id
|
266
263
|
})
|
267
|
-
|
264
|
+
send_and_collect_if_needed message, options do |task|
|
268
265
|
collect_command_responses task, command_list, options[:collect].merge(m_id: m_id)
|
269
266
|
end
|
270
267
|
end
|
@@ -352,19 +349,27 @@ module RSMP
|
|
352
349
|
end
|
353
350
|
|
354
351
|
def collect_status_updates task, status_list, options
|
355
|
-
StatusUpdateMatcher.new(self, status_list, options)
|
352
|
+
collector = StatusUpdateMatcher.new(self, status_list, options)
|
353
|
+
collector.collect task
|
354
|
+
collector
|
356
355
|
end
|
357
356
|
|
358
357
|
def collect_status_responses task, status_list, options
|
359
|
-
StatusResponseMatcher.new(self, status_list, options)
|
358
|
+
collector = StatusResponseMatcher.new(self, status_list, options)
|
359
|
+
collector.collect task
|
360
|
+
collector
|
360
361
|
end
|
361
362
|
|
362
363
|
def collect_command_responses task, command_list, options
|
363
|
-
CommandResponseMatcher.new(self, command_list, options)
|
364
|
+
collector = CommandResponseMatcher.new(self, command_list, options)
|
365
|
+
collector.collect task
|
366
|
+
collector
|
364
367
|
end
|
365
368
|
|
366
369
|
def collect_aggregated_status task, options
|
367
|
-
AggregatedStatusMatcher.new(self, options)
|
370
|
+
collector = AggregatedStatusMatcher.new(self, options)
|
371
|
+
collector.collect task
|
372
|
+
collector
|
368
373
|
end
|
369
374
|
end
|
370
375
|
end
|
data/lib/rsmp/supervisor.rb
CHANGED
@@ -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
|
-
|
163
|
+
collect: @collect,
|
165
164
|
socket: socket,
|
166
165
|
stream: stream,
|
167
166
|
protocol: protocol,
|
@@ -244,10 +244,13 @@ module RSMP
|
|
244
244
|
@status_subscriptions[component] ||= {}
|
245
245
|
update_list[component] ||= {}
|
246
246
|
now = Time.now # internal timestamp
|
247
|
+
subs = @status_subscriptions[component]
|
247
248
|
|
248
249
|
message.attributes["sS"].each do |arg|
|
249
250
|
sCI = arg["sCI"]
|
250
251
|
subcription = {interval: arg["uRt"].to_i, last_sent_at: now}
|
252
|
+
subs[sCI] ||= {}
|
253
|
+
subs[sCI][arg["n"]] = subcription
|
251
254
|
update_list[component][sCI] ||= []
|
252
255
|
update_list[component][sCI] << arg["n"]
|
253
256
|
end
|
@@ -279,11 +282,7 @@ module RSMP
|
|
279
282
|
end
|
280
283
|
|
281
284
|
def fetch_last_sent_status component, code, name
|
282
|
-
|
283
|
-
@last_status_sent[component][code][name]
|
284
|
-
else
|
285
|
-
nil
|
286
|
-
end
|
285
|
+
@last_status_sent.dig component, code, name
|
287
286
|
end
|
288
287
|
|
289
288
|
def store_last_sent_status message
|
@@ -307,10 +306,12 @@ module RSMP
|
|
307
306
|
by_code.each_pair do |code,by_name|
|
308
307
|
by_name.each_pair do |name,subscription|
|
309
308
|
current = nil
|
309
|
+
should_send = false
|
310
310
|
if subscription[:interval] == 0
|
311
311
|
# send as soon as the data changes
|
312
312
|
if component_object
|
313
313
|
current, age = *(component_object.get_status code, name)
|
314
|
+
current = current.to_s
|
314
315
|
end
|
315
316
|
last_sent = fetch_last_sent_status component, code, name
|
316
317
|
if current != last_sent
|
data/lib/rsmp/version.rb
CHANGED
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
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emil Tin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -189,6 +189,7 @@ files:
|
|
189
189
|
- ".gitignore"
|
190
190
|
- ".gitmodules"
|
191
191
|
- ".rspec"
|
192
|
+
- ".ruby-version"
|
192
193
|
- CHANGELOG.md
|
193
194
|
- Gemfile
|
194
195
|
- Gemfile.lock
|
@@ -208,6 +209,7 @@ files:
|
|
208
209
|
- lib/rsmp/collect/collector.rb
|
209
210
|
- lib/rsmp/collect/listener.rb
|
210
211
|
- lib/rsmp/collect/matcher.rb
|
212
|
+
- lib/rsmp/collect/message_collector.rb
|
211
213
|
- lib/rsmp/collect/message_matchers.rb
|
212
214
|
- lib/rsmp/collect/message_queries.rb
|
213
215
|
- lib/rsmp/collect/notifier.rb
|
@@ -262,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
262
264
|
- !ruby/object:Gem::Version
|
263
265
|
version: '0'
|
264
266
|
requirements: []
|
265
|
-
rubygems_version: 3.2.
|
267
|
+
rubygems_version: 3.2.32
|
266
268
|
signing_key:
|
267
269
|
specification_version: 4
|
268
270
|
summary: RoadSide Message Protocol (RSMP) library.
|