openc3 5.19.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -7
- data/bin/openc3cli +12 -120
- data/bin/pipinstall +5 -3
- data/data/config/command_modifiers.yaml +17 -1
- data/data/config/interface_modifiers.yaml +21 -4
- data/data/config/item_modifiers.yaml +1 -1
- data/data/config/microservice.yaml +15 -2
- data/data/config/param_item_modifiers.yaml +1 -1
- data/data/config/parameter_modifiers.yaml +1 -1
- data/data/config/table_manager.yaml +2 -2
- data/data/config/target.yaml +11 -0
- data/data/config/telemetry_modifiers.yaml +17 -1
- data/data/config/tool.yaml +12 -0
- data/data/config/widgets.yaml +41 -17
- data/ext/openc3/ext/packet/packet.c +3 -0
- data/lib/openc3/accessors/form_accessor.rb +4 -3
- data/lib/openc3/accessors/html_accessor.rb +3 -3
- data/lib/openc3/accessors/http_accessor.rb +13 -13
- data/lib/openc3/accessors/xml_accessor.rb +16 -4
- data/lib/openc3/api/cmd_api.rb +4 -5
- data/lib/openc3/api/limits_api.rb +3 -3
- data/lib/openc3/api/target_api.rb +0 -30
- data/lib/openc3/api/tlm_api.rb +2 -1
- data/lib/openc3/bridge/bridge_config.rb +1 -2
- data/lib/openc3/ccsds/ccsds_parser.rb +12 -8
- data/lib/openc3/config/config_parser.rb +10 -3
- data/lib/openc3/conversions/bit_reverse_conversion.rb +1 -0
- data/lib/openc3/conversions/conversion.rb +5 -1
- data/lib/openc3/conversions/generic_conversion.rb +3 -8
- data/lib/openc3/conversions/object_read_conversion.rb +1 -8
- data/lib/openc3/conversions/polynomial_conversion.rb +3 -8
- data/lib/openc3/conversions/processor_conversion.rb +13 -11
- data/lib/openc3/conversions/segmented_polynomial_conversion.rb +3 -11
- data/lib/openc3/conversions/unix_time_conversion.rb +4 -7
- data/lib/openc3/conversions/unix_time_formatted_conversion.rb +4 -3
- data/lib/openc3/conversions/unix_time_seconds_conversion.rb +4 -3
- data/lib/openc3/core_ext/array.rb +0 -16
- data/lib/openc3/core_ext.rb +0 -1
- data/lib/openc3/interfaces/file_interface.rb +198 -0
- data/lib/openc3/interfaces/http_client_interface.rb +71 -39
- data/lib/openc3/interfaces/http_server_interface.rb +1 -9
- data/lib/openc3/interfaces/interface.rb +3 -2
- data/lib/openc3/interfaces/mqtt_interface.rb +32 -15
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +19 -4
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +7 -0
- data/lib/openc3/interfaces/serial_interface.rb +1 -0
- data/lib/openc3/interfaces/tcpip_server_interface.rb +1 -2
- data/lib/openc3/interfaces/udp_interface.rb +5 -3
- data/lib/openc3/interfaces.rb +2 -4
- data/lib/openc3/io/json_drb.rb +5 -0
- data/lib/openc3/io/json_rpc.rb +10 -9
- data/lib/openc3/io/udp_sockets.rb +7 -5
- data/lib/openc3/microservices/decom_microservice.rb +24 -7
- data/lib/openc3/microservices/interface_microservice.rb +65 -7
- data/lib/openc3/microservices/microservice.rb +1 -2
- data/lib/openc3/microservices/multi_microservice.rb +3 -3
- data/lib/openc3/migrations/20241208080000_no_critical_cmd.rb +31 -0
- data/lib/openc3/migrations/20241208080001_no_trigger_group.rb +46 -0
- data/lib/openc3/models/activity_model.rb +7 -3
- data/lib/openc3/models/cvt_model.rb +7 -1
- data/lib/openc3/models/interface_model.rb +9 -3
- data/lib/openc3/models/microservice_model.rb +8 -1
- data/lib/openc3/models/model.rb +1 -0
- data/lib/openc3/models/plugin_model.rb +11 -6
- data/lib/openc3/models/python_package_model.rb +10 -3
- data/lib/openc3/models/reaction_model.rb +14 -10
- data/lib/openc3/models/scope_model.rb +87 -25
- data/lib/openc3/models/target_model.rb +17 -1
- data/lib/openc3/models/timeline_model.rb +17 -5
- data/lib/openc3/models/tool_model.rb +15 -3
- data/lib/openc3/models/trigger_group_model.rb +6 -3
- data/lib/openc3/operators/microservice_operator.rb +10 -3
- data/lib/openc3/packets/commands.rb +17 -6
- data/lib/openc3/packets/limits.rb +0 -12
- data/lib/openc3/packets/packet.rb +10 -1
- data/lib/openc3/packets/packet_config.rb +34 -1
- data/lib/openc3/packets/packet_item.rb +30 -32
- data/lib/openc3/packets/structure_item.rb +2 -2
- data/lib/openc3/script/calendar.rb +1 -6
- data/lib/openc3/script/commands.rb +19 -13
- data/lib/openc3/script/critical_cmd.rb +91 -0
- data/lib/openc3/script/screen.rb +2 -2
- data/lib/openc3/script/script.rb +17 -10
- data/lib/openc3/script/web_socket_api.rb +5 -5
- data/lib/openc3/streams/mqtt_stream.rb +41 -33
- data/lib/openc3/streams/serial_stream.rb +27 -27
- data/lib/openc3/streams/stream.rb +17 -17
- data/lib/openc3/streams/tcpip_client_stream.rb +1 -1
- data/lib/openc3/streams/tcpip_socket_stream.rb +19 -19
- data/lib/openc3/system/system.rb +1 -1
- data/lib/openc3/system.rb +2 -3
- data/lib/openc3/tools/table_manager/table.rb +2 -2
- data/lib/openc3/tools/table_manager/table_parser.rb +1 -1
- data/lib/openc3/top_level.rb +9 -5
- data/lib/openc3/topics/command_decom_topic.rb +0 -7
- data/lib/openc3/topics/command_topic.rb +16 -0
- data/lib/openc3/topics/interface_topic.rb +2 -0
- data/lib/openc3/utilities/authentication.rb +7 -3
- data/lib/openc3/utilities/bucket_utilities.rb +1 -1
- data/lib/openc3/utilities/cli_generator.rb +0 -1
- data/lib/openc3/utilities/logger.rb +1 -0
- data/lib/openc3/utilities/store_queued.rb +1 -0
- data/lib/openc3/version.rb +6 -6
- data/templates/conversion/conversion.rb +2 -0
- data/templates/plugin/README.md +1 -1
- data/templates/target/targets/TARGET/lib/target.rb +1 -1
- data/templates/tool_angular/package.json +9 -9
- data/templates/tool_angular/src/app/app.component.html +4 -13
- data/templates/tool_angular/src/app/app.component.scss +5 -13
- data/templates/tool_angular/src/app/app.component.ts +5 -4
- data/templates/tool_angular/src/app/custom-overlay-container.ts +2 -2
- data/templates/tool_angular/src/app/openc3-api.d.ts +1 -1
- data/templates/tool_angular/src/main.single-spa.ts +1 -1
- data/templates/tool_react/package.json +1 -0
- data/templates/tool_react/src/root.component.js +1 -1
- data/templates/tool_svelte/build/smui.css +1 -1
- data/templates/tool_svelte/package.json +11 -9
- data/templates/tool_svelte/rollup.config.js +2 -0
- data/templates/tool_svelte/src/App.svelte +2 -2
- data/templates/tool_vue/eslint.config.mjs +68 -0
- data/templates/tool_vue/jsconfig.json +1 -1
- data/templates/tool_vue/package.json +26 -43
- data/templates/tool_vue/src/App.vue +3 -5
- data/templates/tool_vue/src/main.js +12 -23
- data/templates/tool_vue/src/router.js +19 -18
- data/templates/tool_vue/src/tools/tool_name/tool_name.vue +2 -2
- data/templates/tool_vue/vite.config.js +52 -0
- data/templates/widget/package.json +19 -26
- data/templates/widget/src/Widget.vue +13 -15
- data/templates/widget/vite.config.js +26 -0
- metadata +25 -39
- data/lib/openc3/core_ext/hash.rb +0 -40
- data/lib/openc3/core_ext/httpclient.rb +0 -11
- data/lib/openc3/interfaces/linc_interface.rb +0 -480
- data/lib/openc3/interfaces/protocols/override_protocol.rb +0 -4
- data/lib/openc3/microservices/reaction_microservice.rb +0 -607
- data/lib/openc3/microservices/timeline_microservice.rb +0 -400
- data/lib/openc3/microservices/trigger_group_microservice.rb +0 -698
- data/lib/openc3/migrations/20230615000000_autonomic.rb +0 -86
- data/lib/openc3/migrations/20240915000000_activity_uuid.rb +0 -28
- data/lib/openc3/system/system_config.rb +0 -413
- data/templates/tool_svelte/src/services/api.js +0 -92
- data/templates/tool_svelte/src/services/axios.js +0 -85
- data/templates/tool_svelte/src/services/cable.js +0 -65
- data/templates/tool_svelte/src/services/config-parser.js +0 -198
- data/templates/tool_svelte/src/services/openc3-api.js +0 -606
- data/templates/tool_vue/.eslintrc.js +0 -43
- data/templates/tool_vue/babel.config.json +0 -11
- data/templates/tool_vue/vue.config.js +0 -38
- data/templates/widget/.eslintrc.js +0 -43
- data/templates/widget/babel.config.json +0 -11
- data/templates/widget/vue.config.js +0 -28
- /data/templates/tool_vue/{.prettierrc.js → .prettierrc.cjs} +0 -0
- /data/templates/widget/{.prettierrc.js → .prettierrc.cjs} +0 -0
@@ -27,6 +27,8 @@ require 'openc3/config/config_parser'
|
|
27
27
|
module OpenC3
|
28
28
|
# Base class for interfaces that send and receive messages over UDP
|
29
29
|
class UdpInterface < Interface
|
30
|
+
HOST_127_0_0_1 = '127.0.0.1'
|
31
|
+
|
30
32
|
# @param hostname [String] Machine to connect to
|
31
33
|
# @param write_dest_port [Integer] Port to write commands to
|
32
34
|
# @param read_port [Integer] Port to read telemetry from
|
@@ -56,7 +58,7 @@ module OpenC3
|
|
56
58
|
@hostname = ConfigParser.handle_nil(hostname)
|
57
59
|
if @hostname
|
58
60
|
@hostname = @hostname.to_s
|
59
|
-
@hostname =
|
61
|
+
@hostname = HOST_127_0_0_1 if @hostname.casecmp('LOCALHOST').zero?
|
60
62
|
end
|
61
63
|
@write_dest_port = ConfigParser.handle_nil(write_dest_port)
|
62
64
|
@write_dest_port = write_dest_port.to_i if @write_dest_port
|
@@ -66,7 +68,7 @@ module OpenC3
|
|
66
68
|
@write_src_port = @write_src_port.to_i if @write_src_port
|
67
69
|
@interface_address = ConfigParser.handle_nil(interface_address)
|
68
70
|
if @interface_address && @interface_address.casecmp('LOCALHOST').zero?
|
69
|
-
@interface_address =
|
71
|
+
@interface_address = HOST_127_0_0_1
|
70
72
|
end
|
71
73
|
@ttl = ttl.to_i
|
72
74
|
@ttl = 1 if @ttl < 1
|
@@ -81,7 +83,7 @@ module OpenC3
|
|
81
83
|
@read_timeout = @read_timeout.to_f if @read_timeout
|
82
84
|
@bind_address = ConfigParser.handle_nil(bind_address)
|
83
85
|
if @bind_address && @bind_address.casecmp('LOCALHOST').zero?
|
84
|
-
@bind_address =
|
86
|
+
@bind_address = HOST_127_0_0_1
|
85
87
|
end
|
86
88
|
@write_socket = nil
|
87
89
|
@read_socket = nil
|
data/lib/openc3/interfaces.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
|
@@ -25,15 +25,13 @@ module OpenC3
|
|
25
25
|
autoload(:HttpClientInterface, 'openc3/interfaces/http_client_interface.rb')
|
26
26
|
autoload(:HttpServerInterface, 'openc3/interfaces/http_server_interface.rb')
|
27
27
|
autoload(:MqttInterface, 'openc3/interfaces/mqtt_interface.rb')
|
28
|
+
autoload(:MqttStreamInterface, 'openc3/interfaces/mqtt_stream_interface.rb')
|
28
29
|
autoload(:StreamInterface, 'openc3/interfaces/stream_interface.rb')
|
29
30
|
autoload(:SerialInterface, 'openc3/interfaces/serial_interface.rb')
|
30
31
|
autoload(:SimulatedTargetInterface, 'openc3/interfaces/simulated_target_interface.rb')
|
31
32
|
autoload(:TcpipClientInterface, 'openc3/interfaces/tcpip_client_interface.rb')
|
32
33
|
autoload(:TcpipServerInterface, 'openc3/interfaces/tcpip_server_interface.rb')
|
33
34
|
autoload(:UdpInterface, 'openc3/interfaces/udp_interface.rb')
|
34
|
-
autoload(:LincInterface, 'openc3/interfaces/linc_interface.rb')
|
35
|
-
autoload(:LincHandshakeCommand, 'openc3/interfaces/linc_interface.rb')
|
36
|
-
autoload(:LincHandshake, 'openc3/interfaces/linc_interface.rb')
|
37
35
|
|
38
36
|
autoload(:Protocol, 'openc3/interfaces/protocols/protocol.rb')
|
39
37
|
autoload(:BurstProtocol, 'openc3/interfaces/protocols/burst_protocol.rb')
|
data/lib/openc3/io/json_drb.rb
CHANGED
@@ -302,6 +302,11 @@ module OpenC3
|
|
302
302
|
response = JsonRpcErrorResponse.new(
|
303
303
|
JsonRpcError.new(error_code, e.message, e), request.id
|
304
304
|
)
|
305
|
+
elsif CriticalCmdError === e
|
306
|
+
error_code = JsonRpcError::ErrorCode::CRITICAL_CMD_ERROR
|
307
|
+
response = JsonRpcErrorResponse.new(
|
308
|
+
JsonRpcError.new(error_code, e.message, e), request.id
|
309
|
+
)
|
305
310
|
else
|
306
311
|
error_code = JsonRpcError::ErrorCode::OTHER_ERROR
|
307
312
|
response = JsonRpcErrorResponse.new(
|
data/lib/openc3/io/json_rpc.rb
CHANGED
@@ -379,16 +379,17 @@ module OpenC3
|
|
379
379
|
class JsonRpcError < JsonRpc
|
380
380
|
# Enumeration of JSON RPC error codes
|
381
381
|
class ErrorCode
|
382
|
-
PARSE_ERROR
|
383
|
-
INVALID_REQUEST
|
384
|
-
METHOD_NOT_FOUND
|
385
|
-
INVALID_PARAMS
|
386
|
-
INTERNAL_ERROR
|
387
|
-
AUTH_ERROR
|
388
|
-
FORBIDDEN_ERROR
|
389
|
-
HAZARDOUS_ERROR
|
382
|
+
PARSE_ERROR = -32700
|
383
|
+
INVALID_REQUEST = -32600
|
384
|
+
METHOD_NOT_FOUND = -32601
|
385
|
+
INVALID_PARAMS = -32602
|
386
|
+
INTERNAL_ERROR = -32603
|
387
|
+
AUTH_ERROR = -32500
|
388
|
+
FORBIDDEN_ERROR = -32501
|
389
|
+
HAZARDOUS_ERROR = -32502
|
390
|
+
CRITICAL_CMD_ERROR = -32503
|
390
391
|
# Server error reserved: -32000 to -32099
|
391
|
-
OTHER_ERROR
|
392
|
+
OTHER_ERROR = -1
|
392
393
|
end
|
393
394
|
|
394
395
|
# @param code [Integer] The error type that occurred
|
@@ -17,7 +17,7 @@
|
|
17
17
|
# All changes Copyright 2022, 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 'socket'
|
@@ -30,6 +30,8 @@ Socket::IP_MULTICAST_TTL = 10 unless Socket.const_defined?('IP_MULTICAST_TTL')
|
|
30
30
|
|
31
31
|
module OpenC3
|
32
32
|
class UdpReadWriteSocket
|
33
|
+
HOST_0_0_0_0 = '0.0.0.0'
|
34
|
+
|
33
35
|
# @param bind_port [Integer[ Port to write data out from and receive data on (0 = randomly assigned)
|
34
36
|
# @param bind_address [String] Local address to bind to (0.0.0.0 = All local addresses)
|
35
37
|
# @param external_port [Integer] External port to write to
|
@@ -40,7 +42,7 @@ module OpenC3
|
|
40
42
|
# @param write_multicast [Boolean] Whether or not to write to the external address as multicast
|
41
43
|
def initialize(
|
42
44
|
bind_port = 0,
|
43
|
-
bind_address =
|
45
|
+
bind_address = HOST_0_0_0_0,
|
44
46
|
external_port = nil,
|
45
47
|
external_address = nil,
|
46
48
|
multicast_interface_address = nil,
|
@@ -76,7 +78,7 @@ module OpenC3
|
|
76
78
|
|
77
79
|
# Receive messages sent to the multicast address
|
78
80
|
if read_multicast
|
79
|
-
multicast_interface_address =
|
81
|
+
multicast_interface_address = HOST_0_0_0_0 unless multicast_interface_address
|
80
82
|
membership = IPAddr.new(external_address).hton + IPAddr.new(multicast_interface_address).hton
|
81
83
|
@socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, membership)
|
82
84
|
end
|
@@ -155,7 +157,7 @@ module OpenC3
|
|
155
157
|
src_port = nil,
|
156
158
|
multicast_interface_address = nil,
|
157
159
|
ttl = 1,
|
158
|
-
bind_address =
|
160
|
+
bind_address = HOST_0_0_0_0
|
159
161
|
)
|
160
162
|
|
161
163
|
super(
|
@@ -180,7 +182,7 @@ module OpenC3
|
|
180
182
|
recv_port = 0,
|
181
183
|
multicast_address = nil,
|
182
184
|
multicast_interface_address = nil,
|
183
|
-
bind_address =
|
185
|
+
bind_address = HOST_0_0_0_0
|
184
186
|
)
|
185
187
|
|
186
188
|
super(
|
@@ -20,6 +20,7 @@
|
|
20
20
|
# This file may also be used under the terms of a commercial license
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
|
+
require 'time'
|
23
24
|
require 'openc3/microservices/microservice'
|
24
25
|
require 'openc3/microservices/interface_decom_common'
|
25
26
|
require 'openc3/topics/telemetry_decom_topic'
|
@@ -28,6 +29,7 @@ require 'openc3/topics/limits_event_topic'
|
|
28
29
|
module OpenC3
|
29
30
|
class DecomMicroservice < Microservice
|
30
31
|
include InterfaceDecomCommon
|
32
|
+
LIMITS_STATE_INDEX = { RED_LOW: 0, YELLOW_LOW: 1, YELLOW_HIGH: 2, RED_HIGH: 3, GREEN_LOW: 4, GREEN_HIGH: 5 }
|
31
33
|
|
32
34
|
def initialize(*args)
|
33
35
|
super(*args)
|
@@ -134,31 +136,46 @@ module OpenC3
|
|
134
136
|
# @param log_change [Boolean] Whether to log this limits change event
|
135
137
|
def limits_change_callback(packet, item, old_limits_state, value, log_change)
|
136
138
|
return if @cancel_thread
|
137
|
-
packet_time
|
139
|
+
# Make a copy because packet_time is frozen
|
140
|
+
packet_time = packet.packet_time.dup
|
138
141
|
if value
|
139
142
|
message = "#{packet.target_name} #{packet.packet_name} #{item.name} = #{value} is #{item.limits.state}"
|
143
|
+
if item.limits.values
|
144
|
+
values = item.limits.values[System.limits_set]
|
145
|
+
# Check if the state is RED_LOW, YELLOW_LOW, YELLOW_HIGH, RED_HIGH, GREEN_LOW, GREEN_HIGH
|
146
|
+
if LIMITS_STATE_INDEX[item.limits.state]
|
147
|
+
# Directly index into the values and return the value
|
148
|
+
message += " (#{values[LIMITS_STATE_INDEX[item.limits.state]]})"
|
149
|
+
elsif item.limits.state == :GREEN
|
150
|
+
# If we're green we display the green range (YELLOW_LOW - YELLOW_HIGH)
|
151
|
+
message += " (#{values[1]} to #{values[2]})"
|
152
|
+
elsif item.limits.state == :BLUE
|
153
|
+
# If we're blue we display the blue range (GREEN_LOW - GREEN_HIGH)
|
154
|
+
message += " (#{values[4]} to #{values[5]})"
|
155
|
+
end
|
156
|
+
end
|
140
157
|
else
|
141
158
|
message = "#{packet.target_name} #{packet.packet_name} #{item.name} is disabled"
|
142
159
|
end
|
143
|
-
message << " (#{packet.packet_time.sys.formatted})" if packet_time
|
144
160
|
|
145
|
-
|
161
|
+
# Include the packet_time in the log json but not the log message
|
162
|
+
time = { packet_time: packet_time.utc.iso8601(6) }
|
146
163
|
if log_change
|
147
164
|
case item.limits.state
|
148
165
|
when :BLUE, :GREEN, :GREEN_LOW, :GREEN_HIGH
|
149
166
|
# Only print INFO messages if we're changing ... not on initialization
|
150
|
-
@logger.info
|
167
|
+
@logger.info(message, other: time) if old_limits_state
|
151
168
|
when :YELLOW, :YELLOW_LOW, :YELLOW_HIGH
|
152
|
-
@logger.warn(message, type: Logger::NOTIFICATION)
|
169
|
+
@logger.warn(message, other: time, type: Logger::NOTIFICATION)
|
153
170
|
when :RED, :RED_LOW, :RED_HIGH
|
154
|
-
@logger.error(message, type: Logger::ALERT)
|
171
|
+
@logger.error(message, other: time, type: Logger::ALERT)
|
155
172
|
end
|
156
173
|
end
|
157
174
|
|
158
175
|
# The openc3_limits_events topic can be listened to for all limits events, it is a continuous stream
|
159
176
|
event = { type: :LIMITS_CHANGE, target_name: packet.target_name, packet_name: packet.packet_name,
|
160
177
|
item_name: item.name, old_limits_state: old_limits_state.to_s, new_limits_state: item.limits.state.to_s,
|
161
|
-
time_nsec:
|
178
|
+
time_nsec: packet_time.to_nsec_from_epoch, message: message.to_s }
|
162
179
|
LimitsEventTopic.write(event, scope: @scope)
|
163
180
|
|
164
181
|
if item.limits.response
|
@@ -26,6 +26,7 @@ require 'openc3/models/interface_model'
|
|
26
26
|
require 'openc3/models/router_model'
|
27
27
|
require 'openc3/models/interface_status_model'
|
28
28
|
require 'openc3/models/router_status_model'
|
29
|
+
require 'openc3/models/scope_model'
|
29
30
|
require 'openc3/topics/telemetry_topic'
|
30
31
|
require 'openc3/topics/command_topic'
|
31
32
|
require 'openc3/topics/command_decom_topic'
|
@@ -33,6 +34,12 @@ require 'openc3/topics/interface_topic'
|
|
33
34
|
require 'openc3/topics/router_topic'
|
34
35
|
require 'openc3/interfaces/interface'
|
35
36
|
|
37
|
+
begin
|
38
|
+
require 'openc3-enterprise/models/critical_cmd_model'
|
39
|
+
rescue LoadError
|
40
|
+
# Should never actual be used in Open Source
|
41
|
+
end
|
42
|
+
|
36
43
|
module OpenC3
|
37
44
|
class InterfaceCmdHandlerThread
|
38
45
|
include InterfaceDecomCommon
|
@@ -41,6 +48,12 @@ module OpenC3
|
|
41
48
|
@interface = interface
|
42
49
|
@tlm = tlm
|
43
50
|
@scope = scope
|
51
|
+
scope_model = ScopeModel.get_model(name: @scope)
|
52
|
+
if scope_model
|
53
|
+
@critical_commanding = scope_model.critical_commanding
|
54
|
+
else
|
55
|
+
@critical_commanding = 'OFF'
|
56
|
+
end
|
44
57
|
@logger = logger
|
45
58
|
@logger = Logger unless @logger
|
46
59
|
@metric = metric
|
@@ -70,10 +83,21 @@ module OpenC3
|
|
70
83
|
def run
|
71
84
|
InterfaceTopic.receive_commands(@interface, scope: @scope) do |topic, msg_id, msg_hash, _redis|
|
72
85
|
OpenC3.with_context(msg_hash) do
|
86
|
+
release_critical = false
|
73
87
|
msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
|
74
88
|
delta = Time.now.to_f - msgid_seconds_from_epoch
|
75
89
|
@metric.set(name: 'interface_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and interface cmd start') if @metric
|
76
90
|
|
91
|
+
if topic == "OPENC3__SYSTEM__EVENTS"
|
92
|
+
msg = JSON.parse(msg_hash['event'])
|
93
|
+
if msg['type'] == 'scope'
|
94
|
+
if msg['name'] == @scope
|
95
|
+
@critical_commanding = msg['critical_commanding']
|
96
|
+
end
|
97
|
+
end
|
98
|
+
next 'SUCCESS'
|
99
|
+
end
|
100
|
+
|
77
101
|
# Check for a raw write to the interface
|
78
102
|
if topic =~ /CMD}INTERFACE/
|
79
103
|
@directive_count += 1
|
@@ -150,10 +174,21 @@ module OpenC3
|
|
150
174
|
handle_inject_tlm(msg_hash['inject_tlm'])
|
151
175
|
next 'SUCCESS'
|
152
176
|
end
|
177
|
+
if msg_hash.key?('release_critical')
|
178
|
+
# Note: intentional fall through below this point
|
179
|
+
model = CriticalCmdModel.get_model(name: msg_hash['release_critical'], scope: @scope)
|
180
|
+
if model
|
181
|
+
msg_hash = model.cmd_hash
|
182
|
+
release_critical = true
|
183
|
+
else
|
184
|
+
next "Critical command #{msg_hash['release_critical']} not found"
|
185
|
+
end
|
186
|
+
end
|
153
187
|
end
|
154
188
|
|
155
189
|
target_name = msg_hash['target_name']
|
156
190
|
cmd_name = msg_hash['cmd_name']
|
191
|
+
manual = ConfigParser.handle_true_false(msg_hash['manual'])
|
157
192
|
cmd_params = nil
|
158
193
|
cmd_buffer = nil
|
159
194
|
hazardous_check = nil
|
@@ -195,11 +230,29 @@ module OpenC3
|
|
195
230
|
command.extra ||= {}
|
196
231
|
command.extra['cmd_string'] = msg_hash['cmd_string']
|
197
232
|
command.extra['username'] = msg_hash['username']
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
233
|
+
hazardous, hazardous_description = System.commands.cmd_pkt_hazardous?(command)
|
234
|
+
|
235
|
+
# Initial Are you sure? Hazardous check
|
236
|
+
# Return back the error, description, and the formatted command
|
237
|
+
# This allows the error handler to simply re-send the command
|
238
|
+
next "HazardousError\n#{hazardous_description}\n#{msg_hash['cmd_string']}" if hazardous_check and hazardous and not release_critical
|
239
|
+
|
240
|
+
# Check for Critical Command
|
241
|
+
if @critical_commanding and @critical_commanding != 'OFF' and not release_critical
|
242
|
+
restricted = command.restricted
|
243
|
+
if hazardous or restricted or (@critical_commanding == 'ALL' and manual)
|
244
|
+
if hazardous
|
245
|
+
type = 'HAZARDOUS'
|
246
|
+
elsif restricted
|
247
|
+
type = 'RESTRICTED'
|
248
|
+
else
|
249
|
+
type = 'NORMAL'
|
250
|
+
end
|
251
|
+
model = CriticalCmdModel.new(name: SecureRandom.uuid, type: type, interface_name: @interface.name, username: msg_hash['username'], cmd_hash: msg_hash, scope: @scope)
|
252
|
+
model.create
|
253
|
+
@logger.info("Critical Cmd Pending: #{msg_hash['cmd_string']}", user: msg_hash['username'], scope: @scope)
|
254
|
+
next "CriticalCmdError\n#{model.name}"
|
255
|
+
end
|
203
256
|
end
|
204
257
|
|
205
258
|
validate = ConfigParser.handle_true_false(msg_hash['validate'])
|
@@ -223,6 +276,12 @@ module OpenC3
|
|
223
276
|
|
224
277
|
@count += 1
|
225
278
|
@metric.set(name: 'interface_cmd_total', value: @count, type: 'counter') if @metric
|
279
|
+
|
280
|
+
log_message = ConfigParser.handle_true_false(msg_hash['log_message'])
|
281
|
+
if log_message
|
282
|
+
@logger.info(msg_hash['cmd_string'], user: msg_hash['username'], scope: @scope)
|
283
|
+
end
|
284
|
+
|
226
285
|
@interface.write(command)
|
227
286
|
|
228
287
|
if command.validator and validate
|
@@ -440,8 +499,7 @@ module OpenC3
|
|
440
499
|
|
441
500
|
@queued = false
|
442
501
|
@interface.options.each do |option_name, option_values|
|
443
|
-
|
444
|
-
when 'OPTIMIZE_THROUGHPUT'
|
502
|
+
if option_name.upcase == 'OPTIMIZE_THROUGHPUT'
|
445
503
|
@queued = true
|
446
504
|
update_interval = option_values[0].to_f
|
447
505
|
EphemeralStoreQueued.instance.set_update_interval(update_interval)
|
@@ -222,8 +222,7 @@ module OpenC3
|
|
222
222
|
# Returns if the command was handled
|
223
223
|
def microservice_cmd(topic, msg_id, msg_hash, _redis)
|
224
224
|
command = msg_hash['command']
|
225
|
-
|
226
|
-
when 'ADD_TOPICS'
|
225
|
+
if command == 'ADD_TOPICS'
|
227
226
|
topics = JSON.parse(msg_hash['topics'])
|
228
227
|
if topics and Array === topics
|
229
228
|
topics.each do |new_topic|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2024 OpenC3 Inc.
|
4
4
|
# All Rights Reserved.
|
5
5
|
#
|
6
6
|
# This program is free software; you can modify and/or redistribute it
|
@@ -36,8 +36,8 @@ module OpenC3
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
raise "Could not determine class filename from '#{cmd_line}'" unless filename
|
39
|
-
OpenC3.set_working_dir(
|
40
|
-
|
39
|
+
OpenC3.set_working_dir(microservice_model.work_dir) do
|
40
|
+
require File.join(microservice_model.work_dir, filename)
|
41
41
|
end
|
42
42
|
klass = filename.filename_to_class_name.to_class
|
43
43
|
klass.run(microservice_model.name)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'openc3/utilities/migration'
|
2
|
+
require 'openc3/models/scope_model'
|
3
|
+
require 'openc3/models/microservice_model'
|
4
|
+
|
5
|
+
module OpenC3
|
6
|
+
class NoCriticalCmd < Migration
|
7
|
+
begin
|
8
|
+
require 'openc3-enterprise/models/cmd_authority_model'
|
9
|
+
require 'openc3-enterprise/models/critical_cmd_model'
|
10
|
+
BASE = false
|
11
|
+
rescue LoadError
|
12
|
+
BASE = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.run
|
16
|
+
ScopeModel.get_all_models(scope: nil).each do |scope, scope_model|
|
17
|
+
model = MicroserviceModel.get_model(name: "#{scope}__CRITICALCMD__#{scope}", scope: scope)
|
18
|
+
if BASE # Only remove the critical command model if we're not enterprise
|
19
|
+
model.destroy if model
|
20
|
+
else
|
21
|
+
model.work_dir = '/openc3-enterprise/lib/openc3-enterprise/microservices'
|
22
|
+
model.update
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
unless ENV['OPENC3_NO_MIGRATE']
|
30
|
+
OpenC3::NoCriticalCmd.run
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'openc3/utilities/migration'
|
2
|
+
require 'openc3/models/scope_model'
|
3
|
+
require 'openc3/models/microservice_model'
|
4
|
+
|
5
|
+
module OpenC3
|
6
|
+
class NoTriggerGroups < Migration
|
7
|
+
begin
|
8
|
+
require 'openc3-enterprise/models/cmd_authority_model'
|
9
|
+
require 'openc3-enterprise/models/critical_cmd_model'
|
10
|
+
BASE = false
|
11
|
+
rescue LoadError
|
12
|
+
BASE = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.run
|
16
|
+
MicroserviceModel.get_all_models(scope: 'DEFAULT').each do |microservice_name, microservice_model|
|
17
|
+
if microservice_name =~ /__TRIGGER_GROUP__/
|
18
|
+
if BASE
|
19
|
+
# Only remove the trigger group microservice if we're not enterprise
|
20
|
+
microservice_model.destroy
|
21
|
+
else
|
22
|
+
# Need to update working dir for Enterprise
|
23
|
+
microservice_model.work_dir = '/openc3-enterprise/lib/openc3-enterprise/microservices'
|
24
|
+
microservice_model.update
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if microservice_name =~ /__OPENC3__REACTION/
|
29
|
+
# Need to update working dir for Enterprise
|
30
|
+
microservice_model.work_dir = '/openc3-enterprise/lib/openc3-enterprise/microservices'
|
31
|
+
microservice_model.update
|
32
|
+
end
|
33
|
+
|
34
|
+
if microservice_name =~ /__TIMELINE__/
|
35
|
+
# Need to update working dir for Enterprise
|
36
|
+
microservice_model.work_dir = '/openc3-enterprise/lib/openc3-enterprise/microservices'
|
37
|
+
microservice_model.update
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
unless ENV['OPENC3_NO_MIGRATE']
|
45
|
+
OpenC3::NoTriggerGroups.run
|
46
|
+
end
|
@@ -121,7 +121,7 @@ module OpenC3
|
|
121
121
|
|
122
122
|
notification = {
|
123
123
|
# start / stop to match SortedModel
|
124
|
-
'data' => JSON.generate({'start' => score}),
|
124
|
+
'data' => JSON.generate({'start' => score, 'uuid' => uuid}),
|
125
125
|
'kind' => 'deleted',
|
126
126
|
'type' => 'activity',
|
127
127
|
'timeline' => name
|
@@ -361,7 +361,7 @@ module OpenC3
|
|
361
361
|
end
|
362
362
|
end
|
363
363
|
end
|
364
|
-
notify(kind: 'updated', extra: old_start)
|
364
|
+
notify(kind: 'updated', extra: {old_start: old_start, old_uuid: old_uuid})
|
365
365
|
return @start
|
366
366
|
end
|
367
367
|
|
@@ -409,7 +409,11 @@ module OpenC3
|
|
409
409
|
'type' => 'activity',
|
410
410
|
'timeline' => @name
|
411
411
|
}
|
412
|
-
|
412
|
+
if extra
|
413
|
+
extra.each do |key, value|
|
414
|
+
notification[key.to_s] = value
|
415
|
+
end
|
416
|
+
end
|
413
417
|
begin
|
414
418
|
TimelineTopic.write_activity(notification, scope: @scope)
|
415
419
|
rescue StandardError => e
|
@@ -156,7 +156,13 @@ module OpenC3
|
|
156
156
|
item_result[1] = item_result[1].intern if item_result[1] # Convert to symbol
|
157
157
|
end
|
158
158
|
else
|
159
|
-
|
159
|
+
# We didn't find a value but the packet hash contains the key so the item exists
|
160
|
+
# Thus set the result to nil so it comes back like a normal item
|
161
|
+
if hash.key?(value_keys[-1])
|
162
|
+
item_result[1] = nil
|
163
|
+
else
|
164
|
+
raise "Item '#{target_name} #{packet_name} #{value_keys[-1]}' does not exist"
|
165
|
+
end
|
160
166
|
end
|
161
167
|
end
|
162
168
|
results << item_result
|
@@ -50,6 +50,7 @@ module OpenC3
|
|
50
50
|
attr_accessor :work_dir
|
51
51
|
attr_accessor :ports
|
52
52
|
attr_accessor :prefix
|
53
|
+
attr_accessor :shard
|
53
54
|
|
54
55
|
# NOTE: The following three class methods are used by the ModelController
|
55
56
|
# and are reimplemented to enable various Model class methods to work
|
@@ -121,6 +122,7 @@ module OpenC3
|
|
121
122
|
env: {},
|
122
123
|
container: nil,
|
123
124
|
prefix: nil,
|
125
|
+
shard: 0,
|
124
126
|
scope:
|
125
127
|
)
|
126
128
|
if self.class._get_type == 'INTERFACE'
|
@@ -158,6 +160,7 @@ module OpenC3
|
|
158
160
|
@env = env
|
159
161
|
@container = container
|
160
162
|
@prefix = prefix
|
163
|
+
@shard = shard.to_i # to_i to handle nil
|
161
164
|
@secrets = secrets
|
162
165
|
end
|
163
166
|
|
@@ -222,6 +225,7 @@ module OpenC3
|
|
222
225
|
'env' => @env,
|
223
226
|
'container' => @container,
|
224
227
|
'prefix' => @prefix,
|
228
|
+
'shard' => @shard,
|
225
229
|
'updated_at' => @updated_at
|
226
230
|
}
|
227
231
|
end
|
@@ -297,9 +301,7 @@ module OpenC3
|
|
297
301
|
# Option Name, Secret Name
|
298
302
|
@secret_options << [parameters[3], parameters[1]]
|
299
303
|
end
|
300
|
-
|
301
|
-
@secrets[-1] << parameters[4]
|
302
|
-
end
|
304
|
+
@secrets[-1] << ConfigParser.handle_nil(parameters[4])
|
303
305
|
|
304
306
|
when 'ENV'
|
305
307
|
parser.verify_num_parameters(2, 2, "#{keyword} <Key> <Value>")
|
@@ -341,6 +343,9 @@ module OpenC3
|
|
341
343
|
parser.verify_num_parameters(1, 1, "#{keyword} <Route Prefix>")
|
342
344
|
@prefix = parameters[0]
|
343
345
|
|
346
|
+
when 'SHARD'
|
347
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Shard Number Starting from 0>")
|
348
|
+
@shard = Integer(parameters[0])
|
344
349
|
else
|
345
350
|
raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Interface/Router: #{keyword} #{parameters.join(" ")}")
|
346
351
|
|
@@ -365,6 +370,7 @@ module OpenC3
|
|
365
370
|
needs_dependencies: @needs_dependencies,
|
366
371
|
secrets: @secrets,
|
367
372
|
prefix: @prefix,
|
373
|
+
shard: @shard,
|
368
374
|
scope: @scope
|
369
375
|
)
|
370
376
|
unless validate_only
|
@@ -44,6 +44,7 @@ module OpenC3
|
|
44
44
|
attr_accessor :prefix
|
45
45
|
attr_accessor :disable_erb
|
46
46
|
attr_accessor :ignore_changes
|
47
|
+
attr_accessor :shard
|
47
48
|
|
48
49
|
# NOTE: The following three class methods are used by the ModelController
|
49
50
|
# and are reimplemented to enable various Model class methods to work
|
@@ -105,6 +106,7 @@ module OpenC3
|
|
105
106
|
prefix: nil,
|
106
107
|
disable_erb: nil,
|
107
108
|
ignore_changes: nil,
|
109
|
+
shard: 0,
|
108
110
|
scope:
|
109
111
|
)
|
110
112
|
parts = name.split("__")
|
@@ -131,6 +133,7 @@ module OpenC3
|
|
131
133
|
@prefix = prefix
|
132
134
|
@disable_erb = disable_erb
|
133
135
|
@ignore_changes = ignore_changes
|
136
|
+
@shard = shard.to_i # to_i to handle nil
|
134
137
|
@bucket = Bucket.getClient()
|
135
138
|
end
|
136
139
|
|
@@ -153,7 +156,8 @@ module OpenC3
|
|
153
156
|
'secrets' => @secrets.as_json(*a),
|
154
157
|
'prefix' => @prefix,
|
155
158
|
'disable_erb' => @disable_erb,
|
156
|
-
'ignore_changes' => @ignore_changes
|
159
|
+
'ignore_changes' => @ignore_changes,
|
160
|
+
'shard' => @shard,
|
157
161
|
}
|
158
162
|
end
|
159
163
|
|
@@ -215,6 +219,9 @@ module OpenC3
|
|
215
219
|
if parameters
|
216
220
|
@disable_erb.concat(parameters)
|
217
221
|
end
|
222
|
+
when 'SHARD'
|
223
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Shard Number Starting from 0>")
|
224
|
+
@shard = Integer(parameters[0])
|
218
225
|
else
|
219
226
|
raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Microservice: #{keyword} #{parameters.join(" ")}")
|
220
227
|
end
|
data/lib/openc3/models/model.rb
CHANGED