openc3 7.0.0.pre.rc3 → 7.0.1

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openc3cli +58 -10
  3. data/bin/pipinstall +38 -6
  4. data/data/config/command_modifiers.yaml +1 -0
  5. data/data/config/interface_modifiers.yaml +1 -1
  6. data/data/config/item_modifiers.yaml +20 -7
  7. data/data/config/table_parameter_modifiers.yaml +3 -1
  8. data/data/config/telemetry.yaml +1 -1
  9. data/lib/openc3/accessors/json_accessor.rb +1 -1
  10. data/lib/openc3/accessors/template_accessor.rb +9 -0
  11. data/lib/openc3/api/tlm_api.rb +3 -3
  12. data/lib/openc3/config/config_parser.rb +4 -4
  13. data/lib/openc3/conversions/conversion.rb +3 -3
  14. data/lib/openc3/core_ext/faraday.rb +4 -0
  15. data/lib/openc3/interfaces/interface.rb +1 -6
  16. data/lib/openc3/logs/log_writer.rb +24 -6
  17. data/lib/openc3/logs/packet_log_writer.rb +1 -4
  18. data/lib/openc3/logs/stream_log_pair.rb +11 -4
  19. data/lib/openc3/logs/text_log_writer.rb +1 -4
  20. data/lib/openc3/microservices/decom_microservice.rb +1 -1
  21. data/lib/openc3/microservices/interface_decom_common.rb +22 -8
  22. data/lib/openc3/microservices/interface_microservice.rb +14 -3
  23. data/lib/openc3/microservices/log_microservice.rb +7 -2
  24. data/lib/openc3/microservices/microservice.rb +10 -4
  25. data/lib/openc3/microservices/queue_microservice.rb +3 -0
  26. data/lib/openc3/microservices/scope_cleanup_microservice.rb +116 -1
  27. data/lib/openc3/microservices/text_log_microservice.rb +4 -1
  28. data/lib/openc3/migrations/20260204000000_remove_decom_reducer.rb +2 -0
  29. data/lib/openc3/models/activity_model.rb +15 -3
  30. data/lib/openc3/models/cvt_model.rb +2 -247
  31. data/lib/openc3/models/plugin_model.rb +9 -1
  32. data/lib/openc3/models/plugin_store_model.rb +1 -1
  33. data/lib/openc3/models/python_package_model.rb +1 -1
  34. data/lib/openc3/models/reaction_model.rb +27 -9
  35. data/lib/openc3/models/script_engine_model.rb +1 -1
  36. data/lib/openc3/models/target_model.rb +32 -34
  37. data/lib/openc3/models/tool_model.rb +18 -5
  38. data/lib/openc3/models/trigger_model.rb +25 -8
  39. data/lib/openc3/models/widget_model.rb +1 -2
  40. data/lib/openc3/operators/operator.rb +9 -7
  41. data/lib/openc3/packets/json_packet.rb +2 -0
  42. data/lib/openc3/packets/packet.rb +1 -0
  43. data/lib/openc3/packets/packet_config.rb +28 -12
  44. data/lib/openc3/script/api_shared.rb +39 -2
  45. data/lib/openc3/script/calendar.rb +40 -10
  46. data/lib/openc3/script/extract.rb +46 -13
  47. data/lib/openc3/script/script.rb +19 -0
  48. data/lib/openc3/script/storage.rb +6 -6
  49. data/lib/openc3/system/system.rb +6 -6
  50. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +0 -2
  51. data/lib/openc3/top_level.rb +15 -63
  52. data/lib/openc3/topics/decom_interface_topic.rb +19 -4
  53. data/lib/openc3/topics/interface_topic.rb +21 -2
  54. data/lib/openc3/topics/limits_event_topic.rb +1 -1
  55. data/lib/openc3/utilities/bucket_utilities.rb +3 -1
  56. data/lib/openc3/utilities/cli_generator.rb +7 -0
  57. data/lib/openc3/utilities/cmd_log.rb +1 -1
  58. data/lib/openc3/utilities/ctrf.rb +231 -0
  59. data/lib/openc3/utilities/local_mode.rb +3 -0
  60. data/lib/openc3/utilities/process_manager.rb +1 -1
  61. data/lib/openc3/utilities/python_proxy.rb +11 -4
  62. data/lib/openc3/utilities/questdb_client.rb +739 -22
  63. data/lib/openc3/utilities/running_script.rb +25 -7
  64. data/lib/openc3/utilities/script.rb +452 -0
  65. data/lib/openc3/utilities/secrets.rb +1 -1
  66. data/lib/openc3/version.rb +6 -6
  67. data/templates/conversion/conversion.py +0 -8
  68. data/templates/conversion/conversion.rb +0 -11
  69. data/templates/tool_angular/package.json +2 -2
  70. data/templates/tool_react/package.json +1 -1
  71. data/templates/tool_svelte/package.json +1 -1
  72. data/templates/tool_vue/package.json +3 -4
  73. data/templates/widget/package.json +2 -2
  74. metadata +17 -2
  75. data/lib/openc3/migrations/20251022000000_remove_unique_id.rb +0 -23
@@ -15,6 +15,7 @@
15
15
  # This file may also be used under the terms of a commercial license
16
16
  # if purchased from OpenC3, Inc.
17
17
 
18
+ require 'json'
18
19
  require 'openc3/utilities/store'
19
20
 
20
21
  module OpenC3
@@ -154,22 +155,54 @@ module OpenC3
154
155
  end
155
156
 
156
157
  def extract_fields_from_check_text(text)
157
- split_string = text.split
158
- raise "ERROR: Check improperly specified: #{text}" if split_string.length < 3
158
+ target_name, packet_name, item_name, comparison = text.split(nil, 4) # Ruby: second split arg is max number of resultant elements
159
+ raise "ERROR: Check improperly specified: #{text}" if item_name.nil?
159
160
 
160
- target_name = split_string[0]
161
- packet_name = split_string[1]
162
- item_name = split_string[2]
163
- comparison_to_eval = nil
164
- return [target_name, packet_name, item_name, comparison_to_eval] if split_string.length == 3
165
- raise "ERROR: Check improperly specified: #{text}" if split_string.length < 4
161
+ # comparison is either nil, the comparison string, or an empty string.
162
+ # We need it to not be an empty string.
163
+ comparison = nil if comparison&.length == 0
164
+
165
+ operator, _ = comparison&.split(nil, 2)
166
+ raise "ERROR: Use '==' instead of '=' in #{text}" if operator == "="
167
+
168
+ return [target_name, packet_name, item_name, comparison]
169
+ end
170
+
171
+ # Splits `check()` comparison expressions, e.g. "== 'foo bar'" becomes ["==", "foo bar"]
172
+ def extract_operator_and_operand_from_comparison(comparison)
173
+ valid_operators = ["==", "!=", ">=", "<=", ">", "<", "in"]
166
174
 
167
- split_string = text.split(/ /) # Split on regex spaces to preserve spaces in comparison
168
- index = split_string.rindex(item_name)
169
- comparison_to_eval = split_string[(index + 1)..(split_string.length - 1)].join(" ")
170
- raise "ERROR: Use '==' instead of '=': #{text}" if split_string[3] == '='
175
+ operator, operand = comparison.split(nil, 2) # Ruby: second split arg is max number of resultant elements
171
176
 
172
- return [target_name, packet_name, item_name, comparison_to_eval]
177
+ if operand.nil?
178
+ # Don't allow operator without operand
179
+ raise "ERROR: Invalid comparison, must specify an operand: #{comparison}" if !operator.nil?
180
+ return [nil, nil]
181
+ end
182
+
183
+ raise "ERROR: Invalid operator: '#{operator}'" unless valid_operators.include?(operator)
184
+
185
+ # Handle string operand: remove surrounding double/single quotes
186
+ if operand.match?(/^(['"])(.*)\1$/m) # Starts with single or double quote, and ends with matching quote
187
+ operand = operand[1..-2]
188
+ return [operator, operand]
189
+ end
190
+
191
+ # Handle other operand types
192
+ if operand == "nil"
193
+ operand = nil
194
+ elsif operand == "false"
195
+ operand = false
196
+ elsif operand == "true"
197
+ operand = true
198
+ else
199
+ begin
200
+ operand = JSON.parse(operand)
201
+ rescue JSON::ParserError
202
+ raise "ERROR: Unable to parse operand: #{operand}"
203
+ end
204
+ end
205
+ return [operator, operand]
173
206
  end
174
207
  end
175
208
  end
@@ -47,6 +47,9 @@ $disconnect = false
47
47
  $openc3_scope = ENV['OPENC3_SCOPE'] || 'DEFAULT'
48
48
  $openc3_in_cluster = false
49
49
 
50
+ saved_verbose = $VERBOSE
51
+ $VERBOSE = false
52
+
50
53
  module OpenC3
51
54
  module Script
52
55
  private
@@ -177,6 +180,10 @@ module OpenC3
177
180
  message_box(string, *items, **options)
178
181
  end
179
182
 
183
+ def check_box(string, *items, **options)
184
+ message_box(string, *items, **options)
185
+ end
186
+
180
187
  def _file_dialog(title, message, filter:)
181
188
  answer = ''
182
189
  path = "./*"
@@ -199,6 +206,16 @@ module OpenC3
199
206
  _file_dialog(title, message, filter)
200
207
  end
201
208
 
209
+ def open_bucket_dialog(title, message = "Open Bucket File")
210
+ answer = ''
211
+ while answer.empty?
212
+ print "#{title}\n#{message}\n<Type bucket file path (e.g. BUCKET/path/to/file)>:"
213
+ answer = gets
214
+ answer.chomp!
215
+ end
216
+ return answer
217
+ end
218
+
202
219
  def prompt(string, text_color: nil, background_color: nil, font_size: nil, font_family: nil, details: nil)
203
220
  print "#{string}: "
204
221
  print "Details: #{details}\n" if details
@@ -363,3 +380,5 @@ module OpenC3
363
380
  end
364
381
  end
365
382
  end
383
+
384
+ $VERBOSE = saved_verbose
@@ -110,7 +110,7 @@ module OpenC3
110
110
  end
111
111
 
112
112
  return _get_storage_file("#{part}/#{path}", scope: scope)
113
- rescue => e
113
+ rescue
114
114
  if part == "targets_modified"
115
115
  part = "targets"
116
116
  redo
@@ -141,13 +141,13 @@ module OpenC3
141
141
  return result['url']
142
142
  end
143
143
 
144
- def _get_storage_file(path, scope: $openc3_scope)
144
+ def _get_storage_file(path, bucket: 'OPENC3_CONFIG_BUCKET', scope: $openc3_scope)
145
145
  # Create Tempfile to store data
146
146
  file = Tempfile.new('target', binmode: true)
147
147
  file.filename = path
148
148
 
149
149
  endpoint = "/openc3-api/storage/download/#{scope}/#{path}"
150
- result = _get_presigned_request(endpoint, scope: scope)
150
+ result = _get_presigned_request(endpoint, bucket: bucket, scope: scope)
151
151
  puts "Reading #{scope}/#{path}"
152
152
 
153
153
  # Try to get the file
@@ -186,11 +186,11 @@ module OpenC3
186
186
  end
187
187
  end
188
188
 
189
- def _get_presigned_request(endpoint, external: nil, scope: $openc3_scope)
189
+ def _get_presigned_request(endpoint, external: nil, bucket: 'OPENC3_CONFIG_BUCKET', scope: $openc3_scope)
190
190
  if external or !$openc3_in_cluster
191
- response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
191
+ response = $api_server.request('get', endpoint, query: { bucket: bucket }, scope: scope)
192
192
  else
193
- response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET', internal: true }, scope: scope)
193
+ response = $api_server.request('get', endpoint, query: { bucket: bucket, internal: true }, scope: scope)
194
194
  end
195
195
  if response.nil? || response.status != 201
196
196
  raise "Failed to get presigned URL for #{endpoint}"
@@ -81,22 +81,22 @@ module OpenC3
81
81
  # Nothing to do if there are no targets
82
82
  return if target_names.nil? or target_names.length == 0
83
83
  if @@instance.nil?
84
- FileUtils.mkdir_p("#{base_dir}/targets")
84
+ targets_path = "#{base_dir}/_targets"
85
+ FileUtils.mkdir_p(targets_path)
85
86
  bucket = Bucket.getClient()
86
87
  target_names.each do |target_name|
87
88
  # Retrieve bucket/targets/target_name/<TARGET>_current.zip
88
- zip_path = "#{base_dir}/targets/#{target_name}_current.zip"
89
+ zip_path = "#{targets_path}/#{target_name}_current.zip"
89
90
  FileUtils.mkdir_p(File.dirname(zip_path))
90
91
  bucket_key = "#{scope}/target_archives/#{target_name}/#{target_name}_current.zip"
91
92
  Logger.info("Retrieving #{bucket_key} from targets bucket")
92
93
  bucket.get_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: bucket_key, path: zip_path)
93
- targets_path = "#{base_dir}/targets"
94
- FileUtils.mkdir_p(targets_path)
95
94
  Zip::File.open(zip_path) do |zip_file|
96
95
  zip_file.each do |entry|
97
96
  zip_file.extract(entry.name, destination_directory: targets_path)
98
97
  end
99
98
  end
99
+ FileUtils.rm(zip_path) if File.exist?(zip_path)
100
100
 
101
101
  # Now add any modifications in targets_modified/TARGET/cmd_tlm
102
102
  # This adds support for remembering dynamically created packets
@@ -106,13 +106,13 @@ module OpenC3
106
106
  _, files = bucket.list_files(bucket: ENV['OPENC3_CONFIG_BUCKET'], path: bucket_path)
107
107
  files.each do |file|
108
108
  bucket_key = File.join(bucket_path, file['name'])
109
- local_path = "#{base_dir}/targets/#{target_name}/cmd_tlm/#{file['name']}"
109
+ local_path = "#{targets_path}/#{target_name}/cmd_tlm/#{file['name']}"
110
110
  bucket.get_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: bucket_key, path: local_path)
111
111
  end
112
112
  end
113
113
 
114
114
  # Build System from targets
115
- System.instance(target_names, "#{base_dir}/targets")
115
+ System.instance(target_names, targets_path)
116
116
  end
117
117
  end
118
118
 
@@ -221,7 +221,6 @@ module OpenC3
221
221
  else
222
222
  Logger.error connect_error.formatted
223
223
  unless @connection_failed_messages.include?(connect_error.message)
224
- OpenC3.write_exception_file(connect_error)
225
224
  @connection_failed_messages << connect_error.message
226
225
  end
227
226
  end
@@ -242,7 +241,6 @@ module OpenC3
242
241
  else
243
242
  Logger.error err.formatted
244
243
  unless @connection_lost_messages.include?(err.message)
245
- OpenC3.write_exception_file(err)
246
244
  @connection_lost_messages << err.message
247
245
  end
248
246
  end
@@ -1,4 +1,4 @@
1
- # encoding: ascii-8bit
1
+ # encoding: utf-8
2
2
 
3
3
  # Copyright 2022 Ball Aerospace & Technologies Corp.
4
4
  # All Rights Reserved.
@@ -101,6 +101,20 @@ module OpenC3
101
101
  end
102
102
  end
103
103
 
104
+ def self.sanitize_path(path)
105
+ return '' if path.nil?
106
+ # path is passed as a parameter thus we have to sanitize it or the code scanner detects:
107
+ # "Uncontrolled data used in path expression"
108
+ # This method is taken directly from the Rails source:
109
+ # https://api.rubyonrails.org/v5.2/classes/ActiveStorage/Filename.html#method-i-sanitized
110
+ # NOTE: I removed the '/' character because we have to allow this in order to traverse the path
111
+ sanitized = path.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "�").strip.tr("\u{202E}%$|:;\t\r\n\\", "-").gsub('..', '-')
112
+ if sanitized != path
113
+ raise StorageError, "Invalid path: #{path}"
114
+ end
115
+ sanitized
116
+ end
117
+
104
118
  require 'openc3/utilities/logger'
105
119
 
106
120
  # Creates a marshal file by serializing the given obj
@@ -280,65 +294,6 @@ module OpenC3
280
294
  return log_file
281
295
  end
282
296
 
283
- # Writes a log file with information about the current configuration
284
- # including the Ruby version, OpenC3 version, whether you are on Windows, the
285
- # OpenC3 path, and the Ruby path along with the exception that
286
- # is passed in.
287
- #
288
- # @param [String] filename String to append to the exception log filename.
289
- # The filename will start with a date/time stamp.
290
- # @param [String] log_dir By default this method will write to the OpenC3
291
- # default log directory. By setting this parameter you can override the
292
- # directory the log will be written to.
293
- # @return [String|nil] The fully pathed log filename or nil if there was
294
- # an error creating the log file.
295
- def self.write_exception_file(exception, filename = 'exception', log_dir = nil)
296
- log_file = create_log_file(filename, log_dir) do |file|
297
- file.puts "Exception:"
298
- if exception
299
- file.puts exception.formatted
300
- file.puts
301
- else
302
- file.puts "No Exception Given"
303
- file.puts caller.join("\n")
304
- file.puts
305
- end
306
- file.puts "Caller Backtrace:"
307
- file.puts caller().join("\n")
308
- file.puts
309
-
310
- file.puts "Ruby Version: ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} patchlevel #{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]"
311
- file.puts "Rubygems Version: #{Gem::VERSION}"
312
- file.puts "OpenC3 Version: #{OpenC3::VERSION}"
313
- file.puts "OpenC3::PATH: #{OpenC3::PATH}"
314
- file.puts ""
315
- file.puts "Environment:"
316
- file.puts "RUBYOPT: #{ENV['RUBYOPT']}"
317
- file.puts "RUBYLIB: #{ENV['RUBYLIB']}"
318
- file.puts "GEM_PATH: #{ENV['GEM_PATH']}"
319
- file.puts "GEMRC: #{ENV['GEMRC']}"
320
- file.puts "RI_DEVKIT: #{ENV['RI_DEVKIT']}"
321
- file.puts "GEM_HOME: #{ENV['GEM_HOME']}"
322
- file.puts "PYTHONUSERBASE: #{ENV['PYTHONUSERBASE']}"
323
- file.puts "PATH: #{ENV['PATH']}"
324
- file.puts ""
325
- file.puts "Ruby Path:\n #{$:.join("\n ")}\n\n"
326
- file.puts "Gems:"
327
- Gem.loaded_specs.values.map { |x| file.puts "#{x.name} #{x.version} #{x.platform}" }
328
- file.puts ""
329
- file.puts "All Threads Backtraces:"
330
- Thread.list.each do |thread|
331
- file.puts thread.backtrace.join("\n")
332
- file.puts
333
- end
334
- file.puts ""
335
- file.puts ""
336
- ensure
337
- file.close
338
- end
339
- return log_file
340
- end
341
-
342
297
  # Writes a log file with information about unexpected output
343
298
  #
344
299
  # @param [String] text The unexpected output text
@@ -367,7 +322,6 @@ module OpenC3
367
322
  def self.handle_fatal_exception(error, _try_gui = true)
368
323
  unless SystemExit === error or SignalException === error
369
324
  $openc3_fatal_exception = error
370
- self.write_exception_file(error)
371
325
  Logger.fatal "Fatal Exception! Exiting..."
372
326
  Logger.fatal error.formatted
373
327
  if $stdout != STDOUT
@@ -392,7 +346,6 @@ module OpenC3
392
346
  # @param try_gui [Boolean] Whether to try and create a GUI exception popup
393
347
  def self.handle_critical_exception(error, _try_gui = true)
394
348
  Logger.error "Critical Exception! #{error.formatted}"
395
- self.write_exception_file(error)
396
349
  end
397
350
 
398
351
  # Creates a Ruby Thread to run the given block. Rescues any exceptions and
@@ -412,7 +365,6 @@ module OpenC3
412
365
  Logger.error e.formatted
413
366
  retry_count += 1
414
367
  if retry_count <= retry_attempts
415
- self.write_exception_file(e)
416
368
  retry
417
369
  end
418
370
  handle_fatal_exception(e)
@@ -37,7 +37,7 @@ module OpenC3
37
37
  if msg_hash["result"] == "SUCCESS"
38
38
  return msg_hash
39
39
  else
40
- raise msg_hash["message"]
40
+ raise msg_hash["result"]
41
41
  end
42
42
  end
43
43
  end
@@ -45,14 +45,29 @@ module OpenC3
45
45
  raise "Timeout of #{timeout}s waiting for cmd ack. Does target '#{target_name}' exist?"
46
46
  end
47
47
 
48
- def self.inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, scope:)
48
+ def self.inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, timeout: 5, scope:)
49
49
  data = {}
50
50
  data['target_name'] = target_name.to_s.upcase
51
51
  data['packet_name'] = packet_name.to_s.upcase
52
52
  data['item_hash'] = item_hash
53
53
  data['type'] = type
54
- Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",
54
+ ack_topic = "{#{scope}__ACKCMD}TARGET__#{target_name}"
55
+ Topic.update_topic_offsets([ack_topic])
56
+ decom_id = Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",
55
57
  { 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
58
+ time = Time.now
59
+ while (Time.now - time) < timeout
60
+ Topic.read_topics([ack_topic]) do |_topic, _msg_id, msg_hash, _redis|
61
+ if msg_hash["id"] == decom_id
62
+ if msg_hash["result"] == "SUCCESS"
63
+ return
64
+ else
65
+ raise msg_hash["result"]
66
+ end
67
+ end
68
+ end
69
+ end
70
+ raise "Timeout of #{timeout}s waiting for cmd ack. Does target '#{target_name}' exist?"
56
71
  end
57
72
 
58
73
  def self.get_tlm_buffer(target_name, packet_name, timeout: 5, scope:)
@@ -77,7 +92,7 @@ module OpenC3
77
92
  end
78
93
  return msg_hash
79
94
  else
80
- raise msg_hash["message"]
95
+ raise msg_hash["result"]
81
96
  end
82
97
  end
83
98
  end
@@ -111,13 +111,32 @@ module OpenC3
111
111
  Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'protocol_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
112
112
  end
113
113
 
114
- def self.inject_tlm(interface_name, target_name, packet_name, item_hash = nil, type: :CONVERTED, scope:)
114
+ def self.inject_tlm(interface_name, target_name, packet_name, item_hash = nil, type: :CONVERTED, timeout: nil, scope:)
115
+ interface_name = interface_name.upcase
116
+
117
+ timeout = COMMAND_ACK_TIMEOUT_S unless timeout
118
+ ack_topic = "{#{scope}__ACKCMD}INTERFACE__#{interface_name}"
119
+ Topic.update_topic_offsets([ack_topic])
120
+
115
121
  data = {}
116
122
  data['target_name'] = target_name.to_s.upcase
117
123
  data['packet_name'] = packet_name.to_s.upcase
118
124
  data['item_hash'] = item_hash
119
125
  data['type'] = type
120
- Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
126
+ cmd_id = Topic.write_topic("{#{scope}__CMD}INTERFACE__#{interface_name}", { 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
127
+ time = Time.now
128
+ while (Time.now - time) < timeout
129
+ Topic.read_topics([ack_topic]) do |_topic, _msg_id, msg_hash, _redis|
130
+ if msg_hash["id"] == cmd_id
131
+ if msg_hash["result"] == "SUCCESS"
132
+ return
133
+ else
134
+ raise msg_hash["result"]
135
+ end
136
+ end
137
+ end
138
+ end
139
+ raise "Timeout of #{timeout}s waiting for cmd ack"
121
140
  end
122
141
 
123
142
  def self.interface_target_enable(interface_name, target_name, cmd_only: false, tlm_only: false, scope:)
@@ -53,7 +53,7 @@ module OpenC3
53
53
  limits['red_high'] = event[:red_high]
54
54
  limits['green_low'] = event[:green_low] if event[:green_low] && event[:green_high]
55
55
  limits['green_high'] = event[:green_high] if event[:green_low] && event[:green_high]
56
- limits_settings[event[:limits_set]] = limits
56
+ limits_settings[event[:limits_set].to_s] = limits
57
57
  limits_settings['persistence_setting'] = event[:persistence] if event[:persistence]
58
58
  limits_settings['enabled'] = event[:enabled] if not event[:enabled].nil?
59
59
  Store.hset("#{scope}__current_limits_settings", field, JSON.generate(limits_settings, allow_nan: true))
@@ -117,7 +117,9 @@ module OpenC3
117
117
  # Allow caching for files that have a filename versioning strategy
118
118
  has_version_number = /(-|_|\.)\d+(-|_|\.)\d+(-|_|\.)\d+\./.match(filename)
119
119
  has_content_hash = /[\.-][a-f0-9]{20}\./.match(filename)
120
- return nil if has_version_number or has_content_hash
120
+ # Font files are immutable assets deployed with plugins and safe to cache
121
+ is_font = /\.(woff2?|eot|ttf|otf)$/.match(filename)
122
+ return nil if has_version_number or has_content_hash or is_font
121
123
  return 'no-store'
122
124
  end
123
125
 
@@ -197,6 +197,8 @@ module OpenC3
197
197
  target_lib_filename = "#{target_name.downcase}.#{@@language}"
198
198
  target_class = target_lib_filename.filename_to_class_name
199
199
  target_object = target_name.downcase
200
+ target_class.inspect # Remove unused variable warning. These are used in binding for generator
201
+ target_object.inspect # Remove unused variable warning. These are used in binding for generator
200
202
 
201
203
  process_template("#{TEMPLATES_DIR}/target", binding) do |filename|
202
204
  # Rename the template TARGET to our actual target named after the plugin
@@ -292,6 +294,7 @@ RUBY
292
294
  end
293
295
  microservice_filename = "#{microservice_name.downcase}.#{@@language}"
294
296
  microservice_class = microservice_filename.filename_to_class_name
297
+ microservice_class.inspect # Remove unused variable warning. These are used in binding for generator
295
298
 
296
299
  process_template("#{TEMPLATES_DIR}/microservice", binding) do |filename|
297
300
  # Rename the template MICROSERVICE to our actual microservice name
@@ -547,6 +550,7 @@ RUBY
547
550
  conversion_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_CONVERSION"
548
551
  conversion_basename = "#{conversion_name.downcase}.#{@@language}"
549
552
  conversion_class = conversion_basename.filename_to_class_name
553
+ conversion_class.inspect # Remove unused variable warning. These are used in binding for generator
550
554
  conversion_filename = "targets/#{target_name}/lib/#{conversion_basename}"
551
555
  if File.exist?(conversion_filename)
552
556
  abort("Conversion #{conversion_filename} already exists!")
@@ -601,6 +605,7 @@ RUBY
601
605
  processor_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_PROCESSOR"
602
606
  processor_basename = "#{processor_name.downcase}.#{@@language}"
603
607
  processor_class = processor_basename.filename_to_class_name
608
+ processor_class.inspect # Remove unused variable warning. These are used in binding for generator
604
609
  processor_filename = "targets/#{target_name}/lib/#{processor_basename}"
605
610
  if File.exist?(processor_filename)
606
611
  abort("Processor #{processor_filename} already exists!")
@@ -656,6 +661,7 @@ RUBY
656
661
  response_basename = "#{response_name.downcase}.#{@@language}"
657
662
  response_filename = "targets/#{target_name}/lib/#{response_basename}"
658
663
  response_class = response_basename.filename_to_class_name
664
+ response_class.inspect # Remove unused variable warning. These are used in binding for generator
659
665
  if File.exist?(response_filename)
660
666
  abort("response #{response_filename} already exists!")
661
667
  end
@@ -709,6 +715,7 @@ RUBY
709
715
  validator_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_COMMAND_VALIDATOR"
710
716
  validator_basename = "#{validator_name.downcase}.#{@@language}"
711
717
  validator_class = validator_basename.filename_to_class_name
718
+ validator_class.inspect # Remove unused variable warning. These are used in binding for generator
712
719
  validator_filename = "targets/#{target_name}/lib/#{validator_basename}"
713
720
  if File.exist?(validator_filename)
714
721
  abort("Command validator #{validator_filename} already exists!")
@@ -11,7 +11,7 @@
11
11
  # This file may also be used under the terms of a commercial license
12
12
  # if purchased from OpenC3, Inc.
13
13
 
14
- require 'openc3/packets/packet'
14
+ # require 'openc3/packets/packet' # Circular require
15
15
 
16
16
  module OpenC3
17
17
  module CmdLog