openc3 5.13.0 → 5.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of openc3 might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/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 +5 -2
- data/lib/openc3/microservices/interface_microservice.rb +10 -1
- data/lib/openc3/microservices/log_microservice.rb +6 -1
- data/lib/openc3/microservices/microservice.rb +28 -0
- 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 +6 -2
- data/lib/openc3/models/plugin_model.rb +6 -2
- data/lib/openc3/models/target_model.rb +105 -12
- data/lib/openc3/operators/microservice_operator.rb +23 -21
- data/lib/openc3/packets/commands.rb +4 -0
- data/lib/openc3/packets/packet.rb +92 -4
- data/lib/openc3/packets/packet_config.rb +62 -8
- data/lib/openc3/packets/telemetry.rb +4 -0
- 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 +43 -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 +6 -6
- 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
|
@@ -45,6 +45,7 @@ module OpenC3
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def run
|
48
|
+
setup_microservice_topic()
|
48
49
|
while true
|
49
50
|
break if @cancel_thread
|
50
51
|
|
@@ -52,8 +53,9 @@ module OpenC3
|
|
52
53
|
OpenC3.in_span("read_topics") do
|
53
54
|
Topic.read_topics(@topics) do |topic, msg_id, msg_hash, redis|
|
54
55
|
break if @cancel_thread
|
55
|
-
|
56
|
-
|
56
|
+
if topic == @microservice_topic
|
57
|
+
microservice_cmd(topic, msg_id, msg_hash, redis)
|
58
|
+
elsif topic =~ /__DECOMINTERFACE/
|
57
59
|
if msg_hash.key?('inject_tlm')
|
58
60
|
handle_inject_tlm(msg_hash['inject_tlm'])
|
59
61
|
next
|
@@ -100,6 +102,7 @@ module OpenC3
|
|
100
102
|
packet.extra = extra
|
101
103
|
end
|
102
104
|
packet.buffer = msg_hash["buffer"]
|
105
|
+
packet.process # Run processors
|
103
106
|
packet.check_limits(System.limits_set) # Process all the limits and call the limits_change_callback (as necessary)
|
104
107
|
|
105
108
|
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)
|
@@ -62,12 +62,17 @@ module OpenC3
|
|
62
62
|
|
63
63
|
def run
|
64
64
|
setup_plws()
|
65
|
+
setup_microservice_topic()
|
65
66
|
while true
|
66
67
|
break if @cancel_thread
|
67
68
|
|
68
69
|
Topic.read_topics(@topics) do |topic, msg_id, msg_hash, redis|
|
69
70
|
break if @cancel_thread
|
70
|
-
|
71
|
+
if topic == @microservice_topic
|
72
|
+
microservice_cmd(topic, msg_id, msg_hash, redis)
|
73
|
+
else
|
74
|
+
log_data(topic, msg_id, msg_hash, redis)
|
75
|
+
end
|
71
76
|
@count += 1
|
72
77
|
@metric.set(name: 'log_total', value: @count, type: 'counter')
|
73
78
|
end
|
@@ -116,6 +116,7 @@ module OpenC3
|
|
116
116
|
end
|
117
117
|
@logger.info("Microservice initialized with config:\n#{@config}")
|
118
118
|
@topics ||= []
|
119
|
+
@microservice_topic = "MICROSERVICE__#{@name}"
|
119
120
|
|
120
121
|
# Get configuration for any targets
|
121
122
|
@target_names = @config["target_names"]
|
@@ -210,5 +211,32 @@ module OpenC3
|
|
210
211
|
@logger.info("Shutting down microservice complete: #{@name}")
|
211
212
|
@shutdown_complete = true
|
212
213
|
end
|
214
|
+
|
215
|
+
def setup_microservice_topic
|
216
|
+
@topics.append(@microservice_topic)
|
217
|
+
Thread.current[:topic_offsets] ||= {}
|
218
|
+
topic_offsets = Thread.current[:topic_offsets]
|
219
|
+
topic_offsets[@microservice_topic] = "0-0" # Always get all available
|
220
|
+
end
|
221
|
+
|
222
|
+
# Returns if the command was handled
|
223
|
+
def microservice_cmd(topic, msg_id, msg_hash, redis)
|
224
|
+
command = msg_hash['command']
|
225
|
+
case command
|
226
|
+
when 'ADD_TOPICS'
|
227
|
+
topics = JSON.parse(msg_hash['topics'])
|
228
|
+
if topics and Array === topics
|
229
|
+
topics.each do |new_topic|
|
230
|
+
@topics << new_topic unless @topics.include?(new_topic)
|
231
|
+
end
|
232
|
+
else
|
233
|
+
raise "Invalid topics given to microservice_cmd: #{topics}"
|
234
|
+
end
|
235
|
+
Topic.trim_topic(topic, msg_id)
|
236
|
+
return true
|
237
|
+
end
|
238
|
+
Topic.trim_topic(topic, msg_id)
|
239
|
+
return false
|
240
|
+
end
|
213
241
|
end
|
214
242
|
end
|
@@ -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
|
@@ -43,6 +43,7 @@ module OpenC3
|
|
43
43
|
attr_accessor :secrets
|
44
44
|
attr_accessor :prefix
|
45
45
|
attr_accessor :disable_erb
|
46
|
+
attr_accessor :ignore_changes
|
46
47
|
|
47
48
|
# NOTE: The following three class methods are used by the ModelController
|
48
49
|
# and are reimplemented to enable various Model class methods to work
|
@@ -103,6 +104,7 @@ module OpenC3
|
|
103
104
|
secrets: [],
|
104
105
|
prefix: nil,
|
105
106
|
disable_erb: nil,
|
107
|
+
ignore_changes: nil,
|
106
108
|
scope:
|
107
109
|
)
|
108
110
|
parts = name.split("__")
|
@@ -128,6 +130,7 @@ module OpenC3
|
|
128
130
|
@secrets = secrets
|
129
131
|
@prefix = prefix
|
130
132
|
@disable_erb = disable_erb
|
133
|
+
@ignore_changes = ignore_changes
|
131
134
|
@bucket = Bucket.getClient()
|
132
135
|
end
|
133
136
|
|
@@ -149,7 +152,8 @@ module OpenC3
|
|
149
152
|
'needs_dependencies' => @needs_dependencies,
|
150
153
|
'secrets' => @secrets.as_json(*a),
|
151
154
|
'prefix' => @prefix,
|
152
|
-
'disable_erb' => @disable_erb
|
155
|
+
'disable_erb' => @disable_erb,
|
156
|
+
'ignore_changes' => @ignore_changes
|
153
157
|
}
|
154
158
|
end
|
155
159
|
|
@@ -185,7 +189,7 @@ module OpenC3
|
|
185
189
|
@topics << parameters[0]
|
186
190
|
when 'TARGET_NAME'
|
187
191
|
parser.verify_num_parameters(1, 1, "#{keyword} <Target Name>")
|
188
|
-
@target_names << parameters[0]
|
192
|
+
@target_names << parameters[0].upcase
|
189
193
|
when 'CMD'
|
190
194
|
parser.verify_num_parameters(1, nil, "#{keyword} <Args>")
|
191
195
|
@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
|
|
@@ -337,7 +342,7 @@ module OpenC3
|
|
337
342
|
raise message
|
338
343
|
end
|
339
344
|
rescue Exception => error
|
340
|
-
Logger.error("Error undeploying plugin model #{@name} in scope #{@scope} due to: #{error}")
|
345
|
+
Logger.error("Error undeploying plugin model #{@name} in scope #{@scope} due to: #{error.formatted}")
|
341
346
|
ensure
|
342
347
|
# Double check everything is gone
|
343
348
|
found = []
|
@@ -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
|