openc3 5.13.0 → 5.14.0
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/Gemfile +3 -3
- data/bin/openc3cli +18 -15
- data/data/config/command_modifiers.yaml +53 -1
- data/lib/openc3/accessors/accessor.rb +42 -29
- data/lib/openc3/accessors/binary_accessor.rb +11 -1
- data/lib/openc3/accessors/form_accessor.rb +11 -1
- data/lib/openc3/accessors/http_accessor.rb +38 -0
- data/lib/openc3/accessors/json_accessor.rb +15 -3
- data/lib/openc3/accessors/template_accessor.rb +150 -0
- data/lib/openc3/accessors/xml_accessor.rb +11 -1
- data/lib/openc3/accessors.rb +1 -0
- data/lib/openc3/api/limits_api.rb +3 -3
- data/lib/openc3/api/tlm_api.rb +8 -8
- data/lib/openc3/interfaces/interface.rb +9 -7
- data/lib/openc3/interfaces/protocols/cmd_response_protocol.rb +116 -0
- data/lib/openc3/interfaces/tcpip_client_interface.rb +4 -0
- data/lib/openc3/interfaces/tcpip_server_interface.rb +5 -0
- data/lib/openc3/interfaces.rb +1 -1
- data/lib/openc3/microservices/decom_microservice.rb +1 -0
- data/lib/openc3/microservices/interface_microservice.rb +10 -1
- data/lib/openc3/models/cvt_model.rb +16 -12
- data/lib/openc3/models/gem_model.rb +20 -3
- data/lib/openc3/models/microservice_model.rb +1 -1
- data/lib/openc3/models/plugin_model.rb +5 -1
- data/lib/openc3/models/target_model.rb +69 -8
- data/lib/openc3/packets/packet.rb +92 -4
- data/lib/openc3/packets/packet_config.rb +25 -1
- data/lib/openc3/script/api_shared.rb +11 -0
- data/lib/openc3/script/script.rb +6 -12
- data/lib/openc3/streams/tcpip_socket_stream.rb +19 -0
- data/lib/openc3/system/system.rb +13 -1
- data/lib/openc3/utilities/cli_generator.rb +15 -1
- data/lib/openc3/utilities/local_mode.rb +1 -1
- data/lib/openc3/utilities/store_queued.rb +126 -0
- data/lib/openc3/version.rb +5 -5
- data/templates/plugin/plugin.gemspec +2 -2
- data/templates/target/targets/TARGET/public/README.txt +1 -0
- data/templates/tool_angular/package.json +15 -15
- data/templates/tool_angular/yarn.lock +184 -78
- data/templates/tool_react/package.json +10 -10
- data/templates/tool_react/yarn.lock +236 -374
- data/templates/tool_svelte/package.json +13 -13
- data/templates/tool_svelte/yarn.lock +246 -235
- data/templates/tool_vue/package.json +12 -12
- data/templates/tool_vue/yarn.lock +63 -55
- data/templates/widget/package.json +11 -11
- data/templates/widget/yarn.lock +54 -46
- metadata +144 -154
- data/lib/openc3/io/openc3_snmp.rb +0 -61
@@ -190,10 +190,10 @@ module OpenC3
|
|
190
190
|
# 'TVAC' => [-25, -10, 50, 55] }
|
191
191
|
#
|
192
192
|
# @return [Hash{String => Array<Number, Number, Number, Number, Number, Number>}]
|
193
|
-
def get_limits(target_name, packet_name, item_name, scope: $openc3_scope, token: $openc3_token)
|
193
|
+
def get_limits(target_name, packet_name, item_name, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
194
194
|
authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
195
195
|
limits = {}
|
196
|
-
item = _get_item(target_name, packet_name, item_name, scope: scope)
|
196
|
+
item = _get_item(target_name, packet_name, item_name, cache_timeout: cache_timeout, scope: scope)
|
197
197
|
item['limits'].each do |key, vals|
|
198
198
|
next unless vals.is_a?(Hash)
|
199
199
|
|
@@ -374,7 +374,7 @@ module OpenC3
|
|
374
374
|
# @param item_name [String] item name
|
375
375
|
# @param scope [String] scope
|
376
376
|
# @return Hash The requested item based on the packet name
|
377
|
-
def _get_item(target_name, packet_name, item_name, cache_timeout:
|
377
|
+
def _get_item(target_name, packet_name, item_name, cache_timeout: nil, scope:)
|
378
378
|
# Determine if this item exists, it will raise appropriate errors if not
|
379
379
|
packet_name = CvtModel.determine_latest_packet_for_item(target_name, item_name, cache_timeout: cache_timeout, scope: $openc3_scope) if packet_name == 'LATEST'
|
380
380
|
return TargetModel.packet_item(target_name, packet_name, item_name, scope: scope)
|
data/lib/openc3/api/tlm_api.rb
CHANGED
@@ -69,26 +69,26 @@ module OpenC3
|
|
69
69
|
# @param args [String|Array<String>] See the description for calling style
|
70
70
|
# @param type [Symbol] Telemetry type, :RAW, :CONVERTED (default), :FORMATTED, or :WITH_UNITS
|
71
71
|
# @return [Object] The telemetry value formatted as requested
|
72
|
-
def tlm(*args, type: :CONVERTED, cache_timeout:
|
72
|
+
def tlm(*args, type: :CONVERTED, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
73
73
|
target_name, packet_name, item_name = _tlm_process_args(args, 'tlm', cache_timeout: cache_timeout, scope: scope)
|
74
74
|
authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
75
75
|
CvtModel.get_item(target_name, packet_name, item_name, type: type.intern, cache_timeout: cache_timeout, scope: scope)
|
76
76
|
end
|
77
77
|
|
78
|
-
def tlm_raw(*args, cache_timeout:
|
78
|
+
def tlm_raw(*args, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
79
79
|
tlm(*args, type: :RAW, cache_timeout: cache_timeout, scope: scope, token: token)
|
80
80
|
end
|
81
81
|
|
82
|
-
def tlm_formatted(*args, cache_timeout:
|
82
|
+
def tlm_formatted(*args, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
83
83
|
tlm(*args, type: :FORMATTED, cache_timeout: cache_timeout, scope: scope, token: token)
|
84
84
|
end
|
85
85
|
|
86
|
-
def tlm_with_units(*args, cache_timeout:
|
86
|
+
def tlm_with_units(*args, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
87
87
|
tlm(*args, type: :WITH_UNITS, cache_timeout: cache_timeout, scope: scope, token: token)
|
88
88
|
end
|
89
89
|
|
90
90
|
# @deprecated Use tlm with type:
|
91
|
-
def tlm_variable(*args, cache_timeout:
|
91
|
+
def tlm_variable(*args, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
92
92
|
tlm(*args[0..-2], type: args[-1].intern, cache_timeout: cache_timeout, scope: scope, token: token)
|
93
93
|
end
|
94
94
|
|
@@ -226,7 +226,7 @@ module OpenC3
|
|
226
226
|
# @return [Array<String, Object, Symbol|nil>] Returns an Array consisting
|
227
227
|
# of [item name, item value, item limits state] where the item limits
|
228
228
|
# state can be one of {OpenC3::Limits::LIMITS_STATES}
|
229
|
-
def get_tlm_packet(*args, stale_time: 30, type: :CONVERTED, cache_timeout:
|
229
|
+
def get_tlm_packet(*args, stale_time: 30, type: :CONVERTED, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
230
230
|
target_name, packet_name = _extract_target_packet_names('get_tlm_packet', *args)
|
231
231
|
authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
232
232
|
packet = TargetModel.packet(target_name, packet_name, scope: scope)
|
@@ -248,7 +248,7 @@ module OpenC3
|
|
248
248
|
# @return [Array<Object, Symbol>]
|
249
249
|
# Array consisting of the item value and limits state
|
250
250
|
# given as symbols such as :RED, :YELLOW, :STALE
|
251
|
-
def get_tlm_values(items, stale_time: 30, cache_timeout:
|
251
|
+
def get_tlm_values(items, stale_time: 30, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
252
252
|
if !items.is_a?(Array) || !items[0].is_a?(String)
|
253
253
|
raise ArgumentError, "items must be array of strings: ['TGT__PKT__ITEM__TYPE', ...]"
|
254
254
|
end
|
@@ -466,7 +466,7 @@ module OpenC3
|
|
466
466
|
return nil
|
467
467
|
end
|
468
468
|
|
469
|
-
def _tlm_process_args(args, method_name, cache_timeout:
|
469
|
+
def _tlm_process_args(args, method_name, cache_timeout: nil, scope: $openc3_scope, token: $openc3_token)
|
470
470
|
case args.length
|
471
471
|
when 1
|
472
472
|
target_name, packet_name, item_name = extract_fields_from_tlm_text(args[0])
|
@@ -198,14 +198,16 @@ module OpenC3
|
|
198
198
|
log_dont_log.upcase!
|
199
199
|
period = "#{period.to_f}s"
|
200
200
|
@scheduler.every period do
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
201
|
+
if connected?()
|
202
|
+
begin
|
203
|
+
if log_dont_log == 'DONT_LOG'
|
204
|
+
cmd(cmd_string, log_message: false)
|
205
|
+
else
|
206
|
+
cmd(cmd_string)
|
207
|
+
end
|
208
|
+
rescue Exception => err
|
209
|
+
Logger.error("Error sending periodic cmd(#{cmd_string}):\n#{err.formatted}")
|
206
210
|
end
|
207
|
-
rescue Exception => err
|
208
|
-
Logger.error("Error sending periodic cmd(#{cmd_string}):\n#{err.formatted}")
|
209
211
|
end
|
210
212
|
end
|
211
213
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2024 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# This file may also be used under the terms of a commercial license
|
17
|
+
# if purchased from OpenC3, Inc.
|
18
|
+
|
19
|
+
require 'openc3/config/config_parser'
|
20
|
+
require 'openc3/interfaces/protocols/protocol'
|
21
|
+
require 'thread' # For Queue
|
22
|
+
require 'timeout' # For Timeout::Error
|
23
|
+
|
24
|
+
module OpenC3
|
25
|
+
# Protocol that waits for a response for any commands with a defined response packet.
|
26
|
+
# The response packet is identified but not defined by the protocol.
|
27
|
+
class CmdResponseProtocol < Protocol
|
28
|
+
# @param response_timeout [Float] Number of seconds to wait before timing out
|
29
|
+
# when waiting for a response
|
30
|
+
# @param response_polling_period [Float] Number of seconds to wait between polling
|
31
|
+
# for a response
|
32
|
+
# @param raise_exceptions [String] Whether to raise exceptions when errors
|
33
|
+
# occur in the protocol like unexpected responses or response timeouts.
|
34
|
+
# @param allow_empty_data [true/false/nil] See Protocol#initialize
|
35
|
+
def initialize(
|
36
|
+
response_timeout = 5.0,
|
37
|
+
response_polling_period = 0.02,
|
38
|
+
raise_exceptions = false,
|
39
|
+
allow_empty_data = nil
|
40
|
+
)
|
41
|
+
super(allow_empty_data)
|
42
|
+
@response_timeout = ConfigParser.handle_nil(response_timeout)
|
43
|
+
@response_timeout = @response_timeout.to_f if @response_timeout
|
44
|
+
@response_polling_period = response_polling_period.to_f
|
45
|
+
@raise_exceptions = ConfigParser.handle_true_false(raise_exceptions)
|
46
|
+
@write_block_queue = Queue.new
|
47
|
+
@response_packet = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def connect_reset
|
51
|
+
super()
|
52
|
+
@write_block_queue.clear
|
53
|
+
end
|
54
|
+
|
55
|
+
def disconnect_reset
|
56
|
+
super()
|
57
|
+
@write_block_queue << nil # Unblock the write block queue
|
58
|
+
end
|
59
|
+
|
60
|
+
def read_packet(packet)
|
61
|
+
if @response_packet
|
62
|
+
# Grab the response packet specified in the command
|
63
|
+
result_packet = System.telemetry.packet(@response_packet[0], @response_packet[1]).clone
|
64
|
+
result_packet.buffer = packet.buffer
|
65
|
+
result_packet.received_time = nil
|
66
|
+
result_packet.stored = packet.stored
|
67
|
+
result_packet.extra = packet.extra
|
68
|
+
|
69
|
+
# Release the write
|
70
|
+
@write_block_queue << nil
|
71
|
+
|
72
|
+
# This returns the fully identified and defined packet
|
73
|
+
# Received time is handled by the interface microservice
|
74
|
+
return result_packet
|
75
|
+
else
|
76
|
+
return packet
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def write_packet(packet)
|
81
|
+
# Setup the response packet (if there is one)
|
82
|
+
# This primes waiting for the response in post_write_interface
|
83
|
+
@response_packet = packet.response
|
84
|
+
|
85
|
+
return packet
|
86
|
+
end
|
87
|
+
|
88
|
+
def post_write_interface(packet, data, extra = nil)
|
89
|
+
if @response_packet
|
90
|
+
if @response_timeout
|
91
|
+
response_timeout_time = Time.now + @response_timeout
|
92
|
+
else
|
93
|
+
response_timeout_time = nil
|
94
|
+
end
|
95
|
+
|
96
|
+
# Block the write until the response is received
|
97
|
+
begin
|
98
|
+
@write_block_queue.pop(true)
|
99
|
+
rescue
|
100
|
+
sleep(@response_polling_period)
|
101
|
+
retry if !response_timeout_time
|
102
|
+
retry if response_timeout_time and Time.now < response_timeout_time
|
103
|
+
handle_error("#{@interface ? @interface.name : ""}: Timeout waiting for response")
|
104
|
+
end
|
105
|
+
|
106
|
+
@response_packet = nil
|
107
|
+
end
|
108
|
+
return super(packet, data, extra)
|
109
|
+
end
|
110
|
+
|
111
|
+
def handle_error(msg)
|
112
|
+
Logger.error(msg)
|
113
|
+
raise msg if @raise_exceptions
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -391,6 +391,11 @@ module OpenC3
|
|
391
391
|
read_socket = socket if listen_read
|
392
392
|
stream = TcpipSocketStream.new(write_socket, read_socket, @write_timeout, @read_timeout)
|
393
393
|
|
394
|
+
# Pass down options to the stream
|
395
|
+
@options.each do |option_name, option_values|
|
396
|
+
stream.set_option(option_name, option_values)
|
397
|
+
end
|
398
|
+
|
394
399
|
interface = StreamInterface.new
|
395
400
|
interface.target_names = @target_names
|
396
401
|
interface.cmd_target_names = @cmd_target_names
|
data/lib/openc3/interfaces.rb
CHANGED
@@ -42,7 +42,7 @@ module OpenC3
|
|
42
42
|
autoload(:PreidentifiedProtocol, 'openc3/interfaces/protocols/preidentified_protocol.rb')
|
43
43
|
autoload(:TemplateProtocol, 'openc3/interfaces/protocols/template_protocol.rb')
|
44
44
|
autoload(:TerminatedProtocol, 'openc3/interfaces/protocols/terminated_protocol.rb')
|
45
|
-
|
45
|
+
autoload(:CmdResponseProtocol, 'openc3/interfaces/protocols/cmd_response_protocol.rb')
|
46
46
|
autoload(:CrcProtocol, 'openc3/interfaces/protocols/crc_protocol.rb')
|
47
47
|
autoload(:IgnorePacketProtocol, 'openc3/interfaces/protocols/ignore_packet_protocol.rb')
|
48
48
|
end
|
@@ -100,6 +100,7 @@ module OpenC3
|
|
100
100
|
packet.extra = extra
|
101
101
|
end
|
102
102
|
packet.buffer = msg_hash["buffer"]
|
103
|
+
packet.process # Run processors
|
103
104
|
packet.check_limits(System.limits_set) # Process all the limits and call the limits_change_callback (as necessary)
|
104
105
|
|
105
106
|
TelemetryDecomTopic.write_packet(packet, scope: @scope)
|
@@ -613,7 +613,16 @@ module OpenC3
|
|
613
613
|
|
614
614
|
def connect
|
615
615
|
@logger.info "#{@interface.name}: Connecting ..."
|
616
|
-
|
616
|
+
begin
|
617
|
+
@interface.connect
|
618
|
+
rescue Exception => error
|
619
|
+
begin
|
620
|
+
@interface.disconnect # Ensure disconnect is called at least once on a partial connect
|
621
|
+
rescue Exception
|
622
|
+
# We want to report any connect errors, not disconnect in this case
|
623
|
+
end
|
624
|
+
raise error
|
625
|
+
end
|
617
626
|
@interface.state = 'CONNECTED'
|
618
627
|
if @interface_or_router == 'INTERFACE'
|
619
628
|
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
@@ -52,12 +52,14 @@ module OpenC3
|
|
52
52
|
|
53
53
|
# Get the hash for packet in the CVT
|
54
54
|
# Note: Does not apply overrides
|
55
|
-
def self.get(target_name:, packet_name:, cache_timeout:
|
55
|
+
def self.get(target_name:, packet_name:, cache_timeout: nil, scope: $openc3_scope)
|
56
56
|
key = "#{scope}__tlm__#{target_name}"
|
57
57
|
tgt_pkt_key = key + "__#{packet_name}"
|
58
|
-
cache_time, hash = @@packet_cache[tgt_pkt_key]
|
59
58
|
now = Time.now
|
60
|
-
|
59
|
+
if cache_timeout
|
60
|
+
cache_time, hash = @@packet_cache[tgt_pkt_key]
|
61
|
+
return hash if hash and (now - cache_time) < cache_timeout
|
62
|
+
end
|
61
63
|
packet = Store.hget(key, packet_name)
|
62
64
|
raise "Packet '#{target_name} #{packet_name}' does not exist" unless packet
|
63
65
|
hash = JSON.parse(packet, :allow_nan => true, :create_additions => true)
|
@@ -67,7 +69,7 @@ module OpenC3
|
|
67
69
|
|
68
70
|
# Set an item in the current value table
|
69
71
|
def self.set_item(target_name, packet_name, item_name, value, type:, scope: $openc3_scope)
|
70
|
-
hash = get(target_name: target_name, packet_name: packet_name, cache_timeout:
|
72
|
+
hash = get(target_name: target_name, packet_name: packet_name, cache_timeout: nil, scope: scope)
|
71
73
|
case type
|
72
74
|
when :WITH_UNITS
|
73
75
|
hash["#{item_name}__U"] = value.to_s # WITH_UNITS should always be a string
|
@@ -89,10 +91,10 @@ module OpenC3
|
|
89
91
|
end
|
90
92
|
|
91
93
|
# Get an item from the current value table
|
92
|
-
def self.get_item(target_name, packet_name, item_name, type:, cache_timeout:
|
94
|
+
def self.get_item(target_name, packet_name, item_name, type:, cache_timeout: nil, scope: $openc3_scope)
|
93
95
|
result, types = self._handle_item_override(target_name, packet_name, item_name, type: type, cache_timeout: cache_timeout, scope: scope)
|
94
96
|
return result if result
|
95
|
-
hash = get(target_name: target_name, packet_name: packet_name, scope: scope)
|
97
|
+
hash = get(target_name: target_name, packet_name: packet_name, cache_timeout: cache_timeout, scope: scope)
|
96
98
|
hash.values_at(*types).each do |result|
|
97
99
|
if result
|
98
100
|
if type == :FORMATTED or type == :WITH_UNITS
|
@@ -109,7 +111,7 @@ module OpenC3
|
|
109
111
|
# @param items [Array<String>] Items to return. Must be formatted as TGT__PKT__ITEM__TYPE
|
110
112
|
# @param stale_time [Integer] Time in seconds from Time.now that value will be marked stale
|
111
113
|
# @return [Array] Array of values
|
112
|
-
def self.get_tlm_values(items, stale_time: 30, cache_timeout:
|
114
|
+
def self.get_tlm_values(items, stale_time: 30, cache_timeout: nil, scope: $openc3_scope)
|
113
115
|
now = Time.now
|
114
116
|
results = []
|
115
117
|
lookups = []
|
@@ -246,7 +248,7 @@ module OpenC3
|
|
246
248
|
end
|
247
249
|
end
|
248
250
|
|
249
|
-
def self.determine_latest_packet_for_item(target_name, item_name, cache_timeout:
|
251
|
+
def self.determine_latest_packet_for_item(target_name, item_name, cache_timeout: nil, scope: $openc3_scope)
|
250
252
|
item_map = TargetModel.get_item_to_packet_map(target_name, scope: scope)
|
251
253
|
packet_names = item_map[item_name]
|
252
254
|
raise "Item '#{target_name} LATEST #{item_name}' does not exist for scope: #{scope}" unless packet_names
|
@@ -293,10 +295,12 @@ module OpenC3
|
|
293
295
|
end
|
294
296
|
|
295
297
|
def self._get_overrides(now, tgt_pkt_key, overrides, target_name, packet_name, cache_timeout:, scope:)
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
298
|
+
if cache_timeout
|
299
|
+
cache_time, hash = @@override_cache[tgt_pkt_key]
|
300
|
+
if hash and (now - cache_time) < cache_timeout
|
301
|
+
overrides[tgt_pkt_key] = hash
|
302
|
+
return hash
|
303
|
+
end
|
300
304
|
end
|
301
305
|
override_data = Store.hget("#{scope}__override__#{target_name}", packet_name)
|
302
306
|
if override_data
|
@@ -39,11 +39,17 @@ module OpenC3
|
|
39
39
|
include Api
|
40
40
|
|
41
41
|
def self.names
|
42
|
-
|
42
|
+
if Dir.exist?("#{ENV['GEM_HOME']}/gems")
|
43
|
+
result = Pathname.new("#{ENV['GEM_HOME']}/gems").children.select { |c| c.directory? }.collect { |p| File.basename(p) + '.gem' }
|
44
|
+
else
|
45
|
+
result = []
|
46
|
+
end
|
43
47
|
return result.sort
|
44
48
|
end
|
45
49
|
|
46
50
|
def self.get(name)
|
51
|
+
path = "#{ENV['GEM_HOME']}/cosmoscache/#{name}"
|
52
|
+
return path if File.exist?(path)
|
47
53
|
path = "#{ENV['GEM_HOME']}/cache/#{name}"
|
48
54
|
return path if File.exist?(path)
|
49
55
|
raise "Gem #{name} not found"
|
@@ -52,8 +58,9 @@ module OpenC3
|
|
52
58
|
def self.put(gem_file_path, gem_install: true, scope:)
|
53
59
|
if File.file?(gem_file_path)
|
54
60
|
gem_filename = File.basename(gem_file_path)
|
55
|
-
|
56
|
-
FileUtils.
|
61
|
+
# Put into cosmoscache folder that we control
|
62
|
+
FileUtils.mkdir_p("#{ENV['GEM_HOME']}/cosmoscache") unless Dir.exist?("#{ENV['GEM_HOME']}/cosmoscache")
|
63
|
+
FileUtils.cp(gem_file_path, "#{ENV['GEM_HOME']}/cosmoscache/#{File.basename(gem_file_path)}")
|
57
64
|
if gem_install
|
58
65
|
Logger.info "Installing gem: #{gem_filename}"
|
59
66
|
result = OpenC3::ProcessManager.instance.spawn(["ruby", "/openc3/bin/openc3cli", "geminstall", gem_filename, scope], "package_install", gem_filename, Time.now + 3600.0, scope: scope)
|
@@ -118,5 +125,15 @@ module OpenC3
|
|
118
125
|
version = File.basename(split_name[-1], '.gem')
|
119
126
|
return gem_name, version
|
120
127
|
end
|
128
|
+
|
129
|
+
def self.destroy_all_other_versions(name)
|
130
|
+
keep_gem_name, keep_gem_version = GemModel.extract_name_and_version(name)
|
131
|
+
GemModel.names.each do |gem_full_name|
|
132
|
+
gem_name, gem_version = GemModel.extract_name_and_version(gem_full_name)
|
133
|
+
if gem_name == keep_gem_name and gem_version != keep_gem_version
|
134
|
+
GemModel.destroy(gem_full_name)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
121
138
|
end
|
122
139
|
end
|
@@ -185,7 +185,7 @@ module OpenC3
|
|
185
185
|
@topics << parameters[0]
|
186
186
|
when 'TARGET_NAME'
|
187
187
|
parser.verify_num_parameters(1, 1, "#{keyword} <Target Name>")
|
188
|
-
@target_names << parameters[0]
|
188
|
+
@target_names << parameters[0].upcase
|
189
189
|
when 'CMD'
|
190
190
|
parser.verify_num_parameters(1, nil, "#{keyword} <Args>")
|
191
191
|
@cmd = parameters.dup
|
@@ -158,6 +158,11 @@ module OpenC3
|
|
158
158
|
gem_file_path = OpenC3::GemModel.get(gem_name)
|
159
159
|
end
|
160
160
|
|
161
|
+
# Attempt to remove all older versions of this same plugin before install to prevent version conflicts
|
162
|
+
# Especially on downgrades
|
163
|
+
# Leave the same version if it already exists
|
164
|
+
OpenC3::GemModel.destroy_all_other_versions(File.basename(gem_file_path))
|
165
|
+
|
161
166
|
# Actually install the gem now (slow)
|
162
167
|
OpenC3::GemModel.install(gem_file_path, scope: scope) unless validate_only
|
163
168
|
|
@@ -356,7 +361,6 @@ module OpenC3
|
|
356
361
|
# Reinstall
|
357
362
|
def restore
|
358
363
|
plugin_hash = self.as_json(:allow_nan => true)
|
359
|
-
plugin_hash['name'] = plugin_hash['name'].split("__")[0]
|
360
364
|
OpenC3::PluginModel.install_phase2(plugin_hash, scope: @scope)
|
361
365
|
@destroyed = false
|
362
366
|
end
|
@@ -742,7 +742,7 @@ module OpenC3
|
|
742
742
|
end
|
743
743
|
end
|
744
744
|
|
745
|
-
def
|
745
|
+
def update_target_model(system)
|
746
746
|
target = system.targets[@name]
|
747
747
|
|
748
748
|
# Add in the information from the target and update
|
@@ -754,10 +754,11 @@ module OpenC3
|
|
754
754
|
@tlm_unique_id_mode = target.tlm_unique_id_mode
|
755
755
|
@limits_groups = system.limits.groups.keys
|
756
756
|
update()
|
757
|
+
end
|
757
758
|
|
758
|
-
|
759
|
-
|
760
|
-
Store.del("#{@scope}__openc3tlm__#{target_name}")
|
759
|
+
def update_store_telemetry(packet_hash, clear_old: true)
|
760
|
+
packet_hash.each do |target_name, packets|
|
761
|
+
Store.del("#{@scope}__openc3tlm__#{target_name}") if clear_old
|
761
762
|
packets.each do |packet_name, packet|
|
762
763
|
Logger.info "Configuring tlm packet: #{target_name} #{packet_name}"
|
763
764
|
begin
|
@@ -773,8 +774,11 @@ module OpenC3
|
|
773
774
|
CvtModel.set(json_hash, target_name: packet.target_name, packet_name: packet.packet_name, scope: @scope)
|
774
775
|
end
|
775
776
|
end
|
776
|
-
|
777
|
-
|
777
|
+
end
|
778
|
+
|
779
|
+
def update_store_commands(packet_hash, clear_old: true)
|
780
|
+
packet_hash.each do |target_name, packets|
|
781
|
+
Store.del("#{@scope}__openc3cmd__#{target_name}") if clear_old
|
778
782
|
packets.each do |packet_name, packet|
|
779
783
|
Logger.info "Configuring cmd packet: #{target_name} #{packet_name}"
|
780
784
|
begin
|
@@ -785,7 +789,9 @@ module OpenC3
|
|
785
789
|
end
|
786
790
|
end
|
787
791
|
end
|
788
|
-
|
792
|
+
end
|
793
|
+
|
794
|
+
def update_store_limits_groups(system)
|
789
795
|
system.limits.groups.each do |group, items|
|
790
796
|
begin
|
791
797
|
Store.hset("#{@scope}__limits_groups", group, JSON.generate(items))
|
@@ -794,23 +800,77 @@ module OpenC3
|
|
794
800
|
raise err
|
795
801
|
end
|
796
802
|
end
|
797
|
-
|
803
|
+
end
|
804
|
+
|
805
|
+
def update_store_limits_sets(system)
|
798
806
|
sets = Store.hgetall("#{@scope}__limits_sets")
|
799
807
|
sets ||= {}
|
800
808
|
system.limits.sets.each do |set|
|
801
809
|
sets[set.to_s] = "false" unless sets.key?(set.to_s)
|
802
810
|
end
|
803
811
|
Store.hmset("#{@scope}__limits_sets", *sets)
|
812
|
+
end
|
804
813
|
|
814
|
+
def update_store_item_map
|
805
815
|
# Create item_map
|
806
816
|
item_map_key = "#{@scope}__#{@name}__item_to_packet_map"
|
807
817
|
item_map = self.class.build_item_to_packet_map(@name, scope: @scope)
|
808
818
|
Store.set(item_map_key, JSON.generate(item_map, :allow_nan => true))
|
809
819
|
@@item_map_cache[@name] = [Time.now, item_map]
|
820
|
+
end
|
810
821
|
|
822
|
+
def update_store(system, clear_old: true)
|
823
|
+
update_target_model(system)
|
824
|
+
update_store_telemetry(system.telemetry.all, clear_old: clear_old)
|
825
|
+
update_store_commands(system.commands.all, clear_old: clear_old)
|
826
|
+
update_store_limits_groups(system)
|
827
|
+
update_store_limits_sets(system)
|
828
|
+
update_store_item_map()
|
811
829
|
return system
|
812
830
|
end
|
813
831
|
|
832
|
+
def dynamic_update(packets, cmd_or_tlm = :TELEMETRY, filename = "dynamic_tlm.txt")
|
833
|
+
# Build hash of targets/packets
|
834
|
+
packet_hash = {}
|
835
|
+
packets.each do |packet|
|
836
|
+
target_name = packet.target_name.upcase
|
837
|
+
packet_hash[target_name] ||= {}
|
838
|
+
packet_name = packet.packet_name.upcase
|
839
|
+
packet_hash[target_name][packet_name] = packet
|
840
|
+
end
|
841
|
+
|
842
|
+
# Update Redis
|
843
|
+
if cmd_or_tlm == :TELEMETRY
|
844
|
+
update_store_telemetry(packet_hash, clear_old: false)
|
845
|
+
update_store_item_map()
|
846
|
+
else
|
847
|
+
update_store_commands(packet_hash, clear_old: false)
|
848
|
+
end
|
849
|
+
|
850
|
+
# Build dynamic file for cmd_tlm
|
851
|
+
configs = {}
|
852
|
+
packets.each do |packet|
|
853
|
+
target_name = packet.target_name.upcase
|
854
|
+
configs[target_name] ||= ""
|
855
|
+
config = configs[target_name]
|
856
|
+
config << packet.to_config(cmd_or_tlm)
|
857
|
+
config << "\n"
|
858
|
+
end
|
859
|
+
configs.each do |target_name, config|
|
860
|
+
begin
|
861
|
+
bucket_key = "#{@scope}/targets_modified/#{target_name}/cmd_tlm/#{filename}"
|
862
|
+
client = Bucket.getClient()
|
863
|
+
client.put_object(
|
864
|
+
# Use targets_modified to save modifications
|
865
|
+
# This keeps the original target clean (read-only)
|
866
|
+
bucket: ENV['OPENC3_CONFIG_BUCKET'],
|
867
|
+
key: bucket_key,
|
868
|
+
body: config
|
869
|
+
)
|
870
|
+
end
|
871
|
+
end
|
872
|
+
end
|
873
|
+
|
814
874
|
def deploy_commmandlog_microservice(gem_path, variables, topics, instance = nil, parent = nil)
|
815
875
|
microservice_name = "#{@scope}__COMMANDLOG#{instance}__#{@name}"
|
816
876
|
microservice = MicroserviceModel.new(
|
@@ -990,6 +1050,7 @@ module OpenC3
|
|
990
1050
|
cmd: ["ruby", "multi_microservice.rb", *@children],
|
991
1051
|
work_dir: '/openc3/lib/openc3/microservices',
|
992
1052
|
plugin: @plugin,
|
1053
|
+
needs_dependencies: @needs_dependencies,
|
993
1054
|
scope: @scope
|
994
1055
|
)
|
995
1056
|
microservice.create
|