openc3 6.8.1 → 6.9.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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/bin/openc3cli +5 -5
- data/data/config/command_modifiers.yaml +9 -1
- data/data/config/screen.yaml +1 -1
- data/lib/openc3/accessors/json_accessor.rb +5 -5
- data/lib/openc3/api/interface_api.rb +71 -4
- data/lib/openc3/api/router_api.rb +98 -8
- data/lib/openc3/api/stash_api.rb +3 -3
- data/lib/openc3/api/tlm_api.rb +1 -1
- data/lib/openc3/bridge/bridge_config.rb +1 -1
- data/lib/openc3/interfaces/file_interface.rb +18 -0
- data/lib/openc3/interfaces/http_client_interface.rb +11 -0
- data/lib/openc3/interfaces/http_server_interface.rb +8 -0
- data/lib/openc3/interfaces/interface.rb +90 -21
- data/lib/openc3/interfaces/mqtt_interface.rb +19 -0
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +20 -0
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +16 -0
- data/lib/openc3/interfaces/protocols/cmd_response_protocol.rb +18 -0
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +19 -0
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +17 -1
- data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +14 -0
- data/lib/openc3/interfaces/protocols/length_protocol.rb +25 -1
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +16 -3
- data/lib/openc3/interfaces/protocols/protocol.rb +79 -1
- data/lib/openc3/interfaces/protocols/slip_protocol.rb +23 -0
- data/lib/openc3/interfaces/protocols/template_protocol.rb +38 -0
- data/lib/openc3/interfaces/protocols/terminated_protocol.rb +14 -1
- data/lib/openc3/interfaces/serial_interface.rb +14 -0
- data/lib/openc3/interfaces/simulated_target_interface.rb +1 -1
- data/lib/openc3/interfaces/tcpip_client_interface.rb +16 -2
- data/lib/openc3/interfaces/tcpip_server_interface.rb +11 -1
- data/lib/openc3/interfaces/udp_interface.rb +14 -0
- data/lib/openc3/io/json_api_object.rb +1 -1
- data/lib/openc3/io/json_drb.rb +1 -1
- data/lib/openc3/io/json_drb_object.rb +1 -1
- data/lib/openc3/io/json_rpc.rb +5 -4
- data/lib/openc3/logs/packet_log_reader.rb +1 -1
- data/lib/openc3/logs/packet_log_writer.rb +6 -6
- data/lib/openc3/microservices/decom_microservice.rb +5 -1
- data/lib/openc3/microservices/interface_microservice.rb +103 -38
- data/lib/openc3/microservices/microservice.rb +4 -4
- data/lib/openc3/microservices/queue_microservice.rb +14 -21
- data/lib/openc3/microservices/reducer_microservice.rb +1 -1
- data/lib/openc3/microservices/router_microservice.rb +28 -25
- data/lib/openc3/models/activity_model.rb +18 -17
- data/lib/openc3/models/cvt_model.rb +12 -9
- data/lib/openc3/models/interface_model.rb +70 -12
- data/lib/openc3/models/metadata_model.rb +2 -2
- data/lib/openc3/models/microservice_model.rb +1 -1
- data/lib/openc3/models/microservice_status_model.rb +2 -2
- data/lib/openc3/models/model.rb +4 -4
- data/lib/openc3/models/note_model.rb +2 -2
- data/lib/openc3/models/plugin_model.rb +9 -4
- data/lib/openc3/models/queue_model.rb +25 -25
- data/lib/openc3/models/reaction_model.rb +6 -6
- data/lib/openc3/models/script_engine_model.rb +1 -1
- data/lib/openc3/models/script_status_model.rb +3 -3
- data/lib/openc3/models/sorted_model.rb +5 -5
- data/lib/openc3/models/target_model.rb +11 -11
- data/lib/openc3/models/timeline_model.rb +2 -2
- data/lib/openc3/models/tool_model.rb +1 -1
- data/lib/openc3/models/trigger_group_model.rb +3 -3
- data/lib/openc3/models/trigger_model.rb +6 -6
- data/lib/openc3/models/widget_model.rb +1 -1
- data/lib/openc3/operators/operator.rb +2 -2
- data/lib/openc3/packets/json_packet.rb +1 -1
- data/lib/openc3/packets/packet.rb +1 -1
- data/lib/openc3/script/calendar.rb +2 -2
- data/lib/openc3/script/metadata.rb +4 -4
- data/lib/openc3/script/queue.rb +13 -5
- data/lib/openc3/script/script_runner.rb +9 -9
- data/lib/openc3/script/storage.rb +1 -1
- data/lib/openc3/script/tables.rb +2 -2
- data/lib/openc3/script/web_socket_api.rb +7 -7
- data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +0 -12
- data/lib/openc3/tools/table_manager/table_manager_core.rb +1 -1
- data/lib/openc3/topics/command_decom_topic.rb +3 -3
- data/lib/openc3/topics/command_topic.rb +1 -1
- data/lib/openc3/topics/interface_topic.rb +45 -5
- data/lib/openc3/topics/limits_event_topic.rb +8 -8
- data/lib/openc3/topics/router_topic.rb +42 -3
- data/lib/openc3/topics/system_events_topic.rb +1 -1
- data/lib/openc3/topics/telemetry_decom_topic.rb +1 -1
- data/lib/openc3/utilities/authentication.rb +1 -1
- data/lib/openc3/utilities/cosmos_rails_formatter.rb +2 -3
- data/lib/openc3/utilities/local_mode.rb +8 -8
- data/lib/openc3/utilities/logger.rb +3 -3
- data/lib/openc3/utilities/running_script.rb +7 -8
- data/lib/openc3/version.rb +5 -5
- data/templates/plugin/README.md +3 -3
- data/templates/plugin/Rakefile +3 -3
- data/templates/plugin/plugin.gemspec +1 -0
- data/templates/tool_angular/.gitignore +1 -1
- data/templates/tool_angular/package.json +2 -48
- data/templates/tool_react/.gitignore +1 -2
- data/templates/tool_react/package.json +1 -51
- data/templates/tool_svelte/.gitignore +1 -2
- data/templates/tool_svelte/package.json +1 -49
- data/templates/tool_vue/package.json +3 -36
- data/templates/widget/Rakefile +1 -1
- data/templates/widget/package.json +2 -28
- metadata +9 -9
@@ -108,5 +108,19 @@ module OpenC3
|
|
108
108
|
@data_bits = option_values[0].to_i
|
109
109
|
end
|
110
110
|
end
|
111
|
+
|
112
|
+
def details
|
113
|
+
result = super()
|
114
|
+
result['write_port_name'] = @write_port_name
|
115
|
+
result['read_port_name'] = @read_port_name
|
116
|
+
result['baud_rate'] = @baud_rate
|
117
|
+
result['parity'] = @parity
|
118
|
+
result['stop_bits'] = @stop_bits
|
119
|
+
result['write_timeout'] = @write_timeout
|
120
|
+
result['read_timeout'] = @read_timeout
|
121
|
+
result['flow_control'] = @flow_control
|
122
|
+
result['data_bits'] = @data_bits
|
123
|
+
return result
|
124
|
+
end
|
111
125
|
end
|
112
126
|
end
|
@@ -49,9 +49,13 @@ module OpenC3
|
|
49
49
|
|
50
50
|
@hostname = hostname
|
51
51
|
@write_port = ConfigParser.handle_nil(write_port)
|
52
|
+
@write_port = Integer(@write_port) if @write_port
|
52
53
|
@read_port = ConfigParser.handle_nil(read_port)
|
53
|
-
@
|
54
|
-
@
|
54
|
+
@read_port = Integer(@read_port) if @read_port
|
55
|
+
@write_timeout = ConfigParser.handle_nil(write_timeout)
|
56
|
+
@write_timeout = Float(@write_timeout) if @write_timeout
|
57
|
+
@read_timeout = ConfigParser.handle_nil(read_timeout)
|
58
|
+
@read_timeout = Float(@read_timeout) if @read_timeout
|
55
59
|
@read_allowed = false unless @read_port
|
56
60
|
@write_allowed = false unless @write_port
|
57
61
|
@write_raw_allowed = false unless @write_port
|
@@ -90,5 +94,15 @@ module OpenC3
|
|
90
94
|
end
|
91
95
|
super()
|
92
96
|
end
|
97
|
+
|
98
|
+
def details
|
99
|
+
result = super()
|
100
|
+
result['hostname'] = @hostname
|
101
|
+
result['write_port'] = @write_port
|
102
|
+
result['read_port'] = @read_port
|
103
|
+
result['write_timeout'] = @write_timeout
|
104
|
+
result['read_timeout'] = @read_timeout
|
105
|
+
return result
|
106
|
+
end
|
93
107
|
end
|
94
108
|
end
|
@@ -297,7 +297,7 @@ module OpenC3
|
|
297
297
|
end
|
298
298
|
end
|
299
299
|
|
300
|
-
protected
|
300
|
+
# protected
|
301
301
|
|
302
302
|
def shutdown_interfaces(interface_infos)
|
303
303
|
@connection_mutex.synchronize do
|
@@ -626,5 +626,15 @@ module OpenC3
|
|
626
626
|
end
|
627
627
|
end # connection_mutex.synchronize
|
628
628
|
end
|
629
|
+
|
630
|
+
def details
|
631
|
+
result = super()
|
632
|
+
result['write_port'] = @write_port
|
633
|
+
result['read_port'] = @read_port
|
634
|
+
result['write_timeout'] = @write_timeout
|
635
|
+
result['read_timeout'] = @read_timeout
|
636
|
+
result['listen_address'] = @listen_address
|
637
|
+
return result
|
638
|
+
end
|
629
639
|
end
|
630
640
|
end
|
@@ -189,5 +189,19 @@ module OpenC3
|
|
189
189
|
@write_socket.write(data, @write_timeout)
|
190
190
|
return data, extra
|
191
191
|
end
|
192
|
+
|
193
|
+
def details
|
194
|
+
result = super()
|
195
|
+
result['hostname'] = @hostname
|
196
|
+
result['write_dest_port'] = @write_dest_port
|
197
|
+
result['read_port'] = @read_port
|
198
|
+
result['write_src_port'] = @write_src_port
|
199
|
+
result['interface_address'] = @interface_address
|
200
|
+
result['ttl'] = @ttl
|
201
|
+
result['write_timeout'] = @write_timeout
|
202
|
+
result['read_timeout'] = @read_timeout
|
203
|
+
result['bind_address'] = @bind_address
|
204
|
+
return result
|
205
|
+
end
|
192
206
|
end
|
193
207
|
end
|
@@ -184,7 +184,7 @@ module OpenC3
|
|
184
184
|
if !data.nil? and !data.is_a?(Hash) and !data.is_a?(String)
|
185
185
|
raise JsonApiError, "incorrect type for keyword 'data' MUST be Hash or String: #{data}"
|
186
186
|
end
|
187
|
-
return kwargs[:json] ? JSON.generate(data) : data
|
187
|
+
return kwargs[:json] ? JSON.generate(data, allow_nan: true) : data
|
188
188
|
end
|
189
189
|
|
190
190
|
# NOTE: This is a helper method and should not be called directly
|
data/lib/openc3/io/json_drb.rb
CHANGED
@@ -336,7 +336,7 @@ module OpenC3
|
|
336
336
|
protected
|
337
337
|
|
338
338
|
def process_response(response, start_time)
|
339
|
-
response_data = response.to_json(:
|
339
|
+
response_data = response.to_json(allow_nan: true)
|
340
340
|
STDOUT.puts response_data if JsonDRb.debug?
|
341
341
|
end_time = Time.now.sys
|
342
342
|
request_time = end_time - start_time
|
@@ -62,7 +62,7 @@ module OpenC3
|
|
62
62
|
@log = [nil, nil, nil]
|
63
63
|
connect() if !@http
|
64
64
|
json_rpc_request = JsonRpcRequest.new(method_name, method_params, keyword_params, @id)
|
65
|
-
data = json_rpc_request.to_json(:
|
65
|
+
data = json_rpc_request.to_json(allow_nan: true)
|
66
66
|
token = keyword_params[:token]
|
67
67
|
response_body = make_request(data: data, token: token)
|
68
68
|
if !response_body or response_body.to_s.length < 1
|
data/lib/openc3/io/json_rpc.rb
CHANGED
@@ -14,13 +14,14 @@
|
|
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 2025, OpenC3, Inc.
|
18
18
|
# All Rights Reserved
|
19
19
|
#
|
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
23
|
require 'json'
|
24
|
+
require 'json/add/string'
|
24
25
|
require 'date'
|
25
26
|
require 'openc3/core_ext/string'
|
26
27
|
|
@@ -196,7 +197,7 @@ module OpenC3
|
|
196
197
|
def <=>(other)
|
197
198
|
return nil unless other.respond_to?(:as_json)
|
198
199
|
|
199
|
-
self.as_json(
|
200
|
+
self.as_json() <=> other.as_json()
|
200
201
|
end
|
201
202
|
|
202
203
|
# @param a [Array] Array of options
|
@@ -267,7 +268,7 @@ module OpenC3
|
|
267
268
|
# @param request_headers [Hash] Request Header to include the auth token
|
268
269
|
# @return [JsonRpcRequest]
|
269
270
|
def self.from_json(request_data, request_headers)
|
270
|
-
hash = JSON.parse(request_data, :
|
271
|
+
hash = JSON.parse(request_data, allow_nan: true, create_additions: true)
|
271
272
|
hash['keyword_params']['token'] = request_headers['HTTP_AUTHORIZATION'] if request_headers['HTTP_AUTHORIZATION']
|
272
273
|
hash['keyword_params']['manual'] = request_headers['HTTP_MANUAL'] if request_headers['HTTP_MANUAL']
|
273
274
|
# Verify the jsonrpc version is correct and there is a method and id
|
@@ -306,7 +307,7 @@ module OpenC3
|
|
306
307
|
def self.from_json(response_data)
|
307
308
|
msg = "Invalid JSON-RPC 2.0 Response#{response_data.inspect}\n"
|
308
309
|
begin
|
309
|
-
hash = JSON.parse(response_data, :
|
310
|
+
hash = JSON.parse(response_data, allow_nan: true, create_additions: true)
|
310
311
|
rescue
|
311
312
|
raise $!, msg, $!.backtrace
|
312
313
|
end
|
@@ -201,7 +201,7 @@ module OpenC3
|
|
201
201
|
if cbor
|
202
202
|
key_map = CBOR.decode(entry[4..(key_map_length + 3)])
|
203
203
|
else
|
204
|
-
key_map = JSON.parse(entry[4..(key_map_length + 3)], :
|
204
|
+
key_map = JSON.parse(entry[4..(key_map_length + 3)], allow_nan: true, create_additions: true)
|
205
205
|
end
|
206
206
|
@packets[packet_index] << key_map
|
207
207
|
return read(identify_and_define)
|
@@ -215,7 +215,7 @@ module OpenC3
|
|
215
215
|
key_map = @key_map_table[packet_index]
|
216
216
|
unless key_map
|
217
217
|
parsed = data
|
218
|
-
parsed = JSON.parse(data, :
|
218
|
+
parsed = JSON.parse(data, allow_nan: true, create_additions: true) if String === parsed
|
219
219
|
keys = parsed.keys
|
220
220
|
key_map = {}
|
221
221
|
reverse_key_map = {}
|
@@ -227,7 +227,7 @@ module OpenC3
|
|
227
227
|
if @data_format == :CBOR
|
228
228
|
write_entry(:KEY_MAP, cmd_or_tlm, target_name, packet_name, nil, nil, key_map.to_cbor, nil)
|
229
229
|
else # JSON
|
230
|
-
write_entry(:KEY_MAP, cmd_or_tlm, target_name, packet_name, nil, nil, JSON.generate(key_map, :
|
230
|
+
write_entry(:KEY_MAP, cmd_or_tlm, target_name, packet_name, nil, nil, JSON.generate(key_map, allow_nan: true), nil)
|
231
231
|
end
|
232
232
|
end
|
233
233
|
end
|
@@ -292,7 +292,7 @@ module OpenC3
|
|
292
292
|
key_map = @key_map_table[packet_index]
|
293
293
|
if key_map
|
294
294
|
# Compress data using key map
|
295
|
-
data = JSON.parse(data, :
|
295
|
+
data = JSON.parse(data, allow_nan: true, create_additions: true) if String === data
|
296
296
|
compressed = {}
|
297
297
|
data.each do |key, value|
|
298
298
|
compressed_key = key_map[key]
|
@@ -303,7 +303,7 @@ module OpenC3
|
|
303
303
|
flags |= OPENC3_CBOR_FLAG_MASK
|
304
304
|
data = compressed.to_cbor
|
305
305
|
else
|
306
|
-
data = JSON.generate(compressed, :
|
306
|
+
data = JSON.generate(compressed, allow_nan: true)
|
307
307
|
end
|
308
308
|
end
|
309
309
|
end
|
@@ -317,12 +317,12 @@ module OpenC3
|
|
317
317
|
extra_encoded = nil
|
318
318
|
if extra
|
319
319
|
flags |= OPENC3_EXTRA_FLAG_MASK
|
320
|
-
extra = JSON.parse(extra, :
|
320
|
+
extra = JSON.parse(extra, allow_nan: true, create_additions: true) if String === extra
|
321
321
|
length += OPENC3_EXTRA_LENGTH_FIXED_SIZE
|
322
322
|
if @data_format == :CBOR
|
323
323
|
extra_encoded = extra.as_json.to_cbor
|
324
324
|
else
|
325
|
-
extra_encoded = JSON.generate(extra.as_json, :
|
325
|
+
extra_encoded = JSON.generate(extra.as_json, allow_nan: true)
|
326
326
|
end
|
327
327
|
length += extra_encoded.length
|
328
328
|
end
|
@@ -202,7 +202,11 @@ module OpenC3
|
|
202
202
|
def limits_change_callback(packet, item, old_limits_state, value, log_change)
|
203
203
|
return if @cancel_thread
|
204
204
|
# Make a copy because packet_time is frozen
|
205
|
-
|
205
|
+
if packet.packet_time
|
206
|
+
packet_time = packet.packet_time.dup
|
207
|
+
else
|
208
|
+
packet_time = Time.now.utc
|
209
|
+
end
|
206
210
|
if value
|
207
211
|
message = "#{packet.target_name} #{packet.packet_name} #{item.name} = #{value} is #{item.limits.state}"
|
208
212
|
if item.limits.values
|
@@ -116,7 +116,7 @@ module OpenC3
|
|
116
116
|
@logger.info "#{@interface.name}: Connect requested"
|
117
117
|
params = []
|
118
118
|
if msg_hash['params']
|
119
|
-
params = JSON.parse(msg_hash['params'], :
|
119
|
+
params = JSON.parse(msg_hash['params'], allow_nan: true, create_additions: true)
|
120
120
|
end
|
121
121
|
@interface = @tlm.attempting(*params)
|
122
122
|
next 'SUCCESS'
|
@@ -163,7 +163,7 @@ module OpenC3
|
|
163
163
|
begin
|
164
164
|
@logger.info "#{@interface.name}: interface_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
|
165
165
|
@interface.interface_cmd(params['cmd_name'], *params['cmd_params'])
|
166
|
-
InterfaceStatusModel.set(@interface.as_json(
|
166
|
+
InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
167
167
|
rescue => e
|
168
168
|
@logger.error "#{@interface.name}: interface_cmd: #{e.formatted}"
|
169
169
|
next e.message
|
@@ -175,7 +175,7 @@ module OpenC3
|
|
175
175
|
begin
|
176
176
|
@logger.info "#{@interface.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
|
177
177
|
@interface.protocol_cmd(params['cmd_name'], *params['cmd_params'], read_write: params['read_write'], index: params['index'])
|
178
|
-
InterfaceStatusModel.set(@interface.as_json(
|
178
|
+
InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
179
179
|
rescue => e
|
180
180
|
@logger.error "#{@interface.name}: protocol_cmd: #{e.formatted}"
|
181
181
|
next e.message
|
@@ -196,16 +196,45 @@ module OpenC3
|
|
196
196
|
next "Critical command #{msg_hash['release_critical']} not found"
|
197
197
|
end
|
198
198
|
end
|
199
|
+
if msg_hash.key?('target_control')
|
200
|
+
begin
|
201
|
+
params = JSON.parse(msg_hash['target_control'], allow_nan: true, create_additions: true)
|
202
|
+
target_name = params['target_name']
|
203
|
+
cmd_only = params['cmd_only']
|
204
|
+
tlm_only = params['tlm_only']
|
205
|
+
action = params['action']
|
206
|
+
if action == 'disable'
|
207
|
+
@interface.cmd_target_enabled[target_name] = false unless tlm_only
|
208
|
+
@interface.tlm_target_enabled[target_name] = false unless cmd_only
|
209
|
+
@logger.info "#{@interface.name}: target_disable: #{target_name} cmd_only:#{cmd_only} tlm_only:#{tlm_only}"
|
210
|
+
else # enable
|
211
|
+
@interface.cmd_target_enabled[target_name] = true unless tlm_only
|
212
|
+
@interface.tlm_target_enabled[target_name] = true unless cmd_only
|
213
|
+
@logger.info "#{@interface.name}: target_enable: #{target_name} cmd_only:#{cmd_only} tlm_only:#{tlm_only}"
|
214
|
+
end
|
215
|
+
rescue => e
|
216
|
+
@logger.error "#{@interface.name}: target_control: #{e.formatted}"
|
217
|
+
next e.message
|
218
|
+
end
|
219
|
+
next 'SUCCESS'
|
220
|
+
end
|
221
|
+
if msg_hash.key?('interface_details')
|
222
|
+
next @interface.details.as_json.to_json(allow_nan: true)
|
223
|
+
end
|
199
224
|
end
|
200
225
|
|
201
226
|
target_name = msg_hash['target_name']
|
227
|
+
if target_name and not @interface.cmd_target_enabled[target_name]
|
228
|
+
next nil # Return and don't ack given target_name if disabled
|
229
|
+
end
|
230
|
+
|
202
231
|
cmd_name = msg_hash['cmd_name']
|
203
232
|
manual = ConfigParser.handle_true_false(msg_hash['manual'])
|
204
233
|
cmd_params = nil
|
205
234
|
cmd_buffer = nil
|
206
235
|
hazardous_check = nil
|
207
236
|
if msg_hash['cmd_params']
|
208
|
-
cmd_params = JSON.parse(msg_hash['cmd_params'], :
|
237
|
+
cmd_params = JSON.parse(msg_hash['cmd_params'], allow_nan: true, create_additions: true)
|
209
238
|
range_check = ConfigParser.handle_true_false(msg_hash['range_check'])
|
210
239
|
raw = ConfigParser.handle_true_false(msg_hash['raw'])
|
211
240
|
hazardous_check = ConfigParser.handle_true_false(msg_hash['hazardous_check'])
|
@@ -230,10 +259,15 @@ module OpenC3
|
|
230
259
|
else
|
231
260
|
raise "Invalid command received:\n #{msg_hash}"
|
232
261
|
end
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
262
|
+
|
263
|
+
if @interface.cmd_target_enabled[command.target_name]
|
264
|
+
orig_command = System.commands.packet(command.target_name, command.packet_name)
|
265
|
+
orig_command.received_count = TargetModel.increment_command_count(command.target_name, command.packet_name, 1, scope: @scope)
|
266
|
+
command.received_count = orig_command.received_count
|
267
|
+
command.received_time = Time.now
|
268
|
+
else
|
269
|
+
next nil # Don't ack disabled targets
|
270
|
+
end
|
237
271
|
rescue => e
|
238
272
|
@logger.error "#{@interface.name}: #{msg_hash}"
|
239
273
|
@logger.error "#{@interface.name}: #{e.formatted}"
|
@@ -312,7 +346,7 @@ module OpenC3
|
|
312
346
|
|
313
347
|
CommandDecomTopic.write_packet(command, scope: @scope)
|
314
348
|
CommandTopic.write_packet(command, scope: @scope)
|
315
|
-
InterfaceStatusModel.set(@interface.as_json(
|
349
|
+
InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
316
350
|
|
317
351
|
# Explicitly check for false to allow nil to represent unknown
|
318
352
|
if result == false
|
@@ -391,7 +425,7 @@ module OpenC3
|
|
391
425
|
@logger.info "#{@router.name}: Connect requested"
|
392
426
|
params = []
|
393
427
|
if msg_hash['params']
|
394
|
-
params = JSON.parse(msg_hash['params'], :
|
428
|
+
params = JSON.parse(msg_hash['params'], allow_nan: true, create_additions: true)
|
395
429
|
end
|
396
430
|
@router = @tlm.attempting(*params)
|
397
431
|
end
|
@@ -413,7 +447,7 @@ module OpenC3
|
|
413
447
|
begin
|
414
448
|
@logger.info "#{@router.name}: router_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
|
415
449
|
@router.interface_cmd(params['cmd_name'], *params['cmd_params'])
|
416
|
-
RouterStatusModel.set(@router.as_json(
|
450
|
+
RouterStatusModel.set(@router.as_json(), queued: true, scope: @scope)
|
417
451
|
rescue => e
|
418
452
|
@logger.error "#{@router.name}: router_cmd: #{e.formatted}"
|
419
453
|
next e.message
|
@@ -425,13 +459,38 @@ module OpenC3
|
|
425
459
|
begin
|
426
460
|
@logger.info "#{@router.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
|
427
461
|
@router.protocol_cmd(params['cmd_name'], *params['cmd_params'], read_write: params['read_write'], index: params['index'])
|
428
|
-
RouterStatusModel.set(@router.as_json(
|
462
|
+
RouterStatusModel.set(@router.as_json(), queued: true, scope: @scope)
|
463
|
+
rescue => e
|
464
|
+
@logger.error "#{@router.name}: protocol_cmd: #{e.formatted}"
|
465
|
+
next e.message
|
466
|
+
end
|
467
|
+
next 'SUCCESS'
|
468
|
+
end
|
469
|
+
if msg_hash.key?('target_control')
|
470
|
+
begin
|
471
|
+
params = JSON.parse(msg_hash['target_control'], allow_nan: true, create_additions: true)
|
472
|
+
target_name = params['target_name']
|
473
|
+
cmd_only = params['cmd_only']
|
474
|
+
tlm_only = params['tlm_only']
|
475
|
+
action = params['action']
|
476
|
+
if action == 'disable'
|
477
|
+
@router.cmd_target_enabled[target_name] = false unless tlm_only
|
478
|
+
@router.tlm_target_enabled[target_name] = false unless cmd_only
|
479
|
+
@logger.info "#{@router.name}: target_disable: #{target_name} cmd_only:#{cmd_only} tlm_only:#{tlm_only}"
|
480
|
+
else # enable
|
481
|
+
@router.cmd_target_enabled[target_name] = true unless tlm_only
|
482
|
+
@router.tlm_target_enabled[target_name] = true unless cmd_only
|
483
|
+
@logger.info "#{@router.name}: target_enable: #{target_name} cmd_only:#{cmd_only} tlm_only:#{tlm_only}"
|
484
|
+
end
|
429
485
|
rescue => e
|
430
|
-
@logger.error "#{@router.name}:
|
486
|
+
@logger.error "#{@router.name}: target_control: #{e.formatted}"
|
431
487
|
next e.message
|
432
488
|
end
|
433
489
|
next 'SUCCESS'
|
434
490
|
end
|
491
|
+
if msg_hash.key?('router_details')
|
492
|
+
next @router.details.as_json.to_json(allow_nan: true)
|
493
|
+
end
|
435
494
|
next 'SUCCESS'
|
436
495
|
end
|
437
496
|
|
@@ -442,20 +501,24 @@ module OpenC3
|
|
442
501
|
target_name = msg_hash["target_name"]
|
443
502
|
packet_name = msg_hash["packet_name"]
|
444
503
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
504
|
+
if @router.tlm_target_enabled[target_name]
|
505
|
+
packet = System.telemetry.packet(target_name, packet_name)
|
506
|
+
packet.stored = ConfigParser.handle_true_false(msg_hash["stored"])
|
507
|
+
packet.received_time = Time.from_nsec_from_epoch(msg_hash["time"].to_i)
|
508
|
+
packet.received_count = msg_hash["received_count"].to_i
|
509
|
+
packet.buffer = msg_hash["buffer"]
|
450
510
|
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
511
|
+
begin
|
512
|
+
@router.write(packet)
|
513
|
+
RouterStatusModel.set(@router.as_json(), queued: true, scope: @scope)
|
514
|
+
next 'SUCCESS'
|
515
|
+
rescue => e
|
516
|
+
@logger.error "#{@router.name}: #{e.formatted}"
|
517
|
+
next e.message
|
518
|
+
end
|
458
519
|
end
|
520
|
+
else
|
521
|
+
next nil # Don't ack disabled targets
|
459
522
|
end
|
460
523
|
end
|
461
524
|
end
|
@@ -510,9 +573,9 @@ module OpenC3
|
|
510
573
|
@interface.state = 'DISCONNECTED'
|
511
574
|
end
|
512
575
|
if @interface_or_router == 'INTERFACE'
|
513
|
-
InterfaceStatusModel.set(@interface.as_json(
|
576
|
+
InterfaceStatusModel.set(@interface.as_json(), scope: @scope)
|
514
577
|
else
|
515
|
-
RouterStatusModel.set(@interface.as_json(
|
578
|
+
RouterStatusModel.set(@interface.as_json(), scope: @scope)
|
516
579
|
end
|
517
580
|
|
518
581
|
@queued = false
|
@@ -576,9 +639,9 @@ module OpenC3
|
|
576
639
|
|
577
640
|
@interface.state = 'ATTEMPTING'
|
578
641
|
if @interface_or_router == 'INTERFACE'
|
579
|
-
InterfaceStatusModel.set(@interface.as_json(
|
642
|
+
InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
580
643
|
else
|
581
|
-
RouterStatusModel.set(@interface.as_json(
|
644
|
+
RouterStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
582
645
|
end
|
583
646
|
@interface # Return the interface/router since we may have recreated it
|
584
647
|
# Need to rescue Exception so we cover LoadError
|
@@ -651,15 +714,15 @@ module OpenC3
|
|
651
714
|
disconnect(false)
|
652
715
|
end
|
653
716
|
if @interface_or_router == 'INTERFACE'
|
654
|
-
InterfaceStatusModel.set(@interface.as_json(
|
717
|
+
InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
655
718
|
else
|
656
|
-
RouterStatusModel.set(@interface.as_json(
|
719
|
+
RouterStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
657
720
|
end
|
658
721
|
@logger.info "#{@interface.name}: Stopped packet reading"
|
659
722
|
end
|
660
723
|
|
661
724
|
def handle_packet(packet)
|
662
|
-
InterfaceStatusModel.set(@interface.as_json(
|
725
|
+
InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
663
726
|
packet.received_time = Time.now.sys unless packet.received_time
|
664
727
|
|
665
728
|
if packet.stored
|
@@ -709,8 +772,10 @@ module OpenC3
|
|
709
772
|
end
|
710
773
|
|
711
774
|
# Write to stream
|
712
|
-
|
713
|
-
|
775
|
+
if @interface.tlm_target_enabled[packet.target_name]
|
776
|
+
sync_tlm_packet_counts(packet)
|
777
|
+
TelemetryTopic.write_packet(packet, queued: @queued, scope: @scope)
|
778
|
+
end
|
714
779
|
end
|
715
780
|
|
716
781
|
def handle_connection_failed(connection, connect_error)
|
@@ -774,9 +839,9 @@ module OpenC3
|
|
774
839
|
end
|
775
840
|
@interface.state = 'CONNECTED'
|
776
841
|
if @interface_or_router == 'INTERFACE'
|
777
|
-
InterfaceStatusModel.set(@interface.as_json(
|
842
|
+
InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
778
843
|
else
|
779
|
-
RouterStatusModel.set(@interface.as_json(
|
844
|
+
RouterStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
780
845
|
end
|
781
846
|
@logger.info "#{@interface.name}: Connection Success"
|
782
847
|
end
|
@@ -806,9 +871,9 @@ module OpenC3
|
|
806
871
|
else
|
807
872
|
@interface.state = 'DISCONNECTED'
|
808
873
|
if @interface_or_router == 'INTERFACE'
|
809
|
-
InterfaceStatusModel.set(@interface.as_json(
|
874
|
+
InterfaceStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
810
875
|
else
|
811
|
-
RouterStatusModel.set(@interface.as_json(
|
876
|
+
RouterStatusModel.set(@interface.as_json(), queued: true, scope: @scope)
|
812
877
|
end
|
813
878
|
end
|
814
879
|
end
|
@@ -52,7 +52,7 @@ module OpenC3
|
|
52
52
|
microservice = self.new(name)
|
53
53
|
thread = Thread.new do
|
54
54
|
begin
|
55
|
-
MicroserviceStatusModel.set(microservice.as_json(
|
55
|
+
MicroserviceStatusModel.set(microservice.as_json(), scope: microservice.scope)
|
56
56
|
microservice.state = 'RUNNING'
|
57
57
|
microservice.run
|
58
58
|
microservice.state = 'FINISHED'
|
@@ -66,7 +66,7 @@ module OpenC3
|
|
66
66
|
end
|
67
67
|
microservice.shutdown # Dying in crash so should try to shutdown
|
68
68
|
ensure
|
69
|
-
MicroserviceStatusModel.set(microservice.as_json(
|
69
|
+
MicroserviceStatusModel.set(microservice.as_json(), scope: microservice.scope)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
ThreadManager.instance.register(thread, shutdown_object: microservice)
|
@@ -192,7 +192,7 @@ module OpenC3
|
|
192
192
|
@microservice_status_period_seconds = 5
|
193
193
|
@microservice_status_thread = Thread.new do
|
194
194
|
until @cancel_thread
|
195
|
-
MicroserviceStatusModel.set(as_json(
|
195
|
+
MicroserviceStatusModel.set(as_json(), scope: @scope) unless @cancel_thread
|
196
196
|
break if @microservice_status_sleeper.sleep(@microservice_status_period_seconds)
|
197
197
|
end
|
198
198
|
rescue Exception => e
|
@@ -214,7 +214,7 @@ module OpenC3
|
|
214
214
|
@state = state
|
215
215
|
@cancel_thread = true
|
216
216
|
@microservice_status_sleeper.cancel if @microservice_status_sleeper
|
217
|
-
MicroserviceStatusModel.set(as_json(
|
217
|
+
MicroserviceStatusModel.set(as_json(), scope: @scope)
|
218
218
|
FileUtils.remove_entry_secure(@temp_dir, true)
|
219
219
|
@metric.shutdown
|
220
220
|
@logger.debug("Shutting down microservice complete: #{@name}")
|
@@ -19,11 +19,21 @@
|
|
19
19
|
require 'openc3/microservices/microservice'
|
20
20
|
require 'openc3/topics/queue_topic'
|
21
21
|
require 'openc3/utilities/authentication'
|
22
|
-
require 'openc3/
|
22
|
+
require 'openc3/api/api'
|
23
23
|
|
24
24
|
module OpenC3
|
25
|
+
module Script
|
26
|
+
private
|
27
|
+
# Override the prompt_for_hazardous method to always return true since there is no user to prompt
|
28
|
+
def prompt_for_hazardous(target_name, cmd_name, hazardous_description)
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
25
33
|
# The queue processor runs in a single thread and processes commands via cmd_api.
|
26
34
|
class QueueProcessor
|
35
|
+
include Api # Provides access to api methods
|
36
|
+
|
27
37
|
attr_accessor :state
|
28
38
|
attr_reader :name, :scope
|
29
39
|
|
@@ -35,23 +45,6 @@ module OpenC3
|
|
35
45
|
@cancel_thread = false
|
36
46
|
end
|
37
47
|
|
38
|
-
def get_token(username)
|
39
|
-
if ENV['OPENC3_API_CLIENT'].nil?
|
40
|
-
ENV['OPENC3_API_PASSWORD'] ||= ENV['OPENC3_SERVICE_PASSWORD']
|
41
|
-
return OpenC3Authentication.new().token
|
42
|
-
else
|
43
|
-
# Check for offline access token
|
44
|
-
model = nil
|
45
|
-
model = OpenC3::OfflineAccessModel.get_model(name: username, scope: @scope) if username and username != ''
|
46
|
-
if model and model.offline_access_token
|
47
|
-
auth = OpenC3KeycloakAuthentication.new(ENV['OPENC3_KEYCLOAK_URL'])
|
48
|
-
return auth.get_token_from_refresh_token(model.offline_access_token)
|
49
|
-
else
|
50
|
-
return nil
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
48
|
def run
|
56
49
|
while true
|
57
50
|
if @state == 'RELEASE'
|
@@ -69,11 +62,11 @@ module OpenC3
|
|
69
62
|
_queue_name, command_data, _timestamp = Store.bzpopmin("#{@scope}:#{@name}", timeout: 0.2)
|
70
63
|
if command_data
|
71
64
|
command = JSON.parse(command_data)
|
72
|
-
username = command['username']
|
73
|
-
token = get_token(username)
|
74
65
|
# It's important to set queue: false here to avoid infinite recursion when
|
75
66
|
# OPENC3_DEFAULT_QUEUE is set because commands would be re-queued to the default queue
|
76
|
-
|
67
|
+
# NOTE: cmd() via script rescues hazardous errors and calls prompt_for_hazardous()
|
68
|
+
# but we've overridden it to always return true and go straight to cmd_no_hazardous_check()
|
69
|
+
cmd(command['value'], queue: false, scope: @scope)
|
77
70
|
end
|
78
71
|
rescue StandardError => e
|
79
72
|
@logger.error "QueueProcessor failed to process command from queue #{@name}\n#{e.message}"
|
@@ -522,7 +522,7 @@ module OpenC3
|
|
522
522
|
reduce(type, state.raw_keys, state.converted_keys, state.reduced)
|
523
523
|
state.reduced.merge!(state.entry_samples)
|
524
524
|
time = state.entry_time
|
525
|
-
data = JSON.generate(state.reduced.as_json
|
525
|
+
data = JSON.generate(state.reduced.as_json, allow_nan: true)
|
526
526
|
if type == "minute"
|
527
527
|
redis_topic, redis_offset = TelemetryReducedMinuteTopic.write(target_name: target_name, packet_name: packet_name, stored: stored, time: time, data: data, scope: @scope)
|
528
528
|
elsif type == "hour"
|