openc3 5.15.0 → 5.15.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/data/config/widgets.yaml +1 -1
- data/lib/openc3/accessors/json_accessor.rb +11 -3
- data/lib/openc3/api/cmd_api.rb +33 -1
- data/lib/openc3/io/posix_serial_driver.rb +20 -5
- data/lib/openc3/logs/packet_log_reader.rb +8 -9
- data/lib/openc3/microservices/trigger_group_microservice.rb +9 -9
- data/lib/openc3/models/auth_model.rb +5 -7
- data/lib/openc3/script/commands.rb +2 -2
- data/lib/openc3/script/storage.rb +28 -13
- data/lib/openc3/script/web_socket_api.rb +10 -0
- data/lib/openc3/system/system.rb +4 -5
- data/lib/openc3/top_level.rb +32 -23
- data/lib/openc3/utilities/authorization.rb +1 -1
- data/lib/openc3/utilities/store_autoload.rb +11 -7
- data/lib/openc3/version.rb +5 -5
- data/templates/target/targets/TARGET/lib/target.py +2 -0
- 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 +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a39dab08bb9810376520e75a7bf3a6c63d30ad54b93566b82a849d780693a366
|
4
|
+
data.tar.gz: 65d282829dba0706cbe0e32603e51ad8ab3dfc0fdaf37d9bd400787bb7a1cb03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12bffefe104e90e159c16bcc54ab53745e86a97bfb762c7e0e25141d6bd3c91ad6bb8827017d915dfb459b2fc69ea7365c97e7fa22236abb16ff0d73d8d485d7
|
7
|
+
data.tar.gz: b2efa2780f97e2aa3392cc483534d949be4fb27032dbc3e52015ebfa89da08d234e5777c50dbfa09e477357d3b5ca67aba847f8f5d723676d2331da84e880f7f
|
data/data/config/widgets.yaml
CHANGED
@@ -1302,7 +1302,7 @@ Interactive Widgets:
|
|
1302
1302
|
|
1303
1303
|
Button code can get rather complex so remember to use string concatenation
|
1304
1304
|
to make things more readable. If you use `+` newlines are inserted automatically
|
1305
|
-
during string concatenation. If you use
|
1305
|
+
during string concatenation. If you use `\\` you'll need to separate lines with a
|
1306
1306
|
single semicolon `;`. COSMOS uses double semicolon `;;` to indicate lines should
|
1307
1307
|
be evaluated separately. Note that all OpenC3 commands (using api.cmd) must be
|
1308
1308
|
separated by `;;`.
|
@@ -18,8 +18,16 @@
|
|
18
18
|
|
19
19
|
require 'json'
|
20
20
|
require 'jsonpath'
|
21
|
+
require 'openc3/io/json_rpc'
|
21
22
|
require 'openc3/accessors/accessor'
|
22
23
|
|
24
|
+
# Monkey patch JsonPath to enable create_additions and allow_nan to support binary strings, and NaN, Infinity, -Infinity
|
25
|
+
class JsonPath
|
26
|
+
def self.process_object(obj_or_str, opts = {})
|
27
|
+
obj_or_str.is_a?(String) ? MultiJson.decode(obj_or_str, max_nesting: opts[:max_nesting], create_additions: true, allow_nan: true) : obj_or_str
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
23
31
|
module OpenC3
|
24
32
|
class JsonAccessor < Accessor
|
25
33
|
def self.read_item(item, buffer)
|
@@ -33,7 +41,7 @@ module OpenC3
|
|
33
41
|
|
34
42
|
# Convert to ruby objects
|
35
43
|
if String === buffer
|
36
|
-
decoded = JSON.parse(buffer, :allow_nan => true)
|
44
|
+
decoded = JSON.parse(buffer, :allow_nan => true, :create_additions => true)
|
37
45
|
else
|
38
46
|
decoded = buffer
|
39
47
|
end
|
@@ -43,7 +51,7 @@ module OpenC3
|
|
43
51
|
|
44
52
|
# Update buffer
|
45
53
|
if String === buffer
|
46
|
-
buffer.replace(JSON.generate(decoded, :allow_nan => true))
|
54
|
+
buffer.replace(JSON.generate(decoded.as_json, :allow_nan => true))
|
47
55
|
end
|
48
56
|
|
49
57
|
return value
|
@@ -52,7 +60,7 @@ module OpenC3
|
|
52
60
|
def self.read_items(items, buffer)
|
53
61
|
# Prevent JsonPath from decoding every call
|
54
62
|
if String === buffer
|
55
|
-
decoded = JSON.parse(buffer, :allow_nan => true)
|
63
|
+
decoded = JSON.parse(buffer, :allow_nan => true, :create_additions => true)
|
56
64
|
else
|
57
65
|
decoded = buffer
|
58
66
|
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
|
@@ -456,6 +482,12 @@ module OpenC3
|
|
456
482
|
cmd_params = cmd_params.transform_keys(&:upcase)
|
457
483
|
authorize(permission: 'cmd', target_name: target_name, packet_name: cmd_name, scope: scope, token: token)
|
458
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
|
459
491
|
|
460
492
|
command = {
|
461
493
|
'target_name' => target_name,
|
@@ -14,10 +14,10 @@
|
|
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
|
-
# This file may also be used under the terms of a commercial license
|
20
|
+
# This file may also be used under the terms of a commercial license
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
23
|
require 'fcntl'
|
@@ -82,12 +82,17 @@ module OpenC3
|
|
82
82
|
tio.ospeed = baud_rate
|
83
83
|
@handle.tcflush(Termios::TCIOFLUSH)
|
84
84
|
@handle.tcsetattr(Termios::TCSANOW, tio)
|
85
|
+
|
86
|
+
@pipe_reader, @pipe_writer = IO.pipe
|
87
|
+
@readers = [@handle, @pipe_reader]
|
85
88
|
end
|
86
89
|
|
87
90
|
# (see SerialDriver#close)
|
88
91
|
def close
|
89
92
|
if @handle
|
90
93
|
# Close the serial Port
|
94
|
+
@pipe_writer.write('.')
|
95
|
+
@pipe_writer.close
|
91
96
|
@handle.close
|
92
97
|
@handle = nil
|
93
98
|
end
|
@@ -132,9 +137,19 @@ module OpenC3
|
|
132
137
|
begin
|
133
138
|
data = @handle.read_nonblock(65535)
|
134
139
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
135
|
-
|
136
|
-
|
137
|
-
|
140
|
+
begin
|
141
|
+
read_ready, _ = IO.fast_select(@readers, nil, nil, @read_timeout)
|
142
|
+
rescue IOError
|
143
|
+
@pipe_reader.close unless @pipe_reader.closed?
|
144
|
+
return ""
|
145
|
+
end
|
146
|
+
if read_ready
|
147
|
+
if read_ready.include?(@pipe_reader)
|
148
|
+
@pipe_reader.close unless @pipe_reader.closed?
|
149
|
+
return ""
|
150
|
+
else
|
151
|
+
retry
|
152
|
+
end
|
138
153
|
else
|
139
154
|
raise Timeout::Error, "Read Timeout"
|
140
155
|
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
|
@@ -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
|
@@ -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
|
@@ -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,7 +96,7 @@ module OpenC3
|
|
96
96
|
|
97
97
|
# Get the command and validate the parameters
|
98
98
|
command = $api_server.get_cmd(target_name, cmd_name, scope: scope)
|
99
|
-
cmd_params.each do |param_name,
|
99
|
+
cmd_params.each do |param_name, _param_value|
|
100
100
|
param = command['items'].find { |item| item['name'] == param_name }
|
101
101
|
unless param
|
102
102
|
raise "Packet item '#{target_name} #{cmd_name} #{param_name}' does not exist"
|
@@ -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
|
@@ -43,8 +43,8 @@ module OpenC3
|
|
43
43
|
if response.nil? || response.status != 200
|
44
44
|
raise "Failed to delete #{delete_path}"
|
45
45
|
end
|
46
|
-
rescue =>
|
47
|
-
raise "Failed deleting #{path} due to #{
|
46
|
+
rescue => e
|
47
|
+
raise "Failed deleting #{path} due to #{e.message}"
|
48
48
|
end
|
49
49
|
nil
|
50
50
|
end
|
@@ -84,8 +84,8 @@ module OpenC3
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
87
|
-
rescue =>
|
88
|
-
raise "Failed to write #{upload_path} due to #{
|
87
|
+
rescue => e
|
88
|
+
raise "Failed to write #{upload_path} due to #{e.message}"
|
89
89
|
end
|
90
90
|
nil
|
91
91
|
end
|
@@ -115,19 +115,33 @@ module OpenC3
|
|
115
115
|
end
|
116
116
|
|
117
117
|
return _get_storage_file("#{part}/#{path}", scope: scope)
|
118
|
-
rescue =>
|
118
|
+
rescue => e
|
119
119
|
if part == "targets_modified"
|
120
120
|
part = "targets"
|
121
121
|
redo
|
122
122
|
else
|
123
|
-
raise
|
123
|
+
raise e
|
124
124
|
end
|
125
125
|
end
|
126
126
|
break
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
|
130
|
+
def get_download_url(path, scope: $openc3_scope)
|
131
|
+
targets = "targets_modified" # First try targets_modified
|
132
|
+
response = $api_server.request('get', "/openc3-api/storage/exists/#{scope}/#{targets}/#{path}", query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
|
133
|
+
if response.status != 200
|
134
|
+
targets = "targets" # Next try targets
|
135
|
+
response = $api_server.request('get', "/openc3-api/storage/exists/#{scope}/#{targets}/#{path}", query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
|
136
|
+
if response.status != 200
|
137
|
+
raise "File not found: #{path} in scope: #{scope}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
endpoint = "/openc3-api/storage/download/#{scope}/#{targets}/#{path}"
|
141
|
+
# external must be true because we're using this URL from the frontend
|
142
|
+
result = _get_presigned_request(endpoint, external: true, scope: scope)
|
143
|
+
return result['url']
|
144
|
+
end
|
131
145
|
|
132
146
|
# These are helper methods ... should not be used directly
|
133
147
|
|
@@ -161,7 +175,8 @@ module OpenC3
|
|
161
175
|
if $openc3_in_cluster
|
162
176
|
case ENV['OPENC3_CLOUD']
|
163
177
|
when 'local'
|
164
|
-
|
178
|
+
bucket_url = ENV["OPENC3_BUCKET_URL"] || "http://openc3-minio:9000"
|
179
|
+
URI.parse("#{bucket_url}#{url}")
|
165
180
|
when 'aws'
|
166
181
|
URI.parse("https://s3.#{ENV['AWS_REGION']}.amazonaws.com" + url)
|
167
182
|
when 'gcp'
|
@@ -175,11 +190,11 @@ module OpenC3
|
|
175
190
|
end
|
176
191
|
end
|
177
192
|
|
178
|
-
def _get_presigned_request(endpoint, scope: $openc3_scope)
|
179
|
-
if
|
180
|
-
response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET', internal: true }, scope: scope)
|
181
|
-
else
|
193
|
+
def _get_presigned_request(endpoint, external: nil, scope: $openc3_scope)
|
194
|
+
if external or !$openc3_in_cluster
|
182
195
|
response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
|
196
|
+
else
|
197
|
+
response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET', internal: true }, scope: scope)
|
183
198
|
end
|
184
199
|
if response.nil? || response.status != 201
|
185
200
|
raise "Failed to get presigned URL for #{endpoint}"
|
@@ -215,6 +215,16 @@ module OpenC3
|
|
215
215
|
end
|
216
216
|
end
|
217
217
|
|
218
|
+
# All Scripts WebSocket
|
219
|
+
class AllScriptsWebSocketApi < ScriptWebSocketApi
|
220
|
+
def initialize(url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
|
221
|
+
@identifier = {
|
222
|
+
channel: "AllScriptsChannel",
|
223
|
+
}
|
224
|
+
super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
218
228
|
# Log Messages WebSocket
|
219
229
|
class MessagesWebSocketApi < CmdTlmWebSocketApi
|
220
230
|
def initialize(history_count: 0, start_time: nil, end_time: nil, level: nil, types: nil, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
|
data/lib/openc3/system/system.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
|
@@ -31,7 +31,6 @@ require 'openc3/system/target'
|
|
31
31
|
require 'openc3/utilities/bucket'
|
32
32
|
require 'openc3/utilities/zip'
|
33
33
|
require 'openc3/topics/limits_event_topic'
|
34
|
-
require 'thread'
|
35
34
|
require 'fileutils'
|
36
35
|
|
37
36
|
module OpenC3
|
@@ -109,7 +108,7 @@ module OpenC3
|
|
109
108
|
# target.txt must be configured to either use all files in cmd_tlm folder (default)
|
110
109
|
# or have a predetermined empty file like dynamic_tlm.txt
|
111
110
|
bucket_path = "#{scope}/targets_modified/#{target_name}/cmd_tlm"
|
112
|
-
|
111
|
+
_, files = bucket.list_files(bucket: ENV['OPENC3_CONFIG_BUCKET'], path: bucket_path)
|
113
112
|
files.each do |file|
|
114
113
|
bucket_key = File.join(bucket_path, file['name'])
|
115
114
|
local_path = "#{base_dir}/targets/#{target_name}/cmd_tlm/#{file['name']}"
|
@@ -180,8 +179,8 @@ module OpenC3
|
|
180
179
|
errors = [] # Store all errors processing the cmd_tlm files
|
181
180
|
target.cmd_tlm_files.each do |cmd_tlm_file|
|
182
181
|
@packet_config.process_file(cmd_tlm_file, target.name, target.language)
|
183
|
-
rescue Exception =>
|
184
|
-
errors << "Error processing #{cmd_tlm_file}:\n#{
|
182
|
+
rescue Exception => e
|
183
|
+
errors << "Error processing #{cmd_tlm_file}:\n#{e.message}"
|
185
184
|
end
|
186
185
|
unless errors.empty?
|
187
186
|
raise errors.join("\n")
|
data/lib/openc3/top_level.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
|
@@ -22,7 +22,6 @@
|
|
22
22
|
|
23
23
|
# This file contains top level functions in the OpenC3 namespace
|
24
24
|
|
25
|
-
require 'thread'
|
26
25
|
require 'digest'
|
27
26
|
require 'open3'
|
28
27
|
require 'openc3/core_ext'
|
@@ -50,6 +49,16 @@ class HazardousError < StandardError
|
|
50
49
|
end
|
51
50
|
end
|
52
51
|
|
52
|
+
# If a disabled command is sent through the {OpenC3::Api} this error is raised.
|
53
|
+
class DisabledError < StandardError
|
54
|
+
attr_accessor :target_name
|
55
|
+
attr_accessor :cmd_name
|
56
|
+
|
57
|
+
def to_s
|
58
|
+
"#{target_name} #{cmd_name} is Disabled"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
53
62
|
# OpenC3 is almost
|
54
63
|
# wholly contained within the OpenC3 module. OpenC3 also extends some of the
|
55
64
|
# core Ruby classes to add additional functionality.
|
@@ -102,18 +111,18 @@ module OpenC3
|
|
102
111
|
file.write(OPENC3_MARSHAL_HEADER)
|
103
112
|
file.write(Marshal.dump(obj))
|
104
113
|
end
|
105
|
-
rescue Exception =>
|
114
|
+
rescue Exception => e
|
106
115
|
begin
|
107
116
|
File.delete(marshal_filename)
|
108
117
|
rescue Exception
|
109
118
|
# Oh well - we tried
|
110
119
|
end
|
111
|
-
if
|
112
|
-
original_backtrace =
|
113
|
-
|
114
|
-
|
120
|
+
if e.class == TypeError and e.message =~ /Thread::Mutex/
|
121
|
+
original_backtrace = e.backtrace
|
122
|
+
e = e.exception("Mutex exists in a packet. Note: Packets must not be read during class initializers for Conversions, Limits Responses, etc.: #{e}")
|
123
|
+
e.set_backtrace(original_backtrace)
|
115
124
|
end
|
116
|
-
self.handle_fatal_exception(
|
125
|
+
self.handle_fatal_exception(e)
|
117
126
|
end
|
118
127
|
|
119
128
|
# Loads the marshal file back into a Ruby object
|
@@ -132,9 +141,9 @@ module OpenC3
|
|
132
141
|
Logger.warn "Marshal load failed with invalid marshal file: #{marshal_filename}"
|
133
142
|
return nil
|
134
143
|
end
|
135
|
-
rescue Exception =>
|
144
|
+
rescue Exception => e
|
136
145
|
if File.exist?(marshal_filename)
|
137
|
-
Logger.error "Marshal load failed with exception: #{marshal_filename}\n#{
|
146
|
+
Logger.error "Marshal load failed with exception: #{marshal_filename}\n#{e.formatted}"
|
138
147
|
else
|
139
148
|
Logger.info "Marshal file does not exist: #{marshal_filename}"
|
140
149
|
end
|
@@ -145,7 +154,7 @@ module OpenC3
|
|
145
154
|
rescue Exception
|
146
155
|
# Oh well - we tried
|
147
156
|
end
|
148
|
-
self.handle_fatal_exception(
|
157
|
+
self.handle_fatal_exception(e) if File.exist?(marshal_filename)
|
149
158
|
return nil
|
150
159
|
end
|
151
160
|
|
@@ -354,7 +363,7 @@ module OpenC3
|
|
354
363
|
#
|
355
364
|
# @param error [Exception] The exception to handle
|
356
365
|
# @param try_gui [Boolean] Whether to try and create a GUI exception popup
|
357
|
-
def self.handle_fatal_exception(error,
|
366
|
+
def self.handle_fatal_exception(error, _try_gui = true)
|
358
367
|
unless SystemExit === error or SignalException === error
|
359
368
|
$openc3_fatal_exception = error
|
360
369
|
self.write_exception_file(error)
|
@@ -380,7 +389,7 @@ module OpenC3
|
|
380
389
|
#
|
381
390
|
# @param error [Exception] The exception to handle
|
382
391
|
# @param try_gui [Boolean] Whether to try and create a GUI exception popup
|
383
|
-
def self.handle_critical_exception(error,
|
392
|
+
def self.handle_critical_exception(error, _try_gui = true)
|
384
393
|
Logger.error "Critical Exception! #{error.formatted}"
|
385
394
|
self.write_exception_file(error)
|
386
395
|
end
|
@@ -397,15 +406,15 @@ module OpenC3
|
|
397
406
|
retry_count = 0
|
398
407
|
begin
|
399
408
|
yield
|
400
|
-
rescue =>
|
409
|
+
rescue => e
|
401
410
|
Logger.error "#{name} thread unexpectedly died. Retries: #{retry_count} of #{retry_attempts}"
|
402
|
-
Logger.error
|
411
|
+
Logger.error e.formatted
|
403
412
|
retry_count += 1
|
404
413
|
if retry_count <= retry_attempts
|
405
|
-
self.write_exception_file(
|
414
|
+
self.write_exception_file(e)
|
406
415
|
retry
|
407
416
|
end
|
408
|
-
handle_fatal_exception(
|
417
|
+
handle_fatal_exception(e)
|
409
418
|
end
|
410
419
|
end
|
411
420
|
end
|
@@ -440,15 +449,15 @@ module OpenC3
|
|
440
449
|
# @param log_error [Boolean] Whether to log an error if we can't require the class
|
441
450
|
def self.require_file(filename, log_error = true)
|
442
451
|
require filename
|
443
|
-
rescue Exception =>
|
444
|
-
msg = "Unable to require #{filename} due to #{
|
452
|
+
rescue Exception => e
|
453
|
+
msg = "Unable to require #{filename} due to #{e.message}. "\
|
445
454
|
"Ensure #{filename} is in the OpenC3 lib directory."
|
446
455
|
Logger.error msg if log_error
|
447
456
|
raise $!, msg, $!.backtrace
|
448
457
|
end
|
449
458
|
|
450
459
|
# @param filename [String] Name of the file to open in the web browser
|
451
|
-
def self.open_in_web_browser(
|
460
|
+
def self.open_in_web_browser(_filename)
|
452
461
|
puts "open_in_web_browser is DEPRECATED"
|
453
462
|
end
|
454
463
|
|
@@ -456,12 +465,12 @@ module OpenC3
|
|
456
465
|
# Working directory is global, so this can make other threads wait
|
457
466
|
# Ruby Dir.chdir with block always throws an error if multiple threads
|
458
467
|
# call Dir.chdir
|
459
|
-
def self.set_working_dir(working_dir, &
|
468
|
+
def self.set_working_dir(working_dir, &)
|
460
469
|
if $openc3_chdir_mutex.owned?
|
461
|
-
set_working_dir_internal(working_dir, &
|
470
|
+
set_working_dir_internal(working_dir, &)
|
462
471
|
else
|
463
472
|
$openc3_chdir_mutex.synchronize do
|
464
|
-
set_working_dir_internal(working_dir, &
|
473
|
+
set_working_dir_internal(working_dir, &)
|
465
474
|
end
|
466
475
|
end
|
467
476
|
end
|
@@ -42,7 +42,7 @@ rescue LoadError
|
|
42
42
|
|
43
43
|
if $openc3_authorize
|
44
44
|
raise AuthError.new("Token is required") unless token
|
45
|
-
unless OpenC3::AuthModel.verify(token
|
45
|
+
unless OpenC3::AuthModel.verify(token)
|
46
46
|
raise AuthError.new("Password is invalid for '#{permission}' permission")
|
47
47
|
end
|
48
48
|
end
|
@@ -37,13 +37,17 @@ module OpenC3
|
|
37
37
|
NO_OPTIONS = {}
|
38
38
|
|
39
39
|
def pipelined
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
if $openc3_redis_cluster
|
41
|
+
yield # TODO: Update keys to support pipelining in cluster
|
42
|
+
else
|
43
|
+
with(NO_OPTIONS) do |redis|
|
44
|
+
redis.pipelined do |pipeline|
|
45
|
+
Thread.current[:pipeline] = pipeline
|
46
|
+
begin
|
47
|
+
yield
|
48
|
+
ensure
|
49
|
+
Thread.current[:pipeline] = nil
|
50
|
+
end
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
data/lib/openc3/version.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
OPENC3_VERSION = '5.15.
|
3
|
+
OPENC3_VERSION = '5.15.2'
|
4
4
|
module OpenC3
|
5
5
|
module Version
|
6
6
|
MAJOR = '5'
|
7
7
|
MINOR = '15'
|
8
|
-
PATCH = '
|
8
|
+
PATCH = '2'
|
9
9
|
OTHER = ''
|
10
|
-
BUILD = '
|
10
|
+
BUILD = '460e13eadf313640ad089597bee233ecdafd2ffa'
|
11
11
|
end
|
12
|
-
VERSION = '5.15.
|
13
|
-
GEM_VERSION = '5.15.
|
12
|
+
VERSION = '5.15.2'
|
13
|
+
GEM_VERSION = '5.15.2'
|
14
14
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "<%= tool_name %>",
|
3
|
-
"version": "5.15.
|
3
|
+
"version": "5.15.2",
|
4
4
|
"scripts": {
|
5
5
|
"ng": "ng",
|
6
6
|
"start": "ng serve",
|
@@ -12,7 +12,7 @@
|
|
12
12
|
},
|
13
13
|
"private": true,
|
14
14
|
"dependencies": {
|
15
|
-
"@openc3/tool-common": "5.15.
|
15
|
+
"@openc3/tool-common": "5.15.2",
|
16
16
|
"@angular/animations": "^17.0.8",
|
17
17
|
"@angular/cdk": "^17.0.4",
|
18
18
|
"@angular/common": "^17.0.8",
|
@@ -11,7 +11,7 @@
|
|
11
11
|
"smui-theme": "smui-theme compile build/smui.css -i src/theme"
|
12
12
|
},
|
13
13
|
"dependencies": {
|
14
|
-
"@openc3/tool-common": "5.15.
|
14
|
+
"@openc3/tool-common": "5.15.2",
|
15
15
|
"@astrouxds/astro-web-components": "7.20.0",
|
16
16
|
"@smui/button": "^7.0.0-beta.16",
|
17
17
|
"@smui/card": "^7.0.0-beta.16",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "<%= tool_name %>",
|
3
|
-
"version": "5.15.
|
3
|
+
"version": "5.15.2",
|
4
4
|
"private": true,
|
5
5
|
"scripts": {
|
6
6
|
"serve": "vue-cli-service serve",
|
@@ -11,7 +11,7 @@
|
|
11
11
|
"test:components": "vue-cli-service test:components"
|
12
12
|
},
|
13
13
|
"dependencies": {
|
14
|
-
"@openc3/tool-common": "5.15.
|
14
|
+
"@openc3/tool-common": "5.15.2",
|
15
15
|
"@astrouxds/astro-web-components": "7.20.0",
|
16
16
|
"axios": "1.6.5",
|
17
17
|
"date-fns": "2.30.0",
|
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "widget",
|
3
|
-
"version": "5.15.
|
3
|
+
"version": "5.15.2",
|
4
4
|
"private": true,
|
5
5
|
"scripts": {
|
6
6
|
"build": "vue-cli-service build --target lib --dest tools/widgets/<%= widget_name %> --formats umd-min <%= widget_path %> --name <%= widget_name %>"
|
7
7
|
},
|
8
8
|
"dependencies": {
|
9
|
-
"@openc3/tool-common": "5.15.
|
9
|
+
"@openc3/tool-common": "5.15.2",
|
10
10
|
"@astrouxds/astro-web-components": "7.20.0",
|
11
11
|
"vue": "2.7.16",
|
12
12
|
"vuetify": "2.7.1"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openc3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.15.
|
4
|
+
version: 5.15.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Melton
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-04-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|