openc3 5.14.2 → 5.15.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/openc3cli +1 -1
- data/data/config/_id_items.yaml +2 -3
- data/data/config/telemetry_modifiers.yaml +0 -1
- data/lib/openc3/accessors/accessor.rb +3 -3
- data/lib/openc3/accessors/http_accessor.rb +1 -1
- data/lib/openc3/api/cmd_api.rb +50 -7
- data/lib/openc3/api/tlm_api.rb +16 -5
- data/lib/openc3/logs/buffered_packet_log_writer.rb +5 -0
- data/lib/openc3/logs/packet_log_reader.rb +8 -9
- data/lib/openc3/microservices/interface_microservice.rb +29 -18
- data/lib/openc3/microservices/trigger_group_microservice.rb +9 -9
- data/lib/openc3/models/auth_model.rb +5 -7
- data/lib/openc3/models/cvt_model.rb +9 -4
- data/lib/openc3/models/gem_model.rb +7 -5
- data/lib/openc3/models/metric_model.rb +8 -0
- data/lib/openc3/models/model.rb +21 -6
- data/lib/openc3/models/plugin_model.rb +8 -2
- data/lib/openc3/models/python_package_model.rb +3 -0
- data/lib/openc3/models/scope_model.rb +2 -2
- data/lib/openc3/models/target_model.rb +21 -28
- data/lib/openc3/models/tool_model.rb +2 -2
- data/lib/openc3/packets/json_packet.rb +5 -3
- data/lib/openc3/script/commands.rb +2 -2
- data/lib/openc3/script/storage.rb +28 -12
- data/lib/openc3/script/suite_results.rb +9 -9
- data/lib/openc3/system/system.rb +4 -5
- data/lib/openc3/top_level.rb +32 -23
- data/lib/openc3/topics/command_decom_topic.rb +2 -1
- data/lib/openc3/topics/command_topic.rb +2 -1
- data/lib/openc3/topics/telemetry_topic.rb +7 -2
- data/lib/openc3/utilities/authorization.rb +1 -1
- data/lib/openc3/utilities/aws_bucket.rb +21 -15
- data/lib/openc3/utilities/bucket.rb +1 -1
- data/lib/openc3/utilities/logger.rb +3 -3
- data/lib/openc3/utilities/process_manager.rb +15 -9
- data/lib/openc3/utilities/store_autoload.rb +33 -2
- data/lib/openc3/utilities/store_queued.rb +23 -24
- data/lib/openc3/version.rb +6 -6
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/package.json +2 -2
- data/templates/widget/package.json +2 -2
- metadata +16 -7
- data/templates/tool_angular/yarn.lock +0 -8155
- data/templates/tool_react/yarn.lock +0 -7201
- data/templates/tool_svelte/yarn.lock +0 -5519
- data/templates/tool_vue/yarn.lock +0 -9455
- data/templates/widget/yarn.lock +0 -9338
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e965c2b2463c93d4f1831b6d6cdfc53cae47bac8297e4335be407e420b37545e
|
4
|
+
data.tar.gz: 1f4a4d4f367daf99411d70d693f511a6550f911787d46f0602e6bc440edc19c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37956addc6a7019369e710ea02fcf8c71b114b049e83eeef7b7a0c2e99f17c2f685311db55697cb31a518bea8cc815647d370d0bdb9640259d76df86b79dff9a
|
7
|
+
data.tar.gz: f90a6beae03680d8fdc256ea2bf4dc937667a4a9d29bc6d3daccd33de02ea485ce808a52ed73a1ce251e0a9a7dc9ef3e9ccf1acdbe5ab8fa360f2dfbfbb104d8
|
data/bin/openc3cli
CHANGED
@@ -471,7 +471,7 @@ def load_plugin(plugin_file_path, scope:, plugin_hash_file: nil, force: false)
|
|
471
471
|
OpenC3::LocalMode.update_local_plugin(plugin_file_path, plugin_hash, scope: scope)
|
472
472
|
end
|
473
473
|
rescue => e
|
474
|
-
abort("Error installing plugin: #{scope}: #{plugin_file_path}\n#{e.
|
474
|
+
abort("Error installing plugin: #{scope}: #{plugin_file_path}\n#{e.formatted}")
|
475
475
|
end
|
476
476
|
else
|
477
477
|
# Outside Cluster
|
data/data/config/_id_items.yaml
CHANGED
@@ -4,13 +4,12 @@
|
|
4
4
|
description:
|
5
5
|
Bit size of this telemetry item. Zero or Negative values may be used
|
6
6
|
to indicate that a string fills the packet up to the offset from the end of
|
7
|
-
the packet specified by this value.
|
8
|
-
this is a derived parameter and the Data Type must be set to 'DERIVED'.
|
7
|
+
the packet specified by this value.
|
9
8
|
values: \d+
|
10
9
|
- name: Data Type
|
11
10
|
required: true
|
12
11
|
description: Data Type of this telemetry item
|
13
|
-
values: <%= %w(INT UINT FLOAT STRING BLOCK
|
12
|
+
values: <%= %w(INT UINT FLOAT STRING BLOCK) %>
|
14
13
|
- name: ID Value
|
15
14
|
required: true
|
16
15
|
description: The value of this telemetry item that uniquely identifies this telemetry packet
|
@@ -45,7 +45,6 @@ ID_ITEM:
|
|
45
45
|
required: true
|
46
46
|
description: Bit offset into the telemetry packet of the Most Significant Bit of this item.
|
47
47
|
May be negative to indicate on offset from the end of the packet.
|
48
|
-
Always use a bit offset of 0 for derived item.
|
49
48
|
values: '[-]?\d+'
|
50
49
|
<%= MetaConfigParser.load('_id_items.yaml').to_meta_config_yaml(4) %>
|
51
50
|
APPEND_ID_ITEM:
|
@@ -74,18 +74,18 @@ module OpenC3
|
|
74
74
|
return false
|
75
75
|
end
|
76
76
|
|
77
|
-
# If this is true it will
|
77
|
+
# If this is true it will enforce that COSMOS DERIVED items must have a
|
78
78
|
# write_conversion to be written
|
79
79
|
def enforce_derived_write_conversion(_item)
|
80
80
|
return true
|
81
81
|
end
|
82
82
|
|
83
83
|
def self.read_item(_item, _buffer)
|
84
|
-
raise "Must be defined by subclass"
|
84
|
+
raise "Must be defined by subclass if needed"
|
85
85
|
end
|
86
86
|
|
87
87
|
def self.write_item(_item, _value, _buffer)
|
88
|
-
raise "Must be defined by subclass"
|
88
|
+
raise "Must be defined by subclass if needed"
|
89
89
|
end
|
90
90
|
|
91
91
|
def self.read_items(items, buffer)
|
@@ -176,7 +176,7 @@ module OpenC3
|
|
176
176
|
when 'HTTP_STATUS', 'HTTP_PATH', 'HTTP_METHOD', 'HTTP_PACKET', 'HTTP_ERROR_PACKET', /^HTTP_QUERY_/, /^HTTP_HEADER_/
|
177
177
|
return false
|
178
178
|
else
|
179
|
-
return @body_accessor.enforce_derived_write_conversion
|
179
|
+
return @body_accessor.enforce_derived_write_conversion(item)
|
180
180
|
end
|
181
181
|
end
|
182
182
|
end
|
data/lib/openc3/api/cmd_api.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 2024, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -41,6 +41,8 @@ module OpenC3
|
|
41
41
|
'cmd_raw_no_checks',
|
42
42
|
'build_cmd',
|
43
43
|
'build_command', # DEPRECATED
|
44
|
+
'enable_cmd',
|
45
|
+
'disable_cmd',
|
44
46
|
'send_raw',
|
45
47
|
'get_all_cmds',
|
46
48
|
'get_all_commands', # DEPRECATED
|
@@ -131,6 +133,30 @@ module OpenC3
|
|
131
133
|
# build_command is DEPRECATED
|
132
134
|
alias build_command build_cmd
|
133
135
|
|
136
|
+
# Helper method for disable_cmd / enable_cmd
|
137
|
+
def _get_and_set_cmd(method, *args, scope: $openc3_scope, token: $openc3_token)
|
138
|
+
target_name, command_name = _extract_target_command_names(method, *args)
|
139
|
+
authorize(permission: 'admin', target_name: target_name, packet_name: command_name, scope: scope, token: token)
|
140
|
+
command = yield TargetModel.packet(target_name, command_name, type: :CMD, scope: scope)
|
141
|
+
TargetModel.set_packet(target_name, command_name, command, type: :CMD, scope: scope)
|
142
|
+
end
|
143
|
+
|
144
|
+
# @since 5.15.1
|
145
|
+
def enable_cmd(*args, scope: $openc3_scope, token: $openc3_token)
|
146
|
+
_get_and_set_cmd('enable_cmd', *args, scope: scope, token: token) do |command|
|
147
|
+
command['disabled'] = false
|
148
|
+
command
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# @since 5.15.1
|
153
|
+
def disable_cmd(*args, scope: $openc3_scope, token: $openc3_token)
|
154
|
+
_get_and_set_cmd('disable_cmd', *args, scope: scope, token: token) do |command|
|
155
|
+
command['disabled'] = true
|
156
|
+
command
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
134
160
|
# Send a raw binary string to the specified interface.
|
135
161
|
#
|
136
162
|
# @param interface_name [String] The interface to send the raw binary
|
@@ -178,10 +204,21 @@ module OpenC3
|
|
178
204
|
# @since 5.0.6
|
179
205
|
# @param target_name [String] Name of the target
|
180
206
|
# @return [Array<String>] Array of all command packet names
|
181
|
-
def get_all_cmd_names(target_name, scope: $openc3_scope, token: $openc3_token)
|
182
|
-
|
183
|
-
|
184
|
-
|
207
|
+
def get_all_cmd_names(target_name, hidden: false, scope: $openc3_scope, token: $openc3_token)
|
208
|
+
begin
|
209
|
+
packets = get_all_cmds(target_name, scope: scope, token: token)
|
210
|
+
rescue RuntimeError
|
211
|
+
packets = []
|
212
|
+
end
|
213
|
+
names = []
|
214
|
+
packets.each do |packet|
|
215
|
+
if hidden
|
216
|
+
names << packet['packet_name']
|
217
|
+
else
|
218
|
+
names << packet['packet_name'] unless packet['hidden']
|
219
|
+
end
|
220
|
+
end
|
221
|
+
return names
|
185
222
|
end
|
186
223
|
# get_all_command_names is DEPRECATED
|
187
224
|
alias get_all_command_names get_all_cmd_names
|
@@ -445,6 +482,12 @@ module OpenC3
|
|
445
482
|
cmd_params = cmd_params.transform_keys(&:upcase)
|
446
483
|
authorize(permission: 'cmd', target_name: target_name, packet_name: cmd_name, scope: scope, token: token)
|
447
484
|
packet = TargetModel.packet(target_name, cmd_name, type: :CMD, scope: scope)
|
485
|
+
if packet['disabled']
|
486
|
+
error = DisabledError.new
|
487
|
+
error.target_name = target_name
|
488
|
+
error.cmd_name = cmd_name
|
489
|
+
raise error
|
490
|
+
end
|
448
491
|
|
449
492
|
command = {
|
450
493
|
'target_name' => target_name,
|
@@ -474,7 +517,7 @@ module OpenC3
|
|
474
517
|
|
475
518
|
def _build_cmd_output_string(method_name, target_name, cmd_name, cmd_params, packet)
|
476
519
|
output_string = "#{method_name}(\""
|
477
|
-
output_string << target_name + ' ' + cmd_name
|
520
|
+
output_string << (target_name + ' ' + cmd_name)
|
478
521
|
if cmd_params.nil? or cmd_params.empty?
|
479
522
|
output_string << '")'
|
480
523
|
else
|
@@ -511,7 +554,7 @@ module OpenC3
|
|
511
554
|
params << "#{key} #{value}"
|
512
555
|
end
|
513
556
|
params = params.join(", ")
|
514
|
-
output_string << ' with ' + params + '")'
|
557
|
+
output_string << (' with ' + params + '")')
|
515
558
|
end
|
516
559
|
return output_string
|
517
560
|
end
|
data/lib/openc3/api/tlm_api.rb
CHANGED
@@ -139,7 +139,7 @@ module OpenC3
|
|
139
139
|
|
140
140
|
# See if this target has a tlm interface
|
141
141
|
interface_name = nil
|
142
|
-
InterfaceModel.all(scope: scope).each do |
|
142
|
+
InterfaceModel.all(scope: scope).each do |_name, interface|
|
143
143
|
if interface['tlm_target_names'].include? target_name
|
144
144
|
interface_name = interface['name']
|
145
145
|
break
|
@@ -287,10 +287,21 @@ module OpenC3
|
|
287
287
|
# @since 5.0.6
|
288
288
|
# @param target_name [String] Name of the target
|
289
289
|
# @return [Array<String>] Array of all telemetry packet names
|
290
|
-
def get_all_tlm_names(target_name, scope: $openc3_scope, token: $openc3_token)
|
291
|
-
|
292
|
-
|
293
|
-
|
290
|
+
def get_all_tlm_names(target_name, hidden: false, scope: $openc3_scope, token: $openc3_token)
|
291
|
+
begin
|
292
|
+
packets = get_all_tlm(target_name, scope: scope, token: token)
|
293
|
+
rescue RuntimeError
|
294
|
+
packets = []
|
295
|
+
end
|
296
|
+
names = []
|
297
|
+
packets.each do |packet|
|
298
|
+
if hidden
|
299
|
+
names << packet['packet_name']
|
300
|
+
else
|
301
|
+
names << packet['packet_name'] unless packet['hidden']
|
302
|
+
end
|
303
|
+
end
|
304
|
+
return names
|
294
305
|
end
|
295
306
|
alias get_all_telemetry_names get_all_tlm_names
|
296
307
|
|
@@ -80,6 +80,11 @@ module OpenC3
|
|
80
80
|
def buffered_write(entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id = nil, redis_topic = nil, redis_offset = '0-0', received_time_nsec_since_epoch: nil, extra: nil)
|
81
81
|
case entry_type
|
82
82
|
when :RAW_PACKET, :JSON_PACKET
|
83
|
+
# If we have data in the buffer, a file should always be open so that cycle time logic will run
|
84
|
+
unless @file
|
85
|
+
@mutex.synchronize { start_new_file() }
|
86
|
+
end
|
87
|
+
|
83
88
|
@buffer << [entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id, redis_topic, redis_offset, received_time_nsec_since_epoch, extra]
|
84
89
|
@buffer.sort! {|entry1, entry2| entry1[4] <=> entry2[4] }
|
85
90
|
if @buffer.length >= @buffer_depth
|
@@ -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 2024, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -96,9 +96,9 @@ module OpenC3
|
|
96
96
|
@max_read_size = @file.size
|
97
97
|
@max_read_size = MAX_READ_SIZE if @max_read_size > MAX_READ_SIZE
|
98
98
|
return read_file_header()
|
99
|
-
rescue =>
|
99
|
+
rescue => e
|
100
100
|
close()
|
101
|
-
raise
|
101
|
+
raise e
|
102
102
|
end
|
103
103
|
|
104
104
|
# Closes the current log file
|
@@ -134,9 +134,8 @@ module OpenC3
|
|
134
134
|
|
135
135
|
if flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_JSON_PACKET_ENTRY_TYPE_MASK
|
136
136
|
packet_index, time_nsec_since_epoch = entry[2..11].unpack('nQ>')
|
137
|
-
next_offset = 12
|
138
137
|
received_time_nsec_since_epoch, extra, json_data = handle_received_time_extra_and_data(entry, time_nsec_since_epoch, includes_received_time, includes_extra, cbor)
|
139
|
-
lookup_cmd_or_tlm, target_name, packet_name,
|
138
|
+
lookup_cmd_or_tlm, target_name, packet_name, _id, key_map = @packets[packet_index]
|
140
139
|
if cmd_or_tlm != lookup_cmd_or_tlm
|
141
140
|
raise "Packet type mismatch, packet:#{cmd_or_tlm}, lookup:#{lookup_cmd_or_tlm}"
|
142
141
|
end
|
@@ -148,8 +147,8 @@ module OpenC3
|
|
148
147
|
end
|
149
148
|
elsif flags & OPENC3_ENTRY_TYPE_MASK == OPENC3_RAW_PACKET_ENTRY_TYPE_MASK
|
150
149
|
packet_index, time_nsec_since_epoch = entry[2..11].unpack('nQ>')
|
151
|
-
received_time_nsec_since_epoch,
|
152
|
-
lookup_cmd_or_tlm, target_name, packet_name,
|
150
|
+
received_time_nsec_since_epoch, _extra, packet_data = handle_received_time_extra_and_data(entry, time_nsec_since_epoch, includes_received_time, includes_extra, cbor)
|
151
|
+
lookup_cmd_or_tlm, target_name, packet_name, _id = @packets[packet_index]
|
153
152
|
if cmd_or_tlm != lookup_cmd_or_tlm
|
154
153
|
raise "Packet type mismatch, packet:#{cmd_or_tlm}, lookup:#{lookup_cmd_or_tlm}"
|
155
154
|
end
|
@@ -220,9 +219,9 @@ module OpenC3
|
|
220
219
|
else
|
221
220
|
raise "Invalid Entry Flags: #{flags}"
|
222
221
|
end
|
223
|
-
rescue =>
|
222
|
+
rescue => e
|
224
223
|
close()
|
225
|
-
raise
|
224
|
+
raise e
|
226
225
|
end
|
227
226
|
|
228
227
|
# @return [Integer] The size of the log file being processed
|
@@ -126,7 +126,7 @@ module OpenC3
|
|
126
126
|
begin
|
127
127
|
@logger.info "#{@interface.name}: interface_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
|
128
128
|
@interface.interface_cmd(params['cmd_name'], *params['cmd_params'])
|
129
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
129
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
130
130
|
rescue => e
|
131
131
|
@logger.error "#{@interface.name}: interface_cmd: #{e.formatted}"
|
132
132
|
next e.message
|
@@ -138,7 +138,7 @@ module OpenC3
|
|
138
138
|
begin
|
139
139
|
@logger.info "#{@interface.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
|
140
140
|
@interface.protocol_cmd(params['cmd_name'], *params['cmd_params'], read_write: params['read_write'], index: params['index'])
|
141
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
141
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
142
142
|
rescue => e
|
143
143
|
@logger.error "#{@interface.name}: protocol_cmd: #{e.formatted}"
|
144
144
|
next e.message
|
@@ -206,7 +206,7 @@ module OpenC3
|
|
206
206
|
@interface.write(command)
|
207
207
|
CommandTopic.write_packet(command, scope: @scope)
|
208
208
|
CommandDecomTopic.write_packet(command, scope: @scope)
|
209
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
209
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
210
210
|
next 'SUCCESS'
|
211
211
|
else
|
212
212
|
next "Interface not connected: #{@interface.name}"
|
@@ -298,7 +298,7 @@ module OpenC3
|
|
298
298
|
begin
|
299
299
|
@logger.info "#{@router.name}: router_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
|
300
300
|
@router.interface_cmd(params['cmd_name'], *params['cmd_params'])
|
301
|
-
RouterStatusModel.set(@router.as_json(:allow_nan => true), scope: @scope)
|
301
|
+
RouterStatusModel.set(@router.as_json(:allow_nan => true), queued: true, scope: @scope)
|
302
302
|
rescue => e
|
303
303
|
@logger.error "#{@router.name}: router_cmd: #{e.formatted}"
|
304
304
|
next e.message
|
@@ -310,7 +310,7 @@ module OpenC3
|
|
310
310
|
begin
|
311
311
|
@logger.info "#{@router.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
|
312
312
|
@router.protocol_cmd(params['cmd_name'], *params['cmd_params'], read_write: params['read_write'], index: params['index'])
|
313
|
-
RouterStatusModel.set(@router.as_json(:allow_nan => true), scope: @scope)
|
313
|
+
RouterStatusModel.set(@router.as_json(:allow_nan => true), queued: true, scope: @scope)
|
314
314
|
rescue => e
|
315
315
|
@logger.error "#{@router.name}: protoco_cmd: #{e.formatted}"
|
316
316
|
next e.message
|
@@ -335,7 +335,7 @@ module OpenC3
|
|
335
335
|
|
336
336
|
begin
|
337
337
|
@router.write(packet)
|
338
|
-
RouterStatusModel.set(@router.as_json(:allow_nan => true), scope: @scope)
|
338
|
+
RouterStatusModel.set(@router.as_json(:allow_nan => true), queued: true, scope: @scope)
|
339
339
|
next 'SUCCESS'
|
340
340
|
rescue => e
|
341
341
|
@logger.error "#{@router.name}: #{e.formatted}"
|
@@ -352,6 +352,7 @@ module OpenC3
|
|
352
352
|
def initialize(name)
|
353
353
|
@mutex = Mutex.new
|
354
354
|
super(name)
|
355
|
+
|
355
356
|
@interface_or_router = self.class.name.to_s.split("Microservice")[0].upcase.split("::")[-1]
|
356
357
|
if @interface_or_router == 'INTERFACE'
|
357
358
|
@metric.set(name: 'interface_tlm_total', value: @count, type: 'counter')
|
@@ -359,7 +360,6 @@ module OpenC3
|
|
359
360
|
@metric.set(name: 'router_cmd_total', value: @count, type: 'counter')
|
360
361
|
end
|
361
362
|
|
362
|
-
@scope = name.split("__")[0]
|
363
363
|
interface_name = name.split("__")[2]
|
364
364
|
if @interface_or_router == 'INTERFACE'
|
365
365
|
@interface = InterfaceModel.get_model(name: interface_name, scope: @scope).build
|
@@ -400,6 +400,17 @@ module OpenC3
|
|
400
400
|
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
401
401
|
end
|
402
402
|
|
403
|
+
@queued = false
|
404
|
+
@interface.options.each do |option_name, option_values|
|
405
|
+
case option_name.upcase
|
406
|
+
when 'OPTIMIZE_THROUGHPUT'
|
407
|
+
@queued = true
|
408
|
+
update_interval = option_values[0].to_f
|
409
|
+
EphemeralStoreQueued.instance.set_update_interval(update_interval)
|
410
|
+
StoreQueued.instance.set_update_interval(update_interval)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
403
414
|
@interface_thread_sleeper = Sleeper.new
|
404
415
|
@cancel_thread = false
|
405
416
|
@connection_failed_messages = []
|
@@ -432,9 +443,9 @@ module OpenC3
|
|
432
443
|
|
433
444
|
@interface.state = 'ATTEMPTING'
|
434
445
|
if @interface_or_router == 'INTERFACE'
|
435
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
446
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
436
447
|
else
|
437
|
-
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
448
|
+
RouterStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
438
449
|
end
|
439
450
|
@interface # Return the interface/router since we may have recreated it
|
440
451
|
# Need to rescue Exception so we cover LoadError
|
@@ -507,15 +518,15 @@ module OpenC3
|
|
507
518
|
disconnect(false)
|
508
519
|
end
|
509
520
|
if @interface_or_router == 'INTERFACE'
|
510
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
521
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
511
522
|
else
|
512
|
-
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
523
|
+
RouterStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
513
524
|
end
|
514
525
|
@logger.info "#{@interface.name}: Stopped packet reading"
|
515
526
|
end
|
516
527
|
|
517
528
|
def handle_packet(packet)
|
518
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
529
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
519
530
|
packet.received_time = Time.now.sys unless packet.received_time
|
520
531
|
|
521
532
|
if packet.stored
|
@@ -557,7 +568,7 @@ module OpenC3
|
|
557
568
|
unknown_packet.extra = packet.extra
|
558
569
|
packet = unknown_packet
|
559
570
|
json_hash = CvtModel.build_json_from_packet(packet)
|
560
|
-
CvtModel.set(json_hash, target_name: packet.target_name, packet_name: packet.packet_name, scope: @scope)
|
571
|
+
CvtModel.set(json_hash, target_name: packet.target_name, packet_name: packet.packet_name, queued: @queued, scope: @scope)
|
561
572
|
num_bytes_to_print = [UNKNOWN_BYTES_TO_PRINT, packet.length].min
|
562
573
|
data = packet.buffer(false)[0..(num_bytes_to_print - 1)]
|
563
574
|
prefix = data.each_byte.map { | byte | sprintf("%02X", byte) }.join()
|
@@ -566,7 +577,7 @@ module OpenC3
|
|
566
577
|
|
567
578
|
# Write to stream
|
568
579
|
packet.received_count += 1
|
569
|
-
TelemetryTopic.write_packet(packet, scope: @scope)
|
580
|
+
TelemetryTopic.write_packet(packet, queued: @queued, scope: @scope)
|
570
581
|
end
|
571
582
|
|
572
583
|
def handle_connection_failed(connect_error)
|
@@ -629,9 +640,9 @@ module OpenC3
|
|
629
640
|
end
|
630
641
|
@interface.state = 'CONNECTED'
|
631
642
|
if @interface_or_router == 'INTERFACE'
|
632
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
643
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
633
644
|
else
|
634
|
-
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
645
|
+
RouterStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
635
646
|
end
|
636
647
|
@logger.info "#{@interface.name}: Connection Success"
|
637
648
|
end
|
@@ -661,9 +672,9 @@ module OpenC3
|
|
661
672
|
else
|
662
673
|
@interface.state = 'DISCONNECTED'
|
663
674
|
if @interface_or_router == 'INTERFACE'
|
664
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
675
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
665
676
|
else
|
666
|
-
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
677
|
+
RouterStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
667
678
|
end
|
668
679
|
end
|
669
680
|
end
|
@@ -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 2024, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -418,7 +418,7 @@ module OpenC3
|
|
418
418
|
when 'OR'
|
419
419
|
return left || right ? 1 : 0
|
420
420
|
end
|
421
|
-
rescue ArgumentError
|
421
|
+
rescue ArgumentError
|
422
422
|
message = "invalid evaluate: (#{left} #{operator} #{right})"
|
423
423
|
notify(name: name, severity: 'error', message: message)
|
424
424
|
return -1
|
@@ -447,7 +447,7 @@ module OpenC3
|
|
447
447
|
if visited["#{head.name}__P"][trigger.name]
|
448
448
|
# Not sure if this is posible as on create it validates that the dependents are already created
|
449
449
|
message = "loop detected from #{head.name} -> #{trigger.name} path: #{visited["#{head.name}__P"]}"
|
450
|
-
notify(name: trigger.name, severity: 'error', message:
|
450
|
+
notify(name: trigger.name, severity: 'error', message: message)
|
451
451
|
return visited["#{trigger.name}__R"] = -1
|
452
452
|
end
|
453
453
|
trigger.roots.each do | root_trigger_name |
|
@@ -455,7 +455,7 @@ module OpenC3
|
|
455
455
|
root_trigger = triggers[root_trigger_name]
|
456
456
|
if head.name == root_trigger.name
|
457
457
|
message = "loop detected from #{head.name} -> #{root_trigger_name} path: #{visited["#{head.name}__P"]}"
|
458
|
-
notify(name: trigger.name, severity: 'error', message:
|
458
|
+
notify(name: trigger.name, severity: 'error', message: message)
|
459
459
|
return visited["#{trigger.name}__R"] = -1
|
460
460
|
end
|
461
461
|
result = evaluate_trigger(
|
@@ -474,9 +474,9 @@ module OpenC3
|
|
474
474
|
else
|
475
475
|
right = operand_value(operand: trigger.right, other: trigger.left, visited: visited)
|
476
476
|
end
|
477
|
-
rescue =>
|
477
|
+
rescue => e
|
478
478
|
# This will primarily happen when the user inputs a bad Regexp
|
479
|
-
notify(name: trigger.name, severity: 'error', message:
|
479
|
+
notify(name: trigger.name, severity: 'error', message: e.message)
|
480
480
|
return visited["#{trigger.name}__R"] = -1
|
481
481
|
end
|
482
482
|
# Convert the standard '==' and '!=' into Ruby Regexp operators
|
@@ -560,7 +560,7 @@ module OpenC3
|
|
560
560
|
while @read_topic
|
561
561
|
begin
|
562
562
|
Topic.read_topics(@topics) do |topic, _msg_id, msg_hash, _redis|
|
563
|
-
@logger.debug "TriggerGroupManager block_for_updates: #{topic} #{msg_hash
|
563
|
+
@logger.debug "TriggerGroupManager block_for_updates: #{topic} #{msg_hash}"
|
564
564
|
if topic != @share.trigger_base.autonomic_topic
|
565
565
|
packet = JsonPacket.new(:TLM, msg_hash['target_name'], msg_hash['packet_name'], msg_hash['time'].to_i, false, msg_hash["json_data"])
|
566
566
|
@share.packet_base.add(topic: topic, packet: packet)
|
@@ -580,7 +580,7 @@ module OpenC3
|
|
580
580
|
def shutdown
|
581
581
|
@read_topic = false
|
582
582
|
@cancel_thread = true
|
583
|
-
@worker_count.times do |
|
583
|
+
@worker_count.times do | _i |
|
584
584
|
@queue << nil
|
585
585
|
end
|
586
586
|
end
|
@@ -635,7 +635,7 @@ module OpenC3
|
|
635
635
|
begin
|
636
636
|
AutonomicTopic.read_topics(@topics) do |_topic, _msg_id, msg_hash, _redis|
|
637
637
|
break if @cancel_thread
|
638
|
-
@logger.debug "TriggerGroupMicroservice block_for_updates: #{msg_hash
|
638
|
+
@logger.debug "TriggerGroupMicroservice block_for_updates: #{msg_hash}"
|
639
639
|
# Process trigger notifications created by TriggerModel notify
|
640
640
|
if msg_hash['type'] == 'trigger'
|
641
641
|
data = JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true)
|
@@ -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 2024, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
20
20
|
# This file may also be used under the terms of a commercial license
|
@@ -31,11 +31,11 @@ module OpenC3
|
|
31
31
|
@@token_cache = nil
|
32
32
|
@@token_cache_time = nil
|
33
33
|
|
34
|
-
def self.
|
34
|
+
def self.set?(key = PRIMARY_KEY)
|
35
35
|
Store.exists(key) == 1
|
36
36
|
end
|
37
37
|
|
38
|
-
def self.verify(token
|
38
|
+
def self.verify(token)
|
39
39
|
return false if token.nil? or token.empty?
|
40
40
|
|
41
41
|
token_hash = hash(token)
|
@@ -47,7 +47,7 @@ module OpenC3
|
|
47
47
|
|
48
48
|
# Handle a service password - Generally only used by ScriptRunner
|
49
49
|
service_password = ENV['OPENC3_SERVICE_PASSWORD']
|
50
|
-
return true if service_password and service_password == token
|
50
|
+
return true if service_password and service_password == token
|
51
51
|
|
52
52
|
return false
|
53
53
|
end
|
@@ -55,15 +55,13 @@ module OpenC3
|
|
55
55
|
def self.set(token, old_token, key = PRIMARY_KEY)
|
56
56
|
raise "token must not be nil or empty" if token.nil? or token.empty?
|
57
57
|
|
58
|
-
if
|
58
|
+
if set?(key)
|
59
59
|
raise "old_token must not be nil or empty" if old_token.nil? or old_token.empty?
|
60
60
|
raise "old_token incorrect" unless verify(old_token)
|
61
61
|
end
|
62
62
|
Store.set(key, hash(token))
|
63
63
|
end
|
64
64
|
|
65
|
-
private
|
66
|
-
|
67
65
|
def self.hash(token)
|
68
66
|
Digest::SHA2.hexdigest token
|
69
67
|
end
|
@@ -21,6 +21,7 @@
|
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
23
|
require 'openc3/utilities/store'
|
24
|
+
require 'openc3/utilities/store_queued'
|
24
25
|
require 'openc3/models/target_model'
|
25
26
|
|
26
27
|
module OpenC3
|
@@ -42,12 +43,16 @@ module OpenC3
|
|
42
43
|
end
|
43
44
|
|
44
45
|
# Set the current value table for a target, packet
|
45
|
-
def self.set(hash, target_name:, packet_name:, scope: $openc3_scope)
|
46
|
+
def self.set(hash, target_name:, packet_name:, queued: false, scope: $openc3_scope)
|
46
47
|
packet_json = JSON.generate(hash.as_json(:allow_nan => true))
|
47
48
|
key = "#{scope}__tlm__#{target_name}"
|
48
49
|
tgt_pkt_key = key + "__#{packet_name}"
|
49
50
|
@@packet_cache[tgt_pkt_key] = [Time.now, hash]
|
50
|
-
|
51
|
+
if queued
|
52
|
+
StoreQueued.hset(key, packet_name, packet_json)
|
53
|
+
else
|
54
|
+
Store.hset(key, packet_name, packet_json)
|
55
|
+
end
|
51
56
|
end
|
52
57
|
|
53
58
|
# Get the hash for packet in the CVT
|
@@ -68,7 +73,7 @@ module OpenC3
|
|
68
73
|
end
|
69
74
|
|
70
75
|
# Set an item in the current value table
|
71
|
-
def self.set_item(target_name, packet_name, item_name, value, type:, scope: $openc3_scope)
|
76
|
+
def self.set_item(target_name, packet_name, item_name, value, type:, queued: false, scope: $openc3_scope)
|
72
77
|
hash = get(target_name: target_name, packet_name: packet_name, cache_timeout: nil, scope: scope)
|
73
78
|
case type
|
74
79
|
when :WITH_UNITS
|
@@ -87,7 +92,7 @@ module OpenC3
|
|
87
92
|
else
|
88
93
|
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
89
94
|
end
|
90
|
-
set(hash, target_name: target_name, packet_name: packet_name, scope: scope)
|
95
|
+
set(hash, target_name: target_name, packet_name: packet_name, queued: queued, scope: scope)
|
91
96
|
end
|
92
97
|
|
93
98
|
# Get an item from the current value table
|
@@ -102,13 +102,15 @@ module OpenC3
|
|
102
102
|
raise err
|
103
103
|
end
|
104
104
|
|
105
|
-
def self.destroy(name)
|
105
|
+
def self.destroy(name, log_and_raise_needed_errors: true)
|
106
106
|
gem_name, version = self.extract_name_and_version(name)
|
107
107
|
plugin_gem_names = PluginModel.gem_names
|
108
108
|
if plugin_gem_names.include?(name)
|
109
|
-
|
110
|
-
|
111
|
-
|
109
|
+
if log_and_raise_needed_errors
|
110
|
+
message = "Gem file #{name} can't be uninstalled because needed by installed plugin"
|
111
|
+
Logger.error message
|
112
|
+
raise message
|
113
|
+
end
|
112
114
|
else
|
113
115
|
begin
|
114
116
|
Gem::Uninstaller.new(gem_name, {:version => version, :force => true}).uninstall
|
@@ -131,7 +133,7 @@ module OpenC3
|
|
131
133
|
GemModel.names.each do |gem_full_name|
|
132
134
|
gem_name, gem_version = GemModel.extract_name_and_version(gem_full_name)
|
133
135
|
if gem_name == keep_gem_name and gem_version != keep_gem_version
|
134
|
-
GemModel.destroy(gem_full_name)
|
136
|
+
GemModel.destroy(gem_full_name, log_and_raise_needed_errors: false)
|
135
137
|
end
|
136
138
|
end
|
137
139
|
end
|
@@ -42,6 +42,14 @@ module OpenC3
|
|
42
42
|
super("#{scope}#{PRIMARY_KEY}")
|
43
43
|
end
|
44
44
|
|
45
|
+
# Sets (updates) the redis hash of this model
|
46
|
+
# Queued defaults to true for MetricModel
|
47
|
+
def self.set(json, scope:, queued: true)
|
48
|
+
json[:scope] = scope
|
49
|
+
json.transform_keys!(&:to_sym)
|
50
|
+
self.new(**json).create(force: true, queued: queued)
|
51
|
+
end
|
52
|
+
|
45
53
|
def self.destroy(scope:, name:)
|
46
54
|
EphemeralStore.hdel("#{scope}#{PRIMARY_KEY}", name)
|
47
55
|
end
|