openc3 6.4.1 → 6.5.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openc3cli +172 -97
  3. data/data/config/_graph_params.yaml +4 -4
  4. data/data/config/conversions.yaml +274 -0
  5. data/data/config/item_modifiers.yaml +8 -70
  6. data/data/config/parameter_modifiers.yaml +9 -69
  7. data/data/config/plugins.yaml +14 -1
  8. data/data/config/processors.yaml +51 -0
  9. data/data/config/telemetry_modifiers.yaml +1 -0
  10. data/lib/openc3/api/api.rb +1 -1
  11. data/lib/openc3/api/tlm_api.rb +10 -5
  12. data/lib/openc3/conversions/unix_time_conversion.rb +2 -2
  13. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +3 -3
  14. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +3 -3
  15. data/lib/openc3/core_ext/time.rb +2 -9
  16. data/lib/openc3/microservices/cleanup_microservice.rb +2 -2
  17. data/lib/openc3/microservices/decom_microservice.rb +2 -2
  18. data/lib/openc3/microservices/interface_microservice.rb +18 -12
  19. data/lib/openc3/microservices/log_microservice.rb +4 -2
  20. data/lib/openc3/microservices/multi_microservice.rb +2 -2
  21. data/lib/openc3/microservices/periodic_microservice.rb +2 -2
  22. data/lib/openc3/microservices/reducer_microservice.rb +2 -2
  23. data/lib/openc3/microservices/router_microservice.rb +2 -2
  24. data/lib/openc3/microservices/scope_cleanup_microservice.rb +2 -2
  25. data/lib/openc3/microservices/text_log_microservice.rb +19 -6
  26. data/lib/openc3/models/plugin_model.rb +5 -4
  27. data/lib/openc3/models/scope_model.rb +87 -57
  28. data/lib/openc3/models/script_engine_model.rb +93 -0
  29. data/lib/openc3/models/script_status_model.rb +26 -4
  30. data/lib/openc3/models/target_model.rb +33 -5
  31. data/lib/openc3/packets/packet_config.rb +1 -1
  32. data/lib/openc3/script/autonomic.rb +359 -0
  33. data/lib/openc3/script/script.rb +6 -1
  34. data/lib/openc3/script_engines/script_engine.rb +118 -0
  35. data/lib/openc3/topics/interface_topic.rb +23 -3
  36. data/lib/openc3/utilities/cli_generator.rb +42 -15
  37. data/lib/openc3/utilities/running_script.rb +1460 -0
  38. data/lib/openc3/version.rb +6 -6
  39. data/templates/conversion/conversion.py +1 -1
  40. data/templates/conversion/conversion.rb +1 -1
  41. data/templates/processor/processor.py +32 -0
  42. data/templates/processor/processor.rb +36 -0
  43. data/templates/tool_angular/package.json +2 -2
  44. data/templates/tool_react/package.json +1 -1
  45. data/templates/tool_svelte/package.json +1 -1
  46. data/templates/tool_vue/package.json +3 -3
  47. data/templates/widget/package.json +2 -2
  48. metadata +9 -1
@@ -20,17 +20,17 @@
20
20
  # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
- require 'openc3/version'
24
- require 'openc3/models/model'
25
- require 'openc3/models/plugin_model'
26
- require 'openc3/models/microservice_model'
27
- require 'openc3/models/setting_model'
28
- require 'openc3/models/trigger_group_model'
29
- require 'openc3/topics/system_events_topic'
23
+ require "openc3/version"
24
+ require "openc3/models/model"
25
+ require "openc3/models/plugin_model"
26
+ require "openc3/models/microservice_model"
27
+ require "openc3/models/setting_model"
28
+ require "openc3/models/trigger_group_model"
29
+ require "openc3/topics/system_events_topic"
30
30
 
31
31
  begin
32
- require 'openc3-enterprise/models/cmd_authority_model'
33
- require 'openc3-enterprise/models/critical_cmd_model'
32
+ require "openc3-enterprise/models/cmd_authority_model"
33
+ require "openc3-enterprise/models/critical_cmd_model"
34
34
  module OpenC3
35
35
  class ScopeModel < Model
36
36
  ENTERPRISE = true
@@ -46,7 +46,7 @@ end
46
46
 
47
47
  module OpenC3
48
48
  class ScopeModel < Model
49
- PRIMARY_KEY = 'openc3_scopes'
49
+ PRIMARY_KEY = "openc3_scopes"
50
50
 
51
51
  attr_accessor :children
52
52
  attr_accessor :text_log_cycle_time
@@ -76,17 +76,17 @@ module OpenC3
76
76
  end
77
77
 
78
78
  def self.from_json(json, scope: nil)
79
- json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
79
+ json = JSON.parse(json, allow_nan: true, create_additions: true) if String === json
80
80
  raise "json data is nil" if json.nil?
81
- self.new(**json.transform_keys(&:to_sym))
81
+ new(**json.transform_keys(&:to_sym))
82
82
  end
83
83
 
84
84
  def self.get_model(name:, scope: nil)
85
85
  json = get(name: name)
86
86
  if json
87
- return from_json(json)
87
+ from_json(json)
88
88
  else
89
- return nil
89
+ nil
90
90
  end
91
91
  end
92
92
 
@@ -99,8 +99,7 @@ module OpenC3
99
99
  command_authority: false,
100
100
  critical_commanding: "OFF",
101
101
  shard: 0,
102
- updated_at: nil
103
- )
102
+ updated_at: nil)
104
103
  super(
105
104
  PRIMARY_KEY,
106
105
  name: name,
@@ -117,7 +116,7 @@ module OpenC3
117
116
  @command_authority = command_authority
118
117
  @critical_commanding = critical_commanding.to_s.upcase
119
118
  @critical_commanding = "OFF" if @critical_commanding.length == 0
120
- if not ["OFF", "NORMAL", "ALL"].include?(@critical_commanding)
119
+ if !["OFF", "NORMAL", "ALL"].include?(@critical_commanding)
121
120
  raise "Invalid value for critical_commanding: #{@critical_commanding}"
122
121
  end
123
122
  @shard = shard.to_i # to_i to handle nil
@@ -126,7 +125,7 @@ module OpenC3
126
125
 
127
126
  def create(update: false, force: false, queued: false)
128
127
  # Ensure there are no "." in the scope name - prevents gems accidentally becoming scope names
129
- raise "Invalid scope name: #{@name}" if @name !~ /^[a-zA-Z0-9_-]+$/
128
+ raise "Invalid scope name: #{@name}" if !/^[a-zA-Z0-9_-]+$/.match?(@name)
130
129
  @name = @name.upcase
131
130
  @scope = @name # Ensure @scope matches @name
132
131
  # Ensure the various cycle and retain times are integers
@@ -135,7 +134,7 @@ module OpenC3
135
134
  @text_log_retain_time = @text_log_retain_time.to_i if @text_log_retain_time
136
135
  @tool_log_retain_time = @tool_log_retain_time.to_i if @tool_log_retain_time
137
136
  @cleanup_poll_time = @cleanup_poll_time.to_i
138
- super(update: update, force: force, queued: queued)
137
+ super
139
138
 
140
139
  if ENTERPRISE
141
140
  # If we're updating the scope and disabling command_authority
@@ -157,50 +156,49 @@ module OpenC3
157
156
  end
158
157
  end
159
158
 
160
- SystemEventsTopic.write(:scope, as_json())
159
+ SystemEventsTopic.write(:scope, as_json)
161
160
  end
162
161
 
163
162
  def destroy
164
- if @name != 'DEFAULT'
163
+ if @name != "DEFAULT"
165
164
  # Remove all the plugins for this scope
166
165
  plugins = PluginModel.get_all_models(scope: @name)
167
166
  plugins.each do |_plugin_name, plugin|
168
167
  plugin.destroy
169
168
  end
170
- super()
169
+ super
171
170
  else
172
171
  raise "DEFAULT scope cannot be destroyed"
173
172
  end
174
173
  end
175
174
 
176
175
  def as_json(*_a)
177
- { 'name' => @name,
178
- 'updated_at' => @updated_at,
179
- 'text_log_cycle_time' => @text_log_cycle_time,
180
- 'text_log_cycle_size' => @text_log_cycle_size,
181
- 'text_log_retain_time' => @text_log_retain_time,
182
- 'tool_log_retain_time' => @tool_log_retain_time,
183
- 'cleanup_poll_time' => @cleanup_poll_time,
184
- 'command_authority' => @command_authority,
185
- 'critical_commanding' => @critical_commanding,
186
- 'shard' => @shard,
187
- }
176
+ {"name" => @name,
177
+ "updated_at" => @updated_at,
178
+ "text_log_cycle_time" => @text_log_cycle_time,
179
+ "text_log_cycle_size" => @text_log_cycle_size,
180
+ "text_log_retain_time" => @text_log_retain_time,
181
+ "tool_log_retain_time" => @tool_log_retain_time,
182
+ "cleanup_poll_time" => @cleanup_poll_time,
183
+ "command_authority" => @command_authority,
184
+ "critical_commanding" => @critical_commanding,
185
+ "shard" => @shard}
188
186
  end
189
187
 
190
188
  def deploy_openc3_log_messages_microservice(gem_path, variables, parent)
191
189
  microservice_name = "#{@scope}__OPENC3__LOG"
192
190
  topics = ["#{@scope}__openc3_log_messages"]
193
191
  # Also log the NOSCOPE messages with this microservice for the DEFAULT scope
194
- if @scope == 'DEFAULT'
192
+ if @scope == "DEFAULT"
195
193
  topics << "NOSCOPE__openc3_log_messages"
196
194
  end
197
195
  microservice = MicroserviceModel.new(
198
196
  name: microservice_name,
199
197
  cmd: ["ruby", "text_log_microservice.rb", microservice_name],
200
- work_dir: '/openc3/lib/openc3/microservices',
198
+ work_dir: "/openc3/lib/openc3/microservices",
201
199
  options: [
202
200
  ["CYCLE_TIME", @text_log_cycle_time],
203
- ["CYCLE_SIZE", @text_log_cycle_size],
201
+ ["CYCLE_SIZE", @text_log_cycle_size]
204
202
  ],
205
203
  topics: topics,
206
204
  parent: parent,
@@ -218,11 +216,11 @@ module OpenC3
218
216
  microservice = MicroserviceModel.new(
219
217
  name: microservice_name,
220
218
  cmd: ["ruby", "log_microservice.rb", microservice_name],
221
- work_dir: '/openc3/lib/openc3/microservices',
219
+ work_dir: "/openc3/lib/openc3/microservices",
222
220
  options: [
223
221
  ["RAW_OR_DECOM", "RAW"],
224
222
  ["CMD_OR_TLM", "CMD"],
225
- ["CYCLE_TIME", "3600"], # Keep at most 1 hour per log
223
+ ["CYCLE_TIME", "3600"] # Keep at most 1 hour per log
226
224
  ],
227
225
  topics: ["#{@scope}__COMMAND__{UNKNOWN}__UNKNOWN"],
228
226
  target_names: [],
@@ -241,11 +239,11 @@ module OpenC3
241
239
  microservice = MicroserviceModel.new(
242
240
  name: microservice_name,
243
241
  cmd: ["ruby", "log_microservice.rb", microservice_name],
244
- work_dir: '/openc3/lib/openc3/microservices',
242
+ work_dir: "/openc3/lib/openc3/microservices",
245
243
  options: [
246
244
  ["RAW_OR_DECOM", "RAW"],
247
245
  ["CMD_OR_TLM", "TLM"],
248
- ["CYCLE_TIME", "3600"], # Keep at most 1 hour per log
246
+ ["CYCLE_TIME", "3600"] # Keep at most 1 hour per log
249
247
  ],
250
248
  topics: ["#{@scope}__TELEMETRY__{UNKNOWN}__UNKNOWN"],
251
249
  target_names: [],
@@ -264,7 +262,7 @@ module OpenC3
264
262
  microservice = MicroserviceModel.new(
265
263
  name: microservice_name,
266
264
  cmd: ["ruby", "periodic_microservice.rb", microservice_name],
267
- work_dir: '/openc3/lib/openc3/microservices',
265
+ work_dir: "/openc3/lib/openc3/microservices",
268
266
  parent: parent,
269
267
  shard: @shard,
270
268
  scope: @scope
@@ -280,7 +278,7 @@ module OpenC3
280
278
  microservice = MicroserviceModel.new(
281
279
  name: microservice_name,
282
280
  cmd: ["ruby", "scope_cleanup_microservice.rb", microservice_name],
283
- work_dir: '/openc3/lib/openc3/microservices',
281
+ work_dir: "/openc3/lib/openc3/microservices",
284
282
  parent: parent,
285
283
  shard: @shard,
286
284
  scope: @scope
@@ -296,7 +294,7 @@ module OpenC3
296
294
  microservice = MicroserviceModel.new(
297
295
  name: microservice_name,
298
296
  cmd: ["ruby", "critical_cmd_microservice.rb", microservice_name],
299
- work_dir: '/openc3-enterprise/lib/openc3-enterprise/microservices',
297
+ work_dir: "/openc3-enterprise/lib/openc3-enterprise/microservices",
300
298
  parent: parent,
301
299
  shard: @shard,
302
300
  scope: @scope
@@ -312,7 +310,7 @@ module OpenC3
312
310
  microservice = MicroserviceModel.new(
313
311
  name: microservice_name,
314
312
  cmd: ["ruby", "multi_microservice.rb", *@children],
315
- work_dir: '/openc3/lib/openc3/microservices',
313
+ work_dir: "/openc3/lib/openc3/microservices",
316
314
  target_names: [],
317
315
  shard: @shard,
318
316
  scope: @scope
@@ -323,15 +321,15 @@ module OpenC3
323
321
  end
324
322
 
325
323
  def deploy(gem_path, variables)
326
- seed_database()
324
+ seed_database
327
325
 
328
326
  if ENTERPRISE
329
327
  # Create DEFAULT trigger group model
330
- model = TriggerGroupModel.get(name: 'DEFAULT', scope: @scope)
328
+ model = TriggerGroupModel.get(name: "DEFAULT", scope: @scope)
331
329
  unless model
332
- model = TriggerGroupModel.new(name: 'DEFAULT', shard: @shard, scope: @scope)
333
- model.create()
334
- model.deploy()
330
+ model = TriggerGroupModel.new(name: "DEFAULT", shard: @shard, scope: @scope)
331
+ model.create
332
+ model.deploy
335
333
  end
336
334
  end
337
335
 
@@ -351,7 +349,7 @@ module OpenC3
351
349
  deploy_unknown_packetlog_microservice(gem_path, variables, @parent)
352
350
 
353
351
  # Only DEFAULT scope
354
- if @scope == 'DEFAULT'
352
+ if @scope == "DEFAULT"
355
353
  # Periodic Microservice
356
354
  deploy_periodic_microservice(gem_path, variables, @parent)
357
355
  end
@@ -403,14 +401,46 @@ module OpenC3
403
401
  end
404
402
 
405
403
  def seed_database
406
- setting = SettingModel.get(name: 'source_url')
407
- SettingModel.set({ name: 'source_url', data: 'https://github.com/OpenC3/cosmos' }, scope: @scope) unless setting
408
- setting = SettingModel.get(name: 'rubygems_url')
409
- SettingModel.set({ name: 'rubygems_url', data: ENV['RUBYGEMS_URL'] || 'https://rubygems.org' }, scope: @scope) unless setting
410
- setting = SettingModel.get(name: 'pypi_url')
411
- SettingModel.set({ name: 'pypi_url', data: ENV['PYPI_URL'] || 'https://pypi.org' }, scope: @scope) unless setting
404
+ setting = SettingModel.get(name: "source_url")
405
+ SettingModel.set({name: "source_url", data: "https://github.com/OpenC3/cosmos"}, scope: @scope) unless setting
406
+ setting = SettingModel.get(name: "rubygems_url")
407
+ SettingModel.set({name: "rubygems_url", data: ENV["RUBYGEMS_URL"] || "https://rubygems.org"}, scope: @scope) unless setting
408
+ setting = SettingModel.get(name: "pypi_url")
409
+ SettingModel.set({name: "pypi_url", data: ENV["PYPI_URL"] || "https://pypi.org"}, scope: @scope) unless setting
412
410
  # Set the news feed to true by default, don't bother checking if it's already set
413
- SettingModel.set({ name: 'news_feed', data: true }, scope: @scope)
411
+ SettingModel.set({name: "news_feed", data: true}, scope: @scope)
412
+
413
+ setting = SettingModel.get(name: "system_health")
414
+ system_health_data = {
415
+ "cpu" => {
416
+ "redThreshold" => 90.0,
417
+ "yellowThreshold" => 80.0,
418
+ "snoozeMinutes" => 15,
419
+ "lastTriggerTimeRed" => nil, # timestamp or nil
420
+ "lastTriggerTimeYellow" => nil, # timestamp or nil
421
+ "sustainedSeconds" => 15
422
+ },
423
+ "memory" => {
424
+ "redThreshold" => 90.0,
425
+ "yellowThreshold" => 80.0,
426
+ "snoozeMinutes" => 15,
427
+ "lastTriggerTimeRed" => nil, # timestamp or nil
428
+ "lastTriggerTimeYellow" => nil, # timestamp or nil
429
+ "sustainedSeconds" => 15
430
+ },
431
+ "disk" => {
432
+ "redThreshold" => 90.0,
433
+ "yellowThreshold" => 80.0,
434
+ "snoozeMinutes" => 720, # 12 hours
435
+ "lastTriggerTimeRed" => nil, # timestamp or nil
436
+ "lastTriggerTimeYellow" => nil, # timestamp or nil
437
+ "sustainedSeconds" => 60
438
+ },
439
+ "global" => {
440
+ "enableAlerts" => true
441
+ }
442
+ }
443
+ SettingModel.set({name: "system_health", data: system_health_data}, scope: "DEFAULT") unless setting
414
444
  end
415
445
  end
416
446
  end
@@ -0,0 +1,93 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2025 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
+ # This file may also be used under the terms of a commercial license
17
+ # if purchased from OpenC3, Inc.
18
+
19
+ require 'openc3/top_level'
20
+ require 'openc3/models/model'
21
+ require 'openc3/models/scope_model'
22
+ require 'openc3/utilities/bucket'
23
+ require 'openc3/utilities/bucket_utilities'
24
+
25
+ module OpenC3
26
+ class ScriptEngineModel < Model
27
+ PRIMARY_KEY = 'openc3_script_engines'
28
+
29
+ attr_accessor :filename # Script Engine filename
30
+
31
+ # NOTE: The following three class methods are used by the ModelController
32
+ # and are reimplemented to enable various Model class methods to work
33
+ def self.get(name:, scope: nil)
34
+ super(PRIMARY_KEY, name: name)
35
+ end
36
+
37
+ def self.names(scope: nil)
38
+ array = []
39
+ all(scope: scope).each do |name, _script_engine|
40
+ array << name
41
+ end
42
+ array
43
+ end
44
+
45
+ def self.all(scope: nil)
46
+ tools = Store.hgetall(PRIMARY_KEY)
47
+ tools.each do |key, value|
48
+ tools[key] = JSON.parse(value, :allow_nan => true, :create_additions => true)
49
+ end
50
+ return tools
51
+ end
52
+
53
+ # Called by the PluginModel to allow this class to validate it's top-level keyword: "SCRIPT_ENGINE"
54
+ def self.handle_config(parser, keyword, parameters, plugin: nil, needs_dependencies: false, scope:)
55
+ case keyword
56
+ when 'SCRIPT_ENGINE'
57
+ parser.verify_num_parameters(1, 3, "SCRIPT_ENGINE <Extension> <Filename>")
58
+ return self.new(name: parameters[0], plugin: plugin, filename: parameters[1], scope: scope)
59
+ else
60
+ raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Script Engine: #{keyword} #{parameters.join(" ")}")
61
+ end
62
+ return nil
63
+ end
64
+
65
+ def initialize(
66
+ name:,
67
+ updated_at: nil,
68
+ plugin: nil,
69
+ filename: nil,
70
+ scope:
71
+ )
72
+ super(PRIMARY_KEY, name: name, plugin: plugin, updated_at: updated_at, scope: scope)
73
+ @filename = filename
74
+ end
75
+
76
+ def as_json(*a)
77
+ {
78
+ 'name' => @name,
79
+ 'updated_at' => @updated_at,
80
+ 'plugin' => @plugin,
81
+ 'filename' => @filename
82
+ }
83
+ end
84
+
85
+ def handle_config(parser, keyword, parameters)
86
+ raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Script Engine: #{keyword} #{parameters.join(" ")}")
87
+ end
88
+
89
+ def deploy(gem_path, variables, validate_only: false)
90
+ # Nothing to do
91
+ end
92
+ end
93
+ end
@@ -45,6 +45,7 @@ module OpenC3
45
45
  attr_accessor :pid
46
46
  attr_accessor :log
47
47
  attr_accessor :report
48
+ attr_accessor :script_engine
48
49
 
49
50
  # NOTE: The following three class methods are used by the ModelController
50
51
  # and are reimplemented to enable various Model class methods to work
@@ -69,9 +70,18 @@ module OpenC3
69
70
  if type == "running"
70
71
  keys = self.store.zrevrange("#{RUNNING_PRIMARY_KEY}__#{scope}__LIST", offset.to_i, offset.to_i + limit.to_i - 1)
71
72
  return [] if keys.empty?
72
- result = self.store.redis_pool.pipelined do
73
+ result = []
74
+ if $openc3_redis_cluster
75
+ # No pipelining for cluster mode
76
+ # because it requires using the same shard for all keys
73
77
  keys.each do |key|
74
- self.store.hget("#{RUNNING_PRIMARY_KEY}__#{scope}", key)
78
+ result << self.store.hget("#{RUNNING_PRIMARY_KEY}__#{scope}", key)
79
+ end
80
+ else
81
+ result = self.store.redis_pool.pipelined do
82
+ keys.each do |key|
83
+ self.store.hget("#{RUNNING_PRIMARY_KEY}__#{scope}", key)
84
+ end
75
85
  end
76
86
  end
77
87
  result = result.map do |r|
@@ -85,9 +95,18 @@ module OpenC3
85
95
  else
86
96
  keys = self.store.zrevrange("#{COMPLETED_PRIMARY_KEY}__#{scope}__LIST", offset.to_i, offset.to_i + limit.to_i - 1)
87
97
  return [] if keys.empty?
88
- result = self.store.redis_pool.pipelined do
98
+ result = []
99
+ if $openc3_redis_cluster
100
+ # No pipelining for cluster mode
101
+ # because it requires using the same shard for all keys
89
102
  keys.each do |key|
90
- self.store.hget("#{COMPLETED_PRIMARY_KEY}__#{scope}", key)
103
+ result << self.store.hget("#{COMPLETED_PRIMARY_KEY}__#{scope}", key)
104
+ end
105
+ else
106
+ result = self.store.redis_pool.pipelined do
107
+ keys.each do |key|
108
+ self.store.hget("#{COMPLETED_PRIMARY_KEY}__#{scope}", key)
109
+ end
91
110
  end
92
111
  end
93
112
  result = result.map do |r|
@@ -129,6 +148,7 @@ module OpenC3
129
148
  pid: nil,
130
149
  log: nil,
131
150
  report: nil,
151
+ script_engine: nil,
132
152
  updated_at: nil,
133
153
  scope:
134
154
  )
@@ -155,6 +175,7 @@ module OpenC3
155
175
  @pid = pid
156
176
  @log = log
157
177
  @report = report
178
+ @script_engine = script_engine
158
179
  end
159
180
 
160
181
  def is_complete?
@@ -239,6 +260,7 @@ module OpenC3
239
260
  'pid' => @pid,
240
261
  'log' => @log,
241
262
  'report' => @report,
263
+ 'script_engine' => @script_engine,
242
264
  'updated_at' => @updated_at,
243
265
  'scope' => @scope
244
266
  }
@@ -676,6 +676,8 @@ module OpenC3
676
676
  LimitsEventTopic.delete(@name, scope: @scope)
677
677
  Store.del("#{@scope}__openc3tlm__#{@name}")
678
678
  Store.del("#{@scope}__openc3cmd__#{@name}")
679
+ Store.del("#{@scope}__TELEMETRYCNTS__{#{@name}}")
680
+ Store.del("#{@scope}__COMMANDCNTS__{#{@name}}")
679
681
 
680
682
  # Note: these match the names of the services in deploy_microservices
681
683
  %w(MULTI DECOM COMMANDLOG DECOMCMDLOG PACKETLOG DECOMLOG REDUCER CLEANUP).each do |type|
@@ -795,6 +797,7 @@ module OpenC3
795
797
  if clear_old
796
798
  Store.del("#{@scope}__openc3tlm__#{target_name}")
797
799
  Store.del("#{@scope}__openc3tlm__#{target_name}__allitems")
800
+ Store.del("#{@scope}__TELEMETRYCNTS__{#{target_name}}")
798
801
  end
799
802
  packets.each do |packet_name, packet|
800
803
  Logger.debug "Configuring tlm packet: #{target_name} #{packet_name}"
@@ -816,7 +819,10 @@ module OpenC3
816
819
 
817
820
  def update_store_commands(packet_hash, clear_old: true)
818
821
  packet_hash.each do |target_name, packets|
819
- Store.del("#{@scope}__openc3cmd__#{target_name}") if clear_old
822
+ if clear_old
823
+ Store.del("#{@scope}__openc3cmd__#{target_name}")
824
+ Store.del("#{@scope}__COMMANDCNTS__{#{target_name}}")
825
+ end
820
826
  packets.each do |packet_name, packet|
821
827
  Logger.debug "Configuring cmd packet: #{target_name} #{packet_name}"
822
828
  begin
@@ -1300,11 +1306,22 @@ module OpenC3
1300
1306
  end
1301
1307
 
1302
1308
  def self.get_telemetry_counts(target_packets, scope:)
1303
- result = Store.redis_pool.pipelined do
1309
+ result = []
1310
+ if $openc3_redis_cluster
1311
+ # No pipelining for cluster mode
1312
+ # because it requires using the same shard for all keys
1304
1313
  target_packets.each do |target_name, packet_name|
1305
1314
  target_name = target_name.upcase
1306
1315
  packet_name = packet_name.upcase
1307
- Store.hget("#{scope}__TELEMETRYCNTS__{#{target_name}}", packet_name)
1316
+ result << Store.hget("#{scope}__TELEMETRYCNTS__{#{target_name}}", packet_name)
1317
+ end
1318
+ else
1319
+ result = Store.redis_pool.pipelined do
1320
+ target_packets.each do |target_name, packet_name|
1321
+ target_name = target_name.upcase
1322
+ packet_name = packet_name.upcase
1323
+ Store.hget("#{scope}__TELEMETRYCNTS__{#{target_name}}", packet_name)
1324
+ end
1308
1325
  end
1309
1326
  end
1310
1327
  counts = []
@@ -1351,11 +1368,22 @@ module OpenC3
1351
1368
  end
1352
1369
 
1353
1370
  def self.get_command_counts(target_packets, scope:)
1354
- result = Store.redis_pool.pipelined do
1371
+ result = []
1372
+ if $openc3_redis_cluster
1373
+ # No pipelining for cluster mode
1374
+ # because it requires using the same shard for all keys
1355
1375
  target_packets.each do |target_name, packet_name|
1356
1376
  target_name = target_name.upcase
1357
1377
  packet_name = packet_name.upcase
1358
- Store.hget("#{scope}__COMMANDCNTS__{#{target_name}}", packet_name)
1378
+ result << Store.hget("#{scope}__COMMANDCNTS__{#{target_name}}", packet_name)
1379
+ end
1380
+ else
1381
+ result = Store.redis_pool.pipelined do
1382
+ target_packets.each do |target_name, packet_name|
1383
+ target_name = target_name.upcase
1384
+ packet_name = packet_name.upcase
1385
+ Store.hget("#{scope}__COMMANDCNTS__{#{target_name}}", packet_name)
1386
+ end
1359
1387
  end
1360
1388
  end
1361
1389
  counts = []
@@ -662,7 +662,7 @@ module OpenC3
662
662
  @converted_bit_size = nil
663
663
  if params[0]
664
664
  @converted_type = params[0].upcase.intern
665
- raise parser.error("Invalid converted_type: #{@converted_type}.") unless [:INT, :UINT, :FLOAT, :STRING, :BLOCK, :RUBY_TIME].include? @converted_type
665
+ raise parser.error("Invalid converted_type: #{@converted_type}.") unless [:INT, :UINT, :FLOAT, :STRING, :BLOCK, :TIME].include? @converted_type
666
666
  end
667
667
  @converted_bit_size = Integer(params[1]) if params[1]
668
668
  if @converted_type.nil? or @converted_bit_size.nil?