openc3 5.14.2 → 5.15.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.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- 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
|