rsmp 0.3.9 → 0.4.0

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: 0f137a9e58a8af4524954c33515926c1b6eb2dc8aa7e4fa9bfd00b22f6e5e4bb
4
- data.tar.gz: a9710492f633d584e6ac0acdac9b8f5bf9b820dbe3ad14ca31295bc56b41e232
3
+ metadata.gz: 05d67026eef7404afe7979c198bcfe97bd63e231400e174988ab14454f23ea09
4
+ data.tar.gz: e82717dc287f0eb2e91577cf5e02d752cdf1d1fef6bdac6f4cf3569494d8da3e
5
5
  SHA512:
6
- metadata.gz: cb33932006870bcedfbf3a8d07311c1a752ffccdb23c5d72303b80e47fef0f1b61a4a9fc01521afb8c02bfa32a039b54356687e2d912c03ae9c6238159fdc291
7
- data.tar.gz: c7161ce4a72fbf33394336ad1d8a8db1aedb5148c8988c66fd7ea361b1afa8efddbccb34e376c47ac030ed30b785b118670f4005412752d490b66696213081f7
6
+ metadata.gz: 0d971e86ebd1ef25ff52cc4babd23567b2b5e870cc70f7edfc18ce7925a850fd94dfa851e70c16a43d4df1ef174045999ad41c0fd5ad2ed7c074ae022282e441
7
+ data.tar.gz: 5f991d2aee4af7ac5a30b133ecfa8e1505b005fbc8e7092551f0d28bd4d26cee36fb645aa188e8a9664c0a7d5c991c78a2059445c82e1ec697ff14a8df3d2cdf
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.3.9)
4
+ rsmp (0.4.0)
5
5
  async (~> 1.29.1)
6
6
  async-io (~> 1.32.1)
7
7
  colorize (~> 0.8.1)
@@ -52,11 +52,14 @@ module RSMP
52
52
  raise RSMP::TimeoutError.new str
53
53
  end
54
54
 
55
+ # Get the collected message.
56
+ def message
57
+ @messages.first
58
+ end
59
+
55
60
  # Get the collected messages.
56
- # If one message was requested, return it as a plain object instead of array
57
- def result
58
- return @messages.first if @options[:num] == 1
59
- @messages.first @options[:num]
61
+ def messages
62
+ @messages
60
63
  end
61
64
 
62
65
  # Clear all query results
File without changes
@@ -0,0 +1,100 @@
1
+ module RSMP
2
+ # Base class for waiting for specific status or command responses, specified by
3
+ # a list of queries. Queries are defined as an array of hashes, e.g
4
+ # [
5
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"securityCode", "v"=>"1111"},
6
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"year", "v"=>"2020"},
7
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/}
8
+ # ]
9
+ #
10
+ # Note that queries can contain regex patterns for values, like /\d+/ in the example above.
11
+ #
12
+ # When an input messages is received it typically contains several items, eg:
13
+ # [
14
+ # {"cCI"=>"M0104", "n"=>"month", "v"=>"9", "age"=>"recent"},
15
+ # {"cCI"=>"M0104", "n"=>"day", "v"=>"29", "age"=>"recent"},
16
+ # {"cCI"=>"M0104", "n"=>"hour", "v"=>"17", "age"=>"recent"}
17
+ # ]
18
+ #
19
+ # Each input item is matched against each of the queries.
20
+ # If a match is found, it's stored in the @results hash, with the query as the key,
21
+ # and a mesage and status as the key. In the example above, this query:
22
+ #
23
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/}
24
+ #
25
+ # matches this input:
26
+ #
27
+ # {"cCI"=>"M0104", "n"=>"month", "v"=>"9", "age"=>"recent"}
28
+ #
29
+ # And the result is stored as:
30
+ # {
31
+ # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/} =>
32
+ # { <StatusResponse message>, {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>"9"} }
33
+ # }
34
+
35
+ class Matcher < Collector
36
+ attr_reader :queries
37
+
38
+ # Initialize with a list a wanted statuses
39
+ def initialize proxy, want, options={}
40
+ super proxy, options.merge( ingoing: true, outgoing: false)
41
+ @queries = want.map { |wanted_item| build_query wanted_item }
42
+ end
43
+
44
+ # Build a query object.
45
+ # Sub-classes should override to use their own query classes.
46
+ def build_query want
47
+ Query.new want
48
+ end
49
+
50
+ # Get a results
51
+ def query_result want
52
+ query = @queries.find { |q| q.want == want}
53
+ raise unless query
54
+ query.item
55
+ end
56
+
57
+ # get the first message. Useful when you only collected one mesage
58
+ def message
59
+ @queries.first.message
60
+ end
61
+
62
+ # Get messages from results
63
+ def messages
64
+ @queries.map { |query| query.message }.uniq
65
+ end
66
+
67
+ # Get items from results
68
+ def items
69
+ @queries.map { |query| query.item }.uniq
70
+ end
71
+
72
+ # Are there queries left to match?
73
+ def done?
74
+ @queries.all? { |query| query.done? }
75
+ end
76
+
77
+ # Get a simplified hash of queries, with values set to either true or false,
78
+ # indicating which queries have been matched.
79
+ def status
80
+ @queries.map { |query| [query.query,query.done?] }.to_h
81
+ end
82
+
83
+ # Get a simply array of bools, showing which queries ahve been matched.
84
+ def summary
85
+ @queries.map { |query| query.done? }
86
+ end
87
+
88
+ # Check if a messages matches our criteria.
89
+ # We iterate through each of the status items or return values in the message
90
+ # Breaks as soon as where done matching all queries
91
+ def check_match message
92
+ return unless match?(message)
93
+ @queries.each do |query| # look through queries
94
+ get_items(message).each do |item| # look through status items in message
95
+ break if query.check_match(item,message) != nil #check_item_match message, query, item
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,64 @@
1
+ module RSMP
2
+ # Class for waiting for specific command responses
3
+ class CommandResponseMatcher < Matcher
4
+ def initialize proxy, want, options={}
5
+ super proxy, want, options.merge(
6
+ type: ['CommandResponse','MessageNotAck'],
7
+ title:'command response'
8
+ )
9
+ end
10
+
11
+ def build_query want
12
+ CommandQuery.new want
13
+ end
14
+
15
+ # Get items, in our case the return values
16
+ def get_items message
17
+ message.attributes['rvs']
18
+ end
19
+ end
20
+
21
+ # Base class for waiting for status updates or responses
22
+ class StatusUpdateOrResponseMatcher < Matcher
23
+ def initialize proxy, want, options={}
24
+ super proxy, want, options.merge
25
+ end
26
+
27
+ def build_query want
28
+ StatusQuery.new want
29
+ end
30
+
31
+ # Get items, in our case status values
32
+ def get_items message
33
+ message.attributes['sS']
34
+ end
35
+ end
36
+
37
+ # Class for waiting for specific status responses
38
+ class StatusResponseMatcher < StatusUpdateOrResponseMatcher
39
+ def initialize proxy, want, options={}
40
+ super proxy, want, options.merge(
41
+ type: ['StatusResponse','MessageNotAck'],
42
+ title: 'status response'
43
+ )
44
+ end
45
+ end
46
+
47
+ # Class for waiting for specific status responses
48
+ class StatusUpdateMatcher < StatusUpdateOrResponseMatcher
49
+ def initialize proxy, want, options={}
50
+ super proxy, want, options.merge(
51
+ type: ['StatusUpdate','MessageNotAck'],
52
+ title:'status update'
53
+ )
54
+ end
55
+ end
56
+
57
+ # Class for waiting for an aggregated status response
58
+ class AggregatedStatusMatcher < Collector
59
+ def initialize proxy, options={}
60
+ required = { type: ['AggregatedStatus','MessageNotAck'], title: 'aggregated status' }
61
+ super proxy, options.merge(required)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,33 @@
1
+ module RSMP
2
+ # Match a specific command responses
3
+ class CommandQuery < Query
4
+ # Match a return value item against a query
5
+ def match? item
6
+ return nil if @want['cCI'] && @want['cCI'] != item['cCI']
7
+ return nil if @want['n'] && @want['n'] != item['n']
8
+ if @want['v'].is_a? Regexp
9
+ return false if @want['v'] && item['v'] !~ @want['v']
10
+ else
11
+ return false if @want['v'] && item['v'] != @want['v']
12
+ end
13
+ true
14
+ end
15
+ end
16
+
17
+ # Match a specific status response or update
18
+ class StatusQuery < Query
19
+ # Match a status value against a query
20
+ def match? item
21
+ return nil if @want['sCI'] && @want['sCI'] != item['sCI']
22
+ return nil if @want['cO'] && @want['cO'] != item['cO']
23
+ return nil if @want['n'] && @want['n'] != item['n']
24
+ return false if @want['q'] && @want['q'] != item['q']
25
+ if @want['s'].is_a? Regexp
26
+ return false if @want['s'] && item['s'] !~ @want['s']
27
+ else
28
+ return false if @want['s'] && item['s'] != @want['s']
29
+ end
30
+ true
31
+ end
32
+ end
33
+ end
File without changes
@@ -0,0 +1,44 @@
1
+ module RSMP
2
+
3
+ # Class that matches a single status or command item
4
+ class Query
5
+ attr_reader :want, :item, :message
6
+
7
+ def initialize want
8
+ @want = want
9
+ @item = nil
10
+ @message = nil
11
+ @done = false
12
+ end
13
+
14
+ def done?
15
+ @done
16
+ end
17
+
18
+ def check_match item, message
19
+ matched = match? item
20
+ if matched == true
21
+ keep message, item
22
+ true
23
+ elsif matched == false
24
+ forget
25
+ true
26
+ end
27
+ end
28
+
29
+ def match? item
30
+ end
31
+
32
+ # Mark a query as matched and store item and message
33
+ def keep message, item
34
+ @message = message
35
+ @item = item
36
+ @done = true
37
+ end
38
+
39
+ # Mark a query as not matched
40
+ def forget
41
+ @done = false
42
+ end
43
+ end
44
+ end
data/lib/rsmp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RSMP
2
- VERSION = "0.3.9"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/rsmp.rb CHANGED
@@ -17,10 +17,13 @@ require 'rsmp/wait'
17
17
  require 'rsmp/node'
18
18
  require 'rsmp/supervisor'
19
19
  require 'rsmp/components'
20
- require 'rsmp/notifier'
21
- require 'rsmp/listener'
22
- require 'rsmp/collector'
23
- require 'rsmp/matcher'
20
+ require 'rsmp/collect/notifier'
21
+ require 'rsmp/collect/listener'
22
+ require 'rsmp/collect/collector'
23
+ require 'rsmp/collect/query'
24
+ require 'rsmp/collect/matcher'
25
+ require 'rsmp/collect/message_queries'
26
+ require 'rsmp/collect/message_matchers'
24
27
  require 'rsmp/component'
25
28
  require 'rsmp/site'
26
29
  require 'rsmp/proxy'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsmp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.4.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: 2021-10-26 00:00:00.000000000 Z
11
+ date: 2021-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -205,7 +205,13 @@ files:
205
205
  - lib/rsmp.rb
206
206
  - lib/rsmp/archive.rb
207
207
  - lib/rsmp/cli.rb
208
- - lib/rsmp/collector.rb
208
+ - lib/rsmp/collect/collector.rb
209
+ - lib/rsmp/collect/listener.rb
210
+ - lib/rsmp/collect/matcher.rb
211
+ - lib/rsmp/collect/message_matchers.rb
212
+ - lib/rsmp/collect/message_queries.rb
213
+ - lib/rsmp/collect/notifier.rb
214
+ - lib/rsmp/collect/query.rb
209
215
  - lib/rsmp/component.rb
210
216
  - lib/rsmp/components.rb
211
217
  - lib/rsmp/convert/export/json_schema.rb
@@ -213,13 +219,10 @@ files:
213
219
  - lib/rsmp/deep_merge.rb
214
220
  - lib/rsmp/error.rb
215
221
  - lib/rsmp/inspect.rb
216
- - lib/rsmp/listener.rb
217
222
  - lib/rsmp/logger.rb
218
223
  - lib/rsmp/logging.rb
219
- - lib/rsmp/matcher.rb
220
224
  - lib/rsmp/message.rb
221
225
  - lib/rsmp/node.rb
222
- - lib/rsmp/notifier.rb
223
226
  - lib/rsmp/proxy.rb
224
227
  - lib/rsmp/rsmp.rb
225
228
  - lib/rsmp/site.rb
@@ -255,7 +258,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
255
258
  - !ruby/object:Gem::Version
256
259
  version: '0'
257
260
  requirements: []
258
- rubygems_version: 3.2.26
261
+ rubygems_version: 3.2.15
259
262
  signing_key:
260
263
  specification_version: 4
261
264
  summary: RoadSide Message Protocol (RSMP) library.
data/lib/rsmp/matcher.rb DELETED
@@ -1,195 +0,0 @@
1
- module RSMP
2
-
3
- # Base class for waiting for specific status or command responses, specified by
4
- # a list of queries. Queries are defined as an array of hashes, e.g
5
- # [
6
- # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"securityCode", "v"=>"1111"},
7
- # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"year", "v"=>"2020"},
8
- # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/}
9
- # ]
10
- #
11
- # Note that queries can contain regex patterns for values, like /\d+/ in the example above.
12
- #
13
- # When an input messages is received it typically contains several items, eg:
14
- # [
15
- # {"cCI"=>"M0104", "n"=>"month", "v"=>"9", "age"=>"recent"},
16
- # {"cCI"=>"M0104", "n"=>"day", "v"=>"29", "age"=>"recent"},
17
- # {"cCI"=>"M0104", "n"=>"hour", "v"=>"17", "age"=>"recent"}
18
- # ]
19
- #
20
- # Each input item is matched against each of the queries.
21
- # If a match is found, it's stored in the @results hash, with the query as the key,
22
- # and a mesage and status as the key. In the example above, this query:
23
- #
24
- # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/}
25
- #
26
- # matches this input:
27
- #
28
- # {"cCI"=>"M0104", "n"=>"month", "v"=>"9", "age"=>"recent"}
29
- #
30
- # And the result is stored as:
31
- # {
32
- # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/} =>
33
- # { <StatusResponse message>, {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>"9"} }
34
- # }
35
- #
36
- #
37
- class Matcher < Collector
38
- attr_reader :queries
39
-
40
- # Initialize with a list a wanted statuses
41
- def initialize proxy, want, options={}
42
- super proxy, options.merge( ingoing: true, outgoing: false)
43
- @queries = {}
44
- want.each do |query|
45
- @queries[query] = nil
46
- end
47
- end
48
-
49
- # Get the results, as a hash of queries => results
50
- def result
51
- @queries
52
- end
53
-
54
- # Get messages from results
55
- def messages
56
- @queries.map { |query,result| result[:message] }.uniq
57
- end
58
-
59
- # Get items from results
60
- def items
61
- @queries.map { |query,result| result[:item] }.uniq
62
- end
63
-
64
- # Are there queries left to match?
65
- def done?
66
- @queries.values.all? { |result| result != nil }
67
- end
68
-
69
- # Get a simplified hash of queries, with values set to either true or false,
70
- # indicating which queries have been matched.
71
- def status
72
- @queries.transform_values{ |v| v != nil }
73
- end
74
-
75
- # Get a simply array of bools, showing which queries ahve been matched.
76
- def summary
77
- @queries.values.map { |v| v != nil }
78
- end
79
-
80
- # Mark a query as matched, by linking it to the matched item and message
81
- def keep query, message, item
82
- @queries[query] = { message:message, item:item }
83
- end
84
-
85
- # Mark a query as not matched
86
- def forget query
87
- @queries[query] = nil
88
- end
89
-
90
- # Check if a messages matches our criteria.
91
- # We iterate through each of the status items or return values in the message
92
- # Breaks as soon as where done matching all queries
93
- def check_match message
94
- return unless match?(message)
95
- @queries.keys.each do |query| # look through queries
96
- get_items(message).each do |item| # look through status items in message
97
- break if check_item_match message, query, item
98
- end
99
- end
100
- end
101
-
102
- # Check if an item matches, and mark query as matched/unmatched accordingly.
103
- def check_item_match message, query, item
104
- matched = match_item? query, item
105
- if matched == true
106
- keep query, message, item
107
- true
108
- elsif matched == false
109
- forget query
110
- true
111
- end
112
- end
113
- end
114
-
115
- # Class for waiting for specific command responses
116
- class CommandResponseMatcher < Matcher
117
- def initialize proxy, want, options={}
118
- super proxy, want, options.merge(
119
- type: ['CommandResponse','MessageNotAck'],
120
- title:'command response'
121
- )
122
- end
123
-
124
- # Get items, in our case the return values
125
- def get_items message
126
- message.attributes['rvs']
127
- end
128
-
129
- # Match a return value item against a query
130
- def match_item? query, item
131
- return nil if query['cCI'] && query['cCI'] != item['cCI']
132
- return nil if query['n'] && query['n'] != item['n']
133
- if query['v'].is_a? Regexp
134
- return false if query['v'] && item['v'] !~ query['v']
135
- else
136
- return false if query['v'] && item['v'] != query['v']
137
- end
138
- true
139
- end
140
- end
141
-
142
- # Base class for waiting for status updates or responses
143
- class StatusUpdateOrResponseMatcher < Matcher
144
- def initialize proxy, want, options={}
145
- super proxy, want, options.merge
146
- end
147
-
148
- # Get items, in our case status values
149
- def get_items message
150
- message.attributes['sS']
151
- end
152
-
153
- # Match a status value against a query
154
- def match_item? query, item
155
- return nil if query['sCI'] && query['sCI'] != item['sCI']
156
- return nil if query['cO'] && query['cO'] != item['cO']
157
- return nil if query['n'] && query['n'] != item['n']
158
- return false if query['q'] && query['q'] != item['q']
159
- if query['s'].is_a? Regexp
160
- return false if query['s'] && item['s'] !~ query['s']
161
- else
162
- return false if query['s'] && item['s'] != query['s']
163
- end
164
- true
165
- end
166
- end
167
-
168
- # Class for waiting for specific status responses
169
- class StatusResponseMatcher < StatusUpdateOrResponseMatcher
170
- def initialize proxy, want, options={}
171
- super proxy, want, options.merge(
172
- type: ['StatusResponse','MessageNotAck'],
173
- title: 'status response'
174
- )
175
- end
176
- end
177
-
178
- # Class for waiting for specific status responses
179
- class StatusUpdateMatcher < StatusUpdateOrResponseMatcher
180
- def initialize proxy, want, options={}
181
- super proxy, want, options.merge(
182
- type: ['StatusUpdate','MessageNotAck'],
183
- title:'status update'
184
- )
185
- end
186
- end
187
-
188
- # Class for waiting for an aggregated status response
189
- class AggregatedStatusMatcher < Collector
190
- def initialize proxy, options={}
191
- required = { type: ['AggregatedStatus','MessageNotAck'], title: 'aggregated status' }
192
- super proxy, options.merge(required)
193
- end
194
- end
195
- end