rsmp 0.3.9 → 0.4.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 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