rsmp 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|