openc3 6.9.1 → 6.10.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 +4 -4
- data/bin/openc3cli +289 -0
- data/data/config/command_modifiers.yaml +79 -0
- data/data/config/item_modifiers.yaml +5 -0
- data/data/config/parameter_modifiers.yaml +5 -0
- data/data/config/telemetry_modifiers.yaml +79 -0
- data/ext/openc3/ext/packet/packet.c +9 -0
- data/lib/openc3/accessors/accessor.rb +27 -3
- data/lib/openc3/accessors/binary_accessor.rb +21 -4
- data/lib/openc3/accessors/template_accessor.rb +3 -2
- data/lib/openc3/api/cmd_api.rb +7 -3
- data/lib/openc3/api/tlm_api.rb +17 -7
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +19 -13
- data/lib/openc3/interfaces.rb +6 -4
- data/lib/openc3/io/json_rpc.rb +6 -0
- data/lib/openc3/microservices/decom_microservice.rb +97 -17
- data/lib/openc3/microservices/interface_decom_common.rb +32 -0
- data/lib/openc3/microservices/interface_microservice.rb +12 -80
- data/lib/openc3/microservices/queue_microservice.rb +30 -7
- data/lib/openc3/migrations/20251022000000_remove_unique_id.rb +23 -0
- data/lib/openc3/models/plugin_model.rb +69 -6
- data/lib/openc3/models/queue_model.rb +32 -5
- data/lib/openc3/models/reaction_model.rb +26 -10
- data/lib/openc3/models/target_model.rb +85 -13
- data/lib/openc3/models/trigger_model.rb +1 -1
- data/lib/openc3/packets/commands.rb +33 -7
- data/lib/openc3/packets/packet.rb +75 -71
- data/lib/openc3/packets/packet_config.rb +78 -29
- data/lib/openc3/packets/packet_item.rb +11 -103
- data/lib/openc3/packets/parsers/packet_item_parser.rb +177 -34
- data/lib/openc3/packets/parsers/xtce_converter.rb +2 -2
- data/lib/openc3/packets/structure.rb +29 -21
- data/lib/openc3/packets/structure_item.rb +31 -19
- data/lib/openc3/packets/telemetry.rb +37 -11
- data/lib/openc3/script/script.rb +1 -1
- data/lib/openc3/script/suite_results.rb +2 -2
- data/lib/openc3/subpacketizers/subpacketizer.rb +18 -0
- data/lib/openc3/system/system.rb +3 -3
- data/lib/openc3/system/target.rb +3 -32
- data/lib/openc3/tools/table_manager/table_config.rb +9 -1
- data/lib/openc3/tools/table_manager/table_item_parser.rb +2 -2
- data/lib/openc3/top_level.rb +45 -19
- data/lib/openc3/topics/decom_interface_topic.rb +31 -0
- data/lib/openc3/utilities/authentication.rb +25 -6
- data/lib/openc3/utilities/cli_generator.rb +347 -3
- data/lib/openc3/utilities/env_helper.rb +10 -0
- data/lib/openc3/utilities/logger.rb +7 -11
- data/lib/openc3/version.rb +6 -6
- data/tasks/spec.rake +2 -1
- data/templates/command_validator/command_validator.py +49 -0
- data/templates/command_validator/command_validator.rb +54 -0
- data/templates/tool_angular/package.json +48 -2
- data/templates/tool_react/package.json +51 -1
- data/templates/tool_svelte/package.json +48 -1
- data/templates/tool_vue/package.json +36 -3
- data/templates/widget/package.json +28 -2
- metadata +8 -5
- data/templates/tool_vue/.browserslistrc +0 -16
- data/templates/widget/.browserslistrc +0 -16
data/lib/openc3/system/target.rb
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# GNU Affero General Public License for more details.
|
|
15
15
|
|
|
16
16
|
# Modified by OpenC3, Inc.
|
|
17
|
-
# All changes Copyright
|
|
17
|
+
# All changes Copyright 2025, OpenC3, Inc.
|
|
18
18
|
# All Rights Reserved
|
|
19
19
|
#
|
|
20
20
|
# This file may also be used under the terms of a commercial license
|
|
@@ -68,12 +68,6 @@ module OpenC3
|
|
|
68
68
|
# @return [Integer] The number of telemetry packets received from this target
|
|
69
69
|
attr_accessor :tlm_cnt
|
|
70
70
|
|
|
71
|
-
# @return [Boolean] Indicates if all command packets identify using different fields
|
|
72
|
-
attr_accessor :cmd_unique_id_mode
|
|
73
|
-
|
|
74
|
-
# @return [Boolean] Indicates if telemetry packets identify using different fields
|
|
75
|
-
attr_accessor :tlm_unique_id_mode
|
|
76
|
-
|
|
77
71
|
# @return [String] Id of the target configuration
|
|
78
72
|
attr_accessor :id
|
|
79
73
|
|
|
@@ -91,13 +85,10 @@ module OpenC3
|
|
|
91
85
|
@ignored_parameters = []
|
|
92
86
|
@ignored_items = []
|
|
93
87
|
@cmd_tlm_files = []
|
|
94
|
-
# @auto_screen_substitute = false
|
|
95
88
|
@interface = nil
|
|
96
89
|
@routers = []
|
|
97
90
|
@cmd_cnt = 0
|
|
98
91
|
@tlm_cnt = 0
|
|
99
|
-
@cmd_unique_id_mode = false
|
|
100
|
-
@tlm_unique_id_mode = false
|
|
101
92
|
@name = target_name.clone.upcase.freeze
|
|
102
93
|
get_target_dir(path, gem_path)
|
|
103
94
|
process_target_config_file()
|
|
@@ -174,20 +165,8 @@ module OpenC3
|
|
|
174
165
|
|
|
175
166
|
@cmd_tlm_files << filename
|
|
176
167
|
|
|
177
|
-
|
|
178
|
-
#
|
|
179
|
-
# parser.verify_num_parameters(0, 0, usage)
|
|
180
|
-
# @auto_screen_substitute = true
|
|
181
|
-
|
|
182
|
-
when 'CMD_UNIQUE_ID_MODE'
|
|
183
|
-
usage = "#{keyword}"
|
|
184
|
-
parser.verify_num_parameters(0, 0, usage)
|
|
185
|
-
@cmd_unique_id_mode = true
|
|
186
|
-
|
|
187
|
-
when 'TLM_UNIQUE_ID_MODE'
|
|
188
|
-
usage = "#{keyword}"
|
|
189
|
-
parser.verify_num_parameters(0, 0, usage)
|
|
190
|
-
@tlm_unique_id_mode = true
|
|
168
|
+
when 'CMD_UNIQUE_ID_MODE', 'TLM_UNIQUE_ID_MODE'
|
|
169
|
+
# Deprecated - Now autodetected
|
|
191
170
|
|
|
192
171
|
else
|
|
193
172
|
# blank lines will have a nil keyword and should not raise an exception
|
|
@@ -202,15 +181,7 @@ module OpenC3
|
|
|
202
181
|
config['requires'] = @requires
|
|
203
182
|
config['ignored_parameters'] = @ignored_parameters
|
|
204
183
|
config['ignored_items'] = @ignored_items
|
|
205
|
-
# config['auto_screen_substitute'] = true if @auto_screen_substitute
|
|
206
184
|
config['cmd_tlm_files'] = @cmd_tlm_files
|
|
207
|
-
# config['filename'] = @filename
|
|
208
|
-
# config['interface'] = @interface.name if @interface
|
|
209
|
-
# config['dir'] = @dir
|
|
210
|
-
# config['cmd_cnt'] = @cmd_cnt
|
|
211
|
-
# config['tlm_cnt'] = @tlm_cnt
|
|
212
|
-
config['cmd_unique_id_mode'] = true if @cmd_unique_id_mode
|
|
213
|
-
config['tlm_unique_id_mode'] = true if @tlm_unique_id_mode
|
|
214
185
|
config['id'] = @id
|
|
215
186
|
config
|
|
216
187
|
end
|
|
@@ -226,7 +226,7 @@ module OpenC3
|
|
|
226
226
|
# (see PacketConfig#start_item)
|
|
227
227
|
def start_item(parser)
|
|
228
228
|
finish_item
|
|
229
|
-
@current_item = TableItemParser.parse(parser, @current_packet, @warnings)
|
|
229
|
+
@current_item = TableItemParser.parse(parser, self, @current_packet, @warnings)
|
|
230
230
|
end
|
|
231
231
|
|
|
232
232
|
# If the table is ROW_COLUMN all currently defined items are
|
|
@@ -266,6 +266,14 @@ module OpenC3
|
|
|
266
266
|
item.default = @defaults[index].to_f
|
|
267
267
|
when :STRING, :BLOCK
|
|
268
268
|
item.default = @defaults[index]
|
|
269
|
+
when :BOOL
|
|
270
|
+
item.default = ConfigParser.handle_true_false(@defaults[index])
|
|
271
|
+
when :ARRAY, :OBJECT, :ANY
|
|
272
|
+
begin
|
|
273
|
+
item.default = JSON.parse(@defaults[index], allow_nan: true)
|
|
274
|
+
rescue Exception
|
|
275
|
+
item.default = @defaults[index]
|
|
276
|
+
end
|
|
269
277
|
end
|
|
270
278
|
end
|
|
271
279
|
end
|
|
@@ -30,8 +30,8 @@ module OpenC3
|
|
|
30
30
|
# @param parser [ConfigParser] Configuration parser
|
|
31
31
|
# @param table [Table] Table all parsed items should be added to
|
|
32
32
|
# # @param warnings [Array<String>] Array of warning strings from PacketConfig
|
|
33
|
-
def self.parse(parser, table, warnings)
|
|
34
|
-
parser = TableItemParser.new(parser, warnings)
|
|
33
|
+
def self.parse(parser, table_config, table, warnings)
|
|
34
|
+
parser = TableItemParser.new(parser, table_config, warnings)
|
|
35
35
|
parser.verify_parameters(PacketConfig::COMMAND)
|
|
36
36
|
parser.create_table_item(table)
|
|
37
37
|
end
|
data/lib/openc3/top_level.rb
CHANGED
|
@@ -26,7 +26,6 @@ require 'digest'
|
|
|
26
26
|
require 'open3'
|
|
27
27
|
require 'openc3/core_ext'
|
|
28
28
|
require 'openc3/version'
|
|
29
|
-
require 'openc3/utilities/logger'
|
|
30
29
|
require 'socket'
|
|
31
30
|
require 'pathname'
|
|
32
31
|
|
|
@@ -107,6 +106,8 @@ module OpenC3
|
|
|
107
106
|
end
|
|
108
107
|
end
|
|
109
108
|
|
|
109
|
+
require 'openc3/utilities/logger'
|
|
110
|
+
|
|
110
111
|
# Creates a marshal file by serializing the given obj
|
|
111
112
|
#
|
|
112
113
|
# @param marshal_filename [String] Name of the marshal file to create
|
|
@@ -551,30 +552,55 @@ module OpenC3
|
|
|
551
552
|
end
|
|
552
553
|
end
|
|
553
554
|
|
|
554
|
-
# The following code makes most older COSMOS
|
|
555
|
+
# The following code makes most older COSMOS plugins still work with OpenC3
|
|
555
556
|
# New plugins should only use openc3 paths and module OpenC3
|
|
556
557
|
unless ENV['OPENC3_NO_COSMOS_COMPATIBILITY']
|
|
557
558
|
Cosmos = OpenC3
|
|
558
559
|
ENV['COSMOS_SCOPE'] = ENV['OPENC3_SCOPE']
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
560
|
+
|
|
561
|
+
# Don't apply the compatibility layer in test environments to avoid conflicts with RSpec
|
|
562
|
+
unless defined?(RSpec) || ENV['RAILS_ENV'] == 'test' || ENV['RACK_ENV'] == 'test'
|
|
563
|
+
module CosmosCompatibility
|
|
564
|
+
# Validates the filename after cosmos->openc3 transformation
|
|
565
|
+
def safe_openc3_path?(filename)
|
|
566
|
+
return false unless filename.is_a?(String)
|
|
567
|
+
# Only validate paths that start with "openc3/" (transformed from "cosmos/")
|
|
568
|
+
return true unless filename.start_with?("openc3/")
|
|
569
|
+
# Disallow any ".." or "." path traversal
|
|
570
|
+
return false if filename.include?("..") || filename.include?("./") || filename.include?("/.") || filename.include?("\\") || filename.include?("//")
|
|
571
|
+
# Disallow absolute paths (Unix and Windows)
|
|
572
|
+
return false if filename.start_with?("/") || filename =~ /^[a-zA-Z]:[\\\/]/
|
|
573
|
+
# Disallow special characters (allow word chars, dash, slash, dot)
|
|
574
|
+
return false unless filename =~ /\A[\w\-\/\.]+\z/
|
|
575
|
+
true
|
|
564
576
|
end
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
577
|
+
|
|
578
|
+
def require(*args)
|
|
579
|
+
filename = args[0]
|
|
580
|
+
if filename.is_a?(String) && filename.start_with?("cosmos/")
|
|
581
|
+
filename = filename.sub(/^cosmos\//, "openc3/")
|
|
582
|
+
unless safe_openc3_path?(filename)
|
|
583
|
+
raise ArgumentError, "Unsafe path in require after cosmos->openc3 transformation: #{filename.inspect}"
|
|
584
|
+
end
|
|
585
|
+
args[0] = filename
|
|
586
|
+
end
|
|
587
|
+
super(*args)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def load(*args)
|
|
591
|
+
filename = args[0]
|
|
592
|
+
if filename.is_a?(String) && filename.start_with?("cosmos/")
|
|
593
|
+
filename = filename.sub(/^cosmos\//, "openc3/")
|
|
594
|
+
unless safe_openc3_path?(filename)
|
|
595
|
+
raise ArgumentError, "Unsafe path in load after cosmos->openc3 transformation: #{filename.inspect}"
|
|
596
|
+
end
|
|
597
|
+
args[0] = filename
|
|
598
|
+
end
|
|
599
|
+
super(*args)
|
|
572
600
|
end
|
|
573
|
-
args[0] = filename
|
|
574
|
-
super(*args)
|
|
575
601
|
end
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
602
|
+
class Object
|
|
603
|
+
include CosmosCompatibility
|
|
604
|
+
end
|
|
579
605
|
end
|
|
580
606
|
end
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
# if purchased from OpenC3, Inc.
|
|
18
18
|
|
|
19
19
|
require 'openc3/topics/topic'
|
|
20
|
+
require 'openc3/config/config_parser'
|
|
20
21
|
|
|
21
22
|
module OpenC3
|
|
22
23
|
class DecomInterfaceTopic < Topic
|
|
@@ -58,5 +59,35 @@ module OpenC3
|
|
|
58
59
|
Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",
|
|
59
60
|
{ 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
|
60
61
|
end
|
|
62
|
+
|
|
63
|
+
def self.get_tlm_buffer(target_name, packet_name, timeout: 5, scope:)
|
|
64
|
+
data = {}
|
|
65
|
+
data['target_name'] = target_name.to_s.upcase
|
|
66
|
+
data['packet_name'] = packet_name.to_s.upcase
|
|
67
|
+
# DecomMicroservice is listening to the DECOMINTERFACE topic and has
|
|
68
|
+
# the most recent decommed packets including subpackets
|
|
69
|
+
ack_topic = "{#{scope}__ACKCMD}TARGET__#{target_name}"
|
|
70
|
+
Topic.update_topic_offsets([ack_topic])
|
|
71
|
+
decom_id = Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",
|
|
72
|
+
{ 'get_tlm_buffer' => JSON.generate(data, allow_nan: true) }, '*', 100)
|
|
73
|
+
time = Time.now
|
|
74
|
+
while (Time.now - time) < timeout
|
|
75
|
+
Topic.read_topics([ack_topic]) do |_topic, _msg_id, msg_hash, _redis|
|
|
76
|
+
if msg_hash["id"] == decom_id
|
|
77
|
+
if msg_hash["result"] == "SUCCESS"
|
|
78
|
+
msg_hash["stored"] = ConfigParser.handle_true_false(msg_hash["stored"])
|
|
79
|
+
extra = msg_hash["extra"]
|
|
80
|
+
if extra and extra.length > 0
|
|
81
|
+
msg_hash["extra"] = JSON.parse(extra, allow_nan: true, create_additions: true)
|
|
82
|
+
end
|
|
83
|
+
return msg_hash
|
|
84
|
+
else
|
|
85
|
+
raise msg_hash["message"]
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
raise "Timeout of #{timeout}s waiting for ack. Does target '#{target_name}' exist?"
|
|
91
|
+
end
|
|
61
92
|
end
|
|
62
93
|
end
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
require 'openc3/version'
|
|
24
24
|
require 'openc3/io/json_drb'
|
|
25
25
|
require 'faraday'
|
|
26
|
+
require 'uri'
|
|
26
27
|
|
|
27
28
|
module OpenC3
|
|
28
29
|
# Basic exception for known errors
|
|
@@ -112,9 +113,13 @@ module OpenC3
|
|
|
112
113
|
client_id = ENV['OPENC3_API_CLIENT'] || 'api'
|
|
113
114
|
if ENV['OPENC3_API_USER'] and ENV['OPENC3_API_PASSWORD']
|
|
114
115
|
# Username and password
|
|
115
|
-
data =
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
data = {
|
|
117
|
+
'username' => ENV['OPENC3_API_USER'],
|
|
118
|
+
'password' => ENV['OPENC3_API_PASSWORD'],
|
|
119
|
+
'client_id' => client_id,
|
|
120
|
+
'grant_type' => 'password',
|
|
121
|
+
'scope' => openid_scope
|
|
122
|
+
}
|
|
118
123
|
headers = {
|
|
119
124
|
'Content-Type' => 'application/x-www-form-urlencoded',
|
|
120
125
|
'User-Agent' => "OpenC3KeycloakAuthorization / #{OPENC3_VERSION} (ruby/openc3/lib/utilities/authentication)",
|
|
@@ -134,7 +139,11 @@ module OpenC3
|
|
|
134
139
|
# Refresh the token and save token to instance
|
|
135
140
|
def _refresh_token(current_time)
|
|
136
141
|
client_id = ENV['OPENC3_API_CLIENT'] || 'api'
|
|
137
|
-
data =
|
|
142
|
+
data = {
|
|
143
|
+
'client_id' => client_id,
|
|
144
|
+
'refresh_token' => @refresh_token,
|
|
145
|
+
'grant_type' => 'refresh_token'
|
|
146
|
+
}
|
|
138
147
|
headers = {
|
|
139
148
|
'Content-Type' => 'application/x-www-form-urlencoded',
|
|
140
149
|
'User-Agent' => "OpenC3KeycloakAuthorization / #{OPENC3_VERSION} (ruby/openc3/lib/utilities/authentication)",
|
|
@@ -150,11 +159,21 @@ module OpenC3
|
|
|
150
159
|
def _make_request(headers, data)
|
|
151
160
|
realm = ENV['OPENC3_KEYCLOAK_REALM'] || 'openc3'
|
|
152
161
|
uri = URI("#{@url}/realms/#{realm}/protocol/openid-connect/token")
|
|
153
|
-
|
|
162
|
+
# Obfuscate password and refresh token in logs unless debug mode is enabled
|
|
163
|
+
if JsonDRb.debug?
|
|
164
|
+
log_data = data.inspect
|
|
165
|
+
else
|
|
166
|
+
# Create a copy of the hash with sensitive values obfuscated
|
|
167
|
+
log_data = data.dup
|
|
168
|
+
log_data['password'] = '***' if log_data.key?('password')
|
|
169
|
+
log_data['refresh_token'] = '***' if log_data.key?('refresh_token')
|
|
170
|
+
log_data = log_data.inspect
|
|
171
|
+
end
|
|
172
|
+
@log[0] = "request uri: #{uri} header: #{headers} body: #{log_data}"
|
|
154
173
|
STDOUT.puts @log[0] if JsonDRb.debug?
|
|
155
174
|
saved_verbose = $VERBOSE; $VERBOSE = nil
|
|
156
175
|
begin
|
|
157
|
-
resp = @http.post(uri, data, headers)
|
|
176
|
+
resp = @http.post(uri, URI.encode_www_form(data), headers)
|
|
158
177
|
ensure
|
|
159
178
|
$VERBOSE = saved_verbose
|
|
160
179
|
end
|