openc3 5.0.9 → 5.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/data/config/_id_items.yaml +2 -1
  3. data/data/config/_id_params.yaml +2 -1
  4. data/data/config/_items.yaml +2 -1
  5. data/data/config/_params.yaml +2 -1
  6. data/data/config/command_modifiers.yaml +30 -0
  7. data/data/config/item_modifiers.yaml +10 -0
  8. data/data/config/microservice.yaml +12 -0
  9. data/data/config/param_item_modifiers.yaml +10 -0
  10. data/data/config/plugins.yaml +0 -9
  11. data/data/config/telemetry_modifiers.yaml +10 -0
  12. data/ext/openc3/ext/packet/packet.c +20 -2
  13. data/ext/openc3/ext/structure/structure.c +12 -17
  14. data/lib/openc3/accessors/accessor.rb +71 -0
  15. data/lib/openc3/accessors/binary_accessor.rb +1226 -0
  16. data/lib/openc3/accessors/cbor_accessor.rb +83 -0
  17. data/lib/openc3/accessors/html_accessor.rb +28 -0
  18. data/lib/openc3/accessors/json_accessor.rb +131 -0
  19. data/lib/openc3/accessors/xml_accessor.rb +67 -0
  20. data/lib/openc3/accessors.rb +23 -0
  21. data/lib/openc3/config/config_parser.rb +10 -4
  22. data/lib/openc3/core_ext/tempfile.rb +20 -0
  23. data/lib/openc3/models/cvt_model.rb +1 -10
  24. data/lib/openc3/models/microservice_model.rb +26 -0
  25. data/lib/openc3/packets/binary_accessor.rb +2 -1207
  26. data/lib/openc3/packets/packet.rb +106 -6
  27. data/lib/openc3/packets/packet_config.rb +30 -7
  28. data/lib/openc3/packets/parsers/limits_response_parser.rb +1 -3
  29. data/lib/openc3/packets/parsers/processor_parser.rb +1 -2
  30. data/lib/openc3/packets/structure.rb +39 -14
  31. data/lib/openc3/packets/structure_item.rb +15 -1
  32. data/lib/openc3/script/storage.rb +1 -0
  33. data/lib/openc3/utilities/local_mode.rb +3 -0
  34. data/lib/openc3/utilities/simulated_target.rb +3 -2
  35. data/lib/openc3/version.rb +5 -5
  36. data/lib/openc3.rb +1 -0
  37. metadata +38 -2
@@ -0,0 +1,83 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+
16
+ require 'cbor'
17
+ require 'openc3/accessors/json_accessor'
18
+
19
+ module OpenC3
20
+ class CborAccessor < JsonAccessor
21
+ def self.read_item(item, buffer)
22
+ return nil if item.data_type == :DERIVED
23
+ if String === buffer
24
+ parsed = CBOR.decode(buffer)
25
+ else
26
+ parsed = buffer
27
+ end
28
+ return super(item, parsed)
29
+ end
30
+
31
+ def self.write_item(item, value, buffer)
32
+ return nil if item.data_type == :DERIVED
33
+
34
+ # Convert to ruby objects
35
+ if String === buffer
36
+ decoded = CBOR.decode(buffer)
37
+ else
38
+ decoded = buffer
39
+ end
40
+
41
+ # Write the value
42
+ write_item_internal(item, value, decoded)
43
+
44
+ # Update buffer
45
+ if String === buffer
46
+ buffer.replace(decoded.to_cbor)
47
+ end
48
+
49
+ return buffer
50
+ end
51
+
52
+ def self.read_items(items, buffer)
53
+ # Prevent JsonPath from decoding every call
54
+ if String === buffer
55
+ decoded = CBOR.decode(buffer)
56
+ else
57
+ decoded = buffer
58
+ end
59
+ super(items, decoded)
60
+ end
61
+
62
+ def self.write_items(items, values, buffer)
63
+ # Convert to ruby objects
64
+ if String === buffer
65
+ decoded = CBOR.decode(buffer)
66
+ else
67
+ decoded = buffer
68
+ end
69
+
70
+ items.each_with_index do |item, index|
71
+ write_item_internal(item, values[index], decoded)
72
+ end
73
+
74
+ # Update buffer
75
+ if String === buffer
76
+ buffer.replace(decoded.to_cbor)
77
+ end
78
+
79
+ return buffer
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+
16
+ require 'openc3/accessors/xml_accessor'
17
+
18
+ module OpenC3
19
+ class HtmlAccessor < XmlAccessor
20
+ def self.buffer_to_doc(buffer)
21
+ Nokogiri.HTML(buffer)
22
+ end
23
+
24
+ def self.doc_to_buffer(doc)
25
+ doc.to_html
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,131 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+
16
+ require 'json'
17
+ require 'jsonpath'
18
+ require 'openc3/accessors/accessor'
19
+
20
+ module OpenC3
21
+ class JsonAccessor < Accessor
22
+ def self.read_item(item, buffer)
23
+ return nil if item.data_type == :DERIVED
24
+ return JsonPath.on(buffer, item.key).first
25
+ end
26
+
27
+ def self.write_item(item, value, buffer)
28
+ return nil if item.data_type == :DERIVED
29
+
30
+ # Convert to ruby objects
31
+ if String === buffer
32
+ decoded = JSON.parse(buffer, :allow_nan => true)
33
+ else
34
+ decoded = buffer
35
+ end
36
+
37
+ # Write the value
38
+ write_item_internal(item, value, decoded)
39
+
40
+ # Update buffer
41
+ if String === buffer
42
+ buffer.replace(JSON.generate(decoded, :allow_nan => true))
43
+ end
44
+
45
+ return buffer
46
+ end
47
+
48
+ def self.read_items(items, buffer)
49
+ # Prevent JsonPath from decoding every call
50
+ if String === buffer
51
+ decoded = JSON.parse(buffer)
52
+ else
53
+ decoded = buffer
54
+ end
55
+ super(items, decoded)
56
+ end
57
+
58
+ def self.write_items(items, values, buffer)
59
+ # Start with an empty object if no buffer
60
+ buffer.replace("{}") if buffer.length == 0 or buffer[0] == "\x00"
61
+
62
+ # Convert to ruby objects
63
+ if String === buffer
64
+ decoded = JSON.parse(buffer, :allow_nan => true)
65
+ else
66
+ decoded = buffer
67
+ end
68
+
69
+ items.each_with_index do |item, index|
70
+ write_item_internal(item, values[index], decoded)
71
+ end
72
+
73
+ # Update buffer
74
+ if String === buffer
75
+ buffer.replace(JSON.generate(decoded, :allow_nan => true))
76
+ end
77
+
78
+ return buffer
79
+ end
80
+
81
+ def self.write_item_internal(item, value, decoded)
82
+ return nil if item.data_type == :DERIVED
83
+
84
+ # Save traversal state
85
+ parent_node = nil
86
+ parent_key = nil
87
+ node = decoded
88
+
89
+ # Parse the JsonPath
90
+ json_path = JsonPath.new(item.key)
91
+
92
+ # Handle each token
93
+ json_path.path.each do |token|
94
+ case token
95
+ when '$'
96
+ # Ignore start - it is implied
97
+ next
98
+ when /\[.*\]/
99
+ # Array or Hash Index
100
+ if token.index("'") # Hash index
101
+ key = token[2..-3]
102
+ if not (Hash === node)
103
+ node = {}
104
+ parent_node[parent_key] = node
105
+ end
106
+ parent_node = node
107
+ parent_key = key
108
+ node = node[key]
109
+ else # Array index
110
+ key = token[1..-2].to_i
111
+ if not (Array === node)
112
+ node = []
113
+ parent_node[parent_key] = node
114
+ end
115
+ parent_node = node
116
+ parent_key = key
117
+ node = node[key]
118
+ end
119
+ else
120
+ raise "Unsupported key/token: #{item.key} - #{token}"
121
+ end
122
+ end
123
+ if parent_node
124
+ parent_node[parent_key] = value
125
+ else
126
+ decoded.replace(value)
127
+ end
128
+ return decoded
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+
16
+ require 'nokogiri'
17
+ require 'openc3/accessors/accessor'
18
+
19
+ module OpenC3
20
+ class XmlAccessor < Accessor
21
+ def self.read_item(item, buffer)
22
+ return nil if item.data_type == :DERIVED
23
+ doc = buffer_to_doc(buffer)
24
+ return convert_to_type(doc.xpath(item.key).first.to_s, item)
25
+ end
26
+
27
+ def self.write_item(item, value, buffer)
28
+ return nil if item.data_type == :DERIVED
29
+ doc = buffer_to_doc(buffer)
30
+ node = doc.xpath(item.key).first
31
+ node.content = value.to_s
32
+ buffer.replace(doc_to_buffer(doc))
33
+ end
34
+
35
+ def self.read_items(items, buffer)
36
+ doc = buffer_to_doc(buffer)
37
+ result = {}
38
+ items.each do |item|
39
+ if item.data_type == :DERIVED
40
+ result[item.name] = nil
41
+ else
42
+ result[item.name] = convert_to_type(doc.xpath(item.key).first.to_s, item)
43
+ end
44
+ end
45
+ return result
46
+ end
47
+
48
+ def self.write_items(items, values, buffer)
49
+ doc = buffer_to_doc(buffer)
50
+ items.each_with_index do |item, index|
51
+ next if item.data_type == :DERIVED
52
+ node = doc.xpath(item.key).first
53
+ node.content = values[index].to_s
54
+ end
55
+ buffer.replace(doc_to_buffer(doc))
56
+ end
57
+
58
+ def self.buffer_to_doc(buffer)
59
+ Nokogiri.XML(buffer)
60
+ end
61
+
62
+ def self.doc_to_buffer(doc)
63
+ doc.to_xml
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+
16
+ module OpenC3
17
+ autoload(:Accessor, 'openc3/accessors/accessor.rb')
18
+ autoload(:BinaryAccessor, 'openc3/accessors/binary_accessor.rb')
19
+ autoload(:CborAccessor, 'openc3/accessors/cbor_accessor.rb')
20
+ autoload(:HtmlAccessor, 'openc3/accessors/html_accessor.rb')
21
+ autoload(:JsonAccessor, 'openc3/accessors/json_accessor.rb')
22
+ autoload(:XmlAccessor, 'openc3/accessors/xml_accessor.rb')
23
+ end
@@ -161,14 +161,20 @@ module OpenC3
161
161
  if options[:locals]
162
162
  options[:locals].each { |key, value| b.local_variable_set(key, value) }
163
163
  end
164
+
165
+ return ERB.new(read_file(template_name), trim_mode: "-").result(b)
166
+ end
167
+
168
+ # Can be called during parsing to read a referenced file
169
+ def read_file(filename)
164
170
  # Assume the file is there. If not we raise a pretty obvious error
165
- if File.expand_path(template_name) == template_name # absolute path
166
- path = template_name
171
+ if File.expand_path(filename) == filename # absolute path
172
+ path = filename
167
173
  else # relative to the current @filename
168
- path = File.join(File.dirname(@filename), template_name)
174
+ path = File.join(File.dirname(@filename), filename)
169
175
  end
170
176
  OpenC3.set_working_dir(File.dirname(path)) do
171
- return ERB.new(File.read(path), trim_mode: "-").result(b)
177
+ return File.read(path)
172
178
  end
173
179
  end
174
180
 
@@ -0,0 +1,20 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU Affero General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+
16
+ require 'tempfile'
17
+
18
+ class Tempfile
19
+ attr_accessor :filename
20
+ end
@@ -26,16 +26,7 @@ module OpenC3
26
26
  @overrides = {}
27
27
 
28
28
  def self.build_json_from_packet(packet)
29
- json_hash = {}
30
- packet.sorted_items.each do |item|
31
- json_hash[item.name] = packet.read_item(item, :RAW)
32
- json_hash["#{item.name}__C"] = packet.read_item(item, :CONVERTED) if item.read_conversion or item.states
33
- json_hash["#{item.name}__F"] = packet.read_item(item, :FORMATTED) if item.format_string
34
- json_hash["#{item.name}__U"] = packet.read_item(item, :WITH_UNITS) if item.units
35
- limits_state = item.limits.state
36
- json_hash["#{item.name}__L"] = limits_state if limits_state
37
- end
38
- json_hash
29
+ packet.decom
39
30
  end
40
31
 
41
32
  # Delete the current value table for a target
@@ -34,6 +34,7 @@ module OpenC3
34
34
  attr_accessor :target_names
35
35
  attr_accessor :topics
36
36
  attr_accessor :work_dir
37
+ attr_accessor :ports
37
38
 
38
39
  # NOTE: The following three class methods are used by the ModelController
39
40
  # and are reimplemented to enable various Model class methods to work
@@ -81,6 +82,7 @@ module OpenC3
81
82
  folder_name: nil,
82
83
  cmd: [],
83
84
  work_dir: '.',
85
+ ports: [],
84
86
  env: {},
85
87
  topics: [],
86
88
  target_names: [],
@@ -103,6 +105,7 @@ module OpenC3
103
105
  @folder_name = folder_name
104
106
  @cmd = cmd
105
107
  @work_dir = work_dir
108
+ @ports = ports
106
109
  @env = env
107
110
  @topics = topics
108
111
  @target_names = target_names
@@ -117,6 +120,7 @@ module OpenC3
117
120
  'folder_name' => @folder_name,
118
121
  'cmd' => @cmd,
119
122
  'work_dir' => @work_dir,
123
+ 'ports' => @ports,
120
124
  'env' => @env,
121
125
  'topics' => @topics,
122
126
  'target_names' => @target_names,
@@ -132,6 +136,9 @@ module OpenC3
132
136
  result = "MICROSERVICE #{@folder_name ? @folder_name : 'nil'} #{@name.split("__")[-1]}\n"
133
137
  result << " CMD #{@cmd.join(' ')}\n"
134
138
  result << " WORK_DIR \"#{@work_dir}\"\n"
139
+ @ports.each do |port|
140
+ result << " PORT #{port}\n"
141
+ end
135
142
  @topics.each do |topic_name|
136
143
  result << " TOPIC #{topic_name}\n"
137
144
  end
@@ -156,6 +163,25 @@ module OpenC3
156
163
  when 'WORK_DIR'
157
164
  parser.verify_num_parameters(1, 1, "#{keyword} <Dir>")
158
165
  @work_dir = parameters[0]
166
+ when 'PORT'
167
+ usage = "PORT <Number> <Protocol (Optional)"
168
+ parser.verify_num_parameters(1, 2, usage)
169
+ begin
170
+ @ports << [Integer(parameters[0])]
171
+ rescue => err # In case Integer fails
172
+ raise ConfigParser::Error.new(parser, "Port must be an integer: #{parameters[0]}", usage)
173
+ end
174
+ protocol = ConfigParser.handle_nil(parameters[1])
175
+ if protocol
176
+ # Per https://kubernetes.io/docs/concepts/services-networking/service/#protocol-support
177
+ if %w(TCP UDP SCTP HTTP SCTP).include?(protocol.upcase)
178
+ @ports[-1] << protocol.upcase
179
+ else
180
+ raise ConfigParser::Error.new(parser, "Unknown port protocol: #{parameters[1]}", usage)
181
+ end
182
+ else
183
+ @ports[-1] << 'TCP'
184
+ end
159
185
  when 'TOPIC'
160
186
  parser.verify_num_parameters(1, 1, "#{keyword} <Topic Name>")
161
187
  @topics << parameters[0]