openc3 5.0.9 → 5.0.11

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of openc3 might be problematic. Click here for more details.

Files changed (46) 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/api/interface_api.rb +10 -3
  22. data/lib/openc3/config/config_parser.rb +10 -4
  23. data/lib/openc3/core_ext/tempfile.rb +20 -0
  24. data/lib/openc3/core_ext.rb +1 -0
  25. data/lib/openc3/interfaces/interface.rb +1 -1
  26. data/lib/openc3/models/auth_model.rb +0 -1
  27. data/lib/openc3/models/cvt_model.rb +1 -10
  28. data/lib/openc3/models/microservice_model.rb +26 -0
  29. data/lib/openc3/models/note_model.rb +5 -5
  30. data/lib/openc3/packets/binary_accessor.rb +2 -1207
  31. data/lib/openc3/packets/packet.rb +106 -6
  32. data/lib/openc3/packets/packet_config.rb +30 -7
  33. data/lib/openc3/packets/parsers/limits_response_parser.rb +1 -3
  34. data/lib/openc3/packets/parsers/processor_parser.rb +1 -2
  35. data/lib/openc3/packets/structure.rb +39 -14
  36. data/lib/openc3/packets/structure_item.rb +15 -1
  37. data/lib/openc3/script/storage.rb +2 -0
  38. data/lib/openc3/utilities/authentication.rb +6 -4
  39. data/lib/openc3/utilities/local_mode.rb +10 -1
  40. data/lib/openc3/utilities/s3.rb +3 -1
  41. data/lib/openc3/utilities/s3_autoload.rb +8 -6
  42. data/lib/openc3/utilities/simulated_target.rb +3 -2
  43. data/lib/openc3/utilities/target_file.rb +45 -6
  44. data/lib/openc3/version.rb +5 -5
  45. data/lib/openc3.rb +1 -0
  46. 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
@@ -119,13 +119,20 @@ module OpenC3
119
119
  # interface. All the commands will go out over and telemetry be received
120
120
  # from that interface.
121
121
  #
122
- # @param target_name [String] The name of the target
122
+ # @param target_name [String/Array] The name of the target(s)
123
123
  # @param interface_name (see #connect_interface)
124
124
  def map_target_to_interface(target_name, interface_name, scope: $openc3_scope, token: $openc3_token)
125
125
  authorize(permission: 'system_set', interface_name: interface_name, scope: scope, token: token)
126
126
  new_interface = InterfaceModel.get_model(name: interface_name, scope: scope)
127
- new_interface.map_target(target_name)
128
- Logger.info("Target #{target_name} mapped to Interface #{interface_name}", scope: scope)
127
+ if Array === target_name
128
+ target_names = target_name
129
+ else
130
+ target_names = [target_name]
131
+ end
132
+ target_names.each do |name|
133
+ new_interface.map_target(name)
134
+ Logger.info("Target #{name} mapped to Interface #{interface_name}", scope: scope)
135
+ end
129
136
  nil
130
137
  end
131
138
  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
@@ -32,5 +32,6 @@ require 'openc3/core_ext/range'
32
32
  require 'openc3/core_ext/socket'
33
33
  require 'openc3/core_ext/string'
34
34
  require 'openc3/core_ext/stringio'
35
+ require 'openc3/core_ext/tempfile'
35
36
  require 'openc3/core_ext/time'
36
37
  require 'openc3/core_ext/objectspace'
@@ -328,7 +328,7 @@ module OpenC3
328
328
  config = {}
329
329
  config['name'] = @name
330
330
  config['state'] = @state
331
- config['clients'] = @num_clients
331
+ config['clients'] = self.num_clients
332
332
  config['txsize'] = @write_queue_size
333
333
  config['rxsize'] = @read_queue_size
334
334
  config['txbytes'] = @bytes_written
@@ -42,7 +42,6 @@ module OpenC3
42
42
  service_hash = set_hash
43
43
  end
44
44
  return true if service_hash == token_hash and permission != 'admin'
45
-
46
45
  return false
47
46
  end
48
47
 
@@ -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]
@@ -96,12 +96,12 @@ module OpenC3
96
96
  end
97
97
 
98
98
  # Update the Redis hash at primary_key
99
- def update(start:, stop:, color:, description:)
99
+ def update(start: nil, stop: nil, color: nil, description: nil)
100
100
  orig_start = @start
101
- @start = start
102
- @stop = stop
103
- @color = color
104
- @description = description
101
+ @start = start if start
102
+ @stop = stop if stop
103
+ @color = color if color
104
+ @description = description if description
105
105
  create(update: orig_start)
106
106
  end
107
107