openc3 5.9.0 → 5.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/openc3/api/limits_api.rb +4 -20
- data/lib/openc3/api/target_api.rb +11 -8
- data/lib/openc3/api/tlm_api.rb +29 -38
- data/lib/openc3/models/auth_model.rb +18 -6
- data/lib/openc3/models/cvt_model.rb +113 -50
- data/lib/openc3/models/target_model.rb +43 -1
- data/lib/openc3/utilities/local_mode.rb +1 -1
- data/lib/openc3/version.rb +5 -5
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_svelte/src/services/openc3-api.js +174 -174
- data/templates/tool_vue/package.json +2 -2
- data/templates/widget/package.json +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c24a28732bfd8c275b65639cd566b4823d78b70b43781bf14a82e114397e7677
|
4
|
+
data.tar.gz: a8567e57ec8008d505e7f6a30cd3462e435988a46729908fbc17775f2b92e976
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc287a9895e3ae60c6332389d0b7926bb84aa04d7d65e51c936ba65f66640b179b0baefdcec232d7775a70f2e95d88557faf5e960663c4c28840428e7cb52904
|
7
|
+
data.tar.gz: 578c1f1fe45512344390492e9aa15d7af851bb81e608fbc874189dcc73bc998c472e62d449c114fb300fc58bb0d9cc269cc3dfbcbb31aaaf76c9003abd63c8e7
|
@@ -373,26 +373,10 @@ module OpenC3
|
|
373
373
|
# @param item_name [String] item name
|
374
374
|
# @param scope [String] scope
|
375
375
|
# @return Hash The requested item based on the packet name
|
376
|
-
def _get_item(target_name, packet_name, item_name, scope:)
|
377
|
-
|
378
|
-
if packet_name == 'LATEST'
|
379
|
-
|
380
|
-
TargetModel.packets(target_name, scope: scope).each do |packet|
|
381
|
-
item = packet['items'].find { |item| item['name'] == item_name }
|
382
|
-
if item
|
383
|
-
hash = CvtModel.get(target_name: target_name, packet_name: packet['packet_name'], scope: scope)
|
384
|
-
if hash['PACKET_TIMESECONDS'] && hash['PACKET_TIMESECONDS'] > latest
|
385
|
-
latest = hash['PACKET_TIMESECONDS']
|
386
|
-
requested_item = item
|
387
|
-
end
|
388
|
-
end
|
389
|
-
end
|
390
|
-
raise "Item '#{target_name} LATEST #{item_name}' does not exist" if latest == -1
|
391
|
-
else
|
392
|
-
# Determine if this item exists, it will raise appropriate errors if not
|
393
|
-
requested_item = TargetModel.packet_item(target_name, packet_name, item_name, scope: scope)
|
394
|
-
end
|
395
|
-
return requested_item
|
376
|
+
def _get_item(target_name, packet_name, item_name, cache_timeout: 0.1, scope:)
|
377
|
+
# Determine if this item exists, it will raise appropriate errors if not
|
378
|
+
packet_name = CvtModel.determine_latest_packet_for_item(target_name, item_name, cache_timeout: cache_timeout, scope: $openc3_scope) if packet_name == 'LATEST'
|
379
|
+
return TargetModel.packet_item(target_name, packet_name, item_name, scope: scope)
|
396
380
|
end
|
397
381
|
end
|
398
382
|
end
|
@@ -26,19 +26,22 @@ module OpenC3
|
|
26
26
|
module Api
|
27
27
|
WHITELIST ||= []
|
28
28
|
WHITELIST.concat([
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
'get_target_names',
|
30
|
+
'get_target_list', # DEPRECATED
|
31
|
+
'get_target',
|
32
|
+
'get_target_interfaces',
|
33
|
+
'get_all_target_info', # DEPRECATED
|
34
|
+
])
|
34
35
|
|
35
36
|
# Returns the list of all target names
|
36
37
|
#
|
37
38
|
# @return [Array<String>] All target names
|
38
|
-
def
|
39
|
+
def get_target_names(scope: $openc3_scope, token: $openc3_token)
|
39
40
|
authorize(permission: 'tlm', scope: scope, token: token)
|
40
41
|
TargetModel.names(scope: scope)
|
41
42
|
end
|
43
|
+
# get_target_list is DEPRECATED
|
44
|
+
alias get_target_list get_target_names
|
42
45
|
|
43
46
|
# Gets the full target hash
|
44
47
|
#
|
@@ -57,7 +60,7 @@ module OpenC3
|
|
57
60
|
authorize(permission: 'system', scope: scope, token: token)
|
58
61
|
info = []
|
59
62
|
interfaces = InterfaceModel.all(scope: scope)
|
60
|
-
|
63
|
+
get_target_names(scope: scope, token: token).each do |target_name|
|
61
64
|
interface_names = []
|
62
65
|
interfaces.each do |name, interface|
|
63
66
|
if interface['target_names'].include? target_name
|
@@ -76,7 +79,7 @@ module OpenC3
|
|
76
79
|
def get_all_target_info(scope: $openc3_scope, token: $openc3_token)
|
77
80
|
authorize(permission: 'system', scope: scope, token: token)
|
78
81
|
info = []
|
79
|
-
|
82
|
+
get_target_names(scope: scope, token: token).each do |target_name|
|
80
83
|
cmd_cnt = 0
|
81
84
|
packets = TargetModel.packets(target_name, type: :CMD, scope: scope)
|
82
85
|
packets.each do |packet|
|
data/lib/openc3/api/tlm_api.rb
CHANGED
@@ -66,30 +66,30 @@ module OpenC3
|
|
66
66
|
# @param args [String|Array<String>] See the description for calling style
|
67
67
|
# @param type [Symbol] Telemetry type, :RAW, :CONVERTED (default), :FORMATTED, or :WITH_UNITS
|
68
68
|
# @return [Object] The telemetry value formatted as requested
|
69
|
-
def tlm(*args, type: :CONVERTED, scope: $openc3_scope, token: $openc3_token)
|
70
|
-
target_name, packet_name, item_name = tlm_process_args(args, 'tlm', scope: scope)
|
69
|
+
def tlm(*args, type: :CONVERTED, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
|
70
|
+
target_name, packet_name, item_name = tlm_process_args(args, 'tlm', cache_timeout: cache_timeout, scope: scope)
|
71
71
|
authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
72
|
-
CvtModel.get_item(target_name, packet_name, item_name, type: type.intern, scope: scope)
|
72
|
+
CvtModel.get_item(target_name, packet_name, item_name, type: type.intern, cache_timeout: cache_timeout, scope: scope)
|
73
73
|
end
|
74
74
|
|
75
75
|
# @deprecated Use tlm with type: :RAW
|
76
|
-
def tlm_raw(*args, scope: $openc3_scope, token: $openc3_token)
|
77
|
-
tlm(*args, type: :RAW, scope: scope, token: token)
|
76
|
+
def tlm_raw(*args, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
|
77
|
+
tlm(*args, type: :RAW, cache_timeout: cache_timeout, scope: scope, token: token)
|
78
78
|
end
|
79
79
|
|
80
80
|
# @deprecated Use tlm with type: :FORMATTED
|
81
|
-
def tlm_formatted(*args, scope: $openc3_scope, token: $openc3_token)
|
82
|
-
tlm(*args, type: :FORMATTED, scope: scope, token: token)
|
81
|
+
def tlm_formatted(*args, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
|
82
|
+
tlm(*args, type: :FORMATTED, cache_timeout: cache_timeout, scope: scope, token: token)
|
83
83
|
end
|
84
84
|
|
85
85
|
# @deprecated Use tlm with type: :WITH_UNITS
|
86
|
-
def tlm_with_units(*args, scope: $openc3_scope, token: $openc3_token)
|
87
|
-
tlm(*args, type: :WITH_UNITS, scope: scope, token: token)
|
86
|
+
def tlm_with_units(*args, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
|
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, scope: $openc3_scope, token: $openc3_token)
|
92
|
-
tlm(*args[0..-2], type: args[-1].intern, scope: scope, token: token)
|
91
|
+
def tlm_variable(*args, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
|
92
|
+
tlm(*args[0..-2], type: args[-1].intern, cache_timeout: cache_timeout, scope: scope, token: token)
|
93
93
|
end
|
94
94
|
|
95
95
|
# Set a telemetry item in the current value table.
|
@@ -227,7 +227,7 @@ module OpenC3
|
|
227
227
|
# @return [Array<String, Object, Symbol|nil>] Returns an Array consisting
|
228
228
|
# of [item name, item value, item limits state] where the item limits
|
229
229
|
# state can be one of {OpenC3::Limits::LIMITS_STATES}
|
230
|
-
def get_tlm_packet(target_name, packet_name, stale_time: 30, type: :CONVERTED, scope: $openc3_scope, token: $openc3_token)
|
230
|
+
def get_tlm_packet(target_name, packet_name, stale_time: 30, type: :CONVERTED, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
|
231
231
|
target_name = target_name.upcase
|
232
232
|
packet_name = packet_name.upcase
|
233
233
|
authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
@@ -235,8 +235,8 @@ module OpenC3
|
|
235
235
|
t = _validate_tlm_type(type)
|
236
236
|
raise ArgumentError, "Unknown type '#{type}' for #{target_name} #{packet_name}" if t.nil?
|
237
237
|
items = packet['items'].map { | item | item['name'].upcase }
|
238
|
-
cvt_items = items.map { | item |
|
239
|
-
current_values = CvtModel.get_tlm_values(cvt_items, stale_time: stale_time, scope: scope)
|
238
|
+
cvt_items = items.map { | item | [target_name, packet_name, item, type] }
|
239
|
+
current_values = CvtModel.get_tlm_values(cvt_items, stale_time: stale_time, cache_timeout: cache_timeout, scope: scope)
|
240
240
|
items.zip(current_values).map { | item , values | [item, values[0], values[1]]}
|
241
241
|
end
|
242
242
|
|
@@ -250,25 +250,26 @@ module OpenC3
|
|
250
250
|
# @return [Array<Object, Symbol>]
|
251
251
|
# Array consisting of the item value and limits state
|
252
252
|
# given as symbols such as :RED, :YELLOW, :STALE
|
253
|
-
def get_tlm_values(items, stale_time: 30, scope: $openc3_scope, token: $openc3_token)
|
253
|
+
def get_tlm_values(items, stale_time: 30, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
|
254
254
|
if !items.is_a?(Array) || !items[0].is_a?(String)
|
255
255
|
raise ArgumentError, "items must be array of strings: ['TGT__PKT__ITEM__TYPE', ...]"
|
256
256
|
end
|
257
|
+
packets = []
|
258
|
+
cvt_items = []
|
257
259
|
items.each_with_index do |item, index|
|
258
|
-
|
260
|
+
item_upcase = item.to_s.upcase
|
261
|
+
target_name, packet_name, item_name, value_type = item_upcase.split('__')
|
259
262
|
raise ArgumentError, "items must be formatted as TGT__PKT__ITEM__TYPE" if target_name.nil? || packet_name.nil? || item_name.nil? || value_type.nil?
|
260
|
-
|
261
|
-
packet_name = packet_name.upcase
|
262
|
-
item_name = item_name.upcase
|
263
|
-
value_type = value_type.upcase
|
264
|
-
if packet_name == 'LATEST'
|
265
|
-
_, packet_name, _ = tlm_process_args([target_name, packet_name, item_name], 'get_tlm_values', scope: scope) # Figure out which packet is LATEST
|
266
|
-
end
|
263
|
+
packet_name = CvtModel.determine_latest_packet_for_item(target_name, item_name, cache_timeout: cache_timeout, scope: scope) if packet_name == 'LATEST'
|
267
264
|
# Change packet_name in case of LATEST and ensure upcase
|
268
|
-
|
265
|
+
cvt_items[index] = [target_name, packet_name, item_name, value_type]
|
266
|
+
packets << [target_name, packet_name]
|
267
|
+
end
|
268
|
+
packets.uniq!
|
269
|
+
packets.each do |target_name, packet_name|
|
269
270
|
authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
|
270
271
|
end
|
271
|
-
CvtModel.get_tlm_values(
|
272
|
+
CvtModel.get_tlm_values(cvt_items, stale_time: stale_time, cache_timeout: cache_timeout, scope: scope)
|
272
273
|
end
|
273
274
|
|
274
275
|
# Returns an array of all the telemetry packet hashes
|
@@ -429,7 +430,7 @@ module OpenC3
|
|
429
430
|
return nil
|
430
431
|
end
|
431
432
|
|
432
|
-
def tlm_process_args(args, method_name, scope: $openc3_scope, token: $openc3_token)
|
433
|
+
def tlm_process_args(args, method_name, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
|
433
434
|
case args.length
|
434
435
|
when 1
|
435
436
|
target_name, packet_name, item_name = extract_fields_from_tlm_text(args[0])
|
@@ -444,19 +445,9 @@ module OpenC3
|
|
444
445
|
target_name = target_name.upcase
|
445
446
|
packet_name = packet_name.upcase
|
446
447
|
item_name = item_name.upcase
|
448
|
+
|
447
449
|
if packet_name == 'LATEST'
|
448
|
-
|
449
|
-
TargetModel.packets(target_name, scope: scope).each do |packet|
|
450
|
-
item = packet['items'].find { |item| item['name'] == item_name }
|
451
|
-
if item
|
452
|
-
hash = CvtModel.get(target_name: target_name, packet_name: packet['packet_name'], scope: scope)
|
453
|
-
if hash['PACKET_TIMESECONDS'] && hash['PACKET_TIMESECONDS'] > latest
|
454
|
-
latest = hash['PACKET_TIMESECONDS']
|
455
|
-
packet_name = packet['packet_name']
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|
459
|
-
raise "Item '#{target_name} LATEST #{item_name}' does not exist" if latest == -1
|
450
|
+
packet_name = CvtModel.determine_latest_packet_for_item(target_name, item_name, cache_timeout: cache_timeout, scope: scope)
|
460
451
|
else
|
461
452
|
# Determine if this item exists, it will raise appropriate errors if not
|
462
453
|
TargetModel.packet_item(target_name, packet_name, item_name, scope: scope)
|
@@ -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 'digest'
|
@@ -28,6 +28,12 @@ module OpenC3
|
|
28
28
|
PRIMARY_KEY = 'OPENC3__TOKEN'
|
29
29
|
SERVICE_KEY = 'OPENC3__SERVICE__TOKEN'
|
30
30
|
|
31
|
+
TOKEN_CACHE_TIMEOUT = 5
|
32
|
+
@@token_cache = nil
|
33
|
+
@@token_cache_time = nil
|
34
|
+
@@service_token_cache = nil
|
35
|
+
@@service_token_cache_time = nil
|
36
|
+
|
31
37
|
def self.is_set?(key = PRIMARY_KEY)
|
32
38
|
Store.exists(key) == 1
|
33
39
|
end
|
@@ -36,15 +42,21 @@ module OpenC3
|
|
36
42
|
return false if token.nil? or token.empty?
|
37
43
|
|
38
44
|
token_hash = hash(token)
|
39
|
-
return true if
|
45
|
+
return true if @@token_cache and (Time.now - @@token_cache_time) < TOKEN_CACHE_TIMEOUT and @@token_cache == token_hash
|
46
|
+
return true if @@service_token_cache and (Time.now - @@service_token_cache_time) < TOKEN_CACHE_TIMEOUT and @@service_token_cache == token_hash and permission != 'admin'
|
47
|
+
|
48
|
+
@@token_cache = Store.get(PRIMARY_KEY)
|
49
|
+
@@token_cache_time = Time.now
|
50
|
+
return true if @@token_cache == token_hash
|
40
51
|
|
41
|
-
|
42
|
-
|
52
|
+
@@service_token_cache = Store.get(SERVICE_KEY)
|
53
|
+
@@service_token_cache_time = @@token_cache_time
|
54
|
+
if ENV['OPENC3_SERVICE_PASSWORD'] and hash(ENV['OPENC3_SERVICE_PASSWORD']) != @@service_token_cache
|
43
55
|
set_hash = hash(ENV['OPENC3_SERVICE_PASSWORD'])
|
44
56
|
OpenC3::Store.set(SERVICE_KEY, set_hash)
|
45
|
-
|
57
|
+
@@service_token_cache = set_hash
|
46
58
|
end
|
47
|
-
return true if
|
59
|
+
return true if @@service_token_cache == token_hash and permission != 'admin'
|
48
60
|
return false
|
49
61
|
end
|
50
62
|
|
@@ -25,6 +25,9 @@ require 'openc3/models/target_model'
|
|
25
25
|
|
26
26
|
module OpenC3
|
27
27
|
class CvtModel
|
28
|
+
@@packet_cache = {}
|
29
|
+
@@override_cache = {}
|
30
|
+
|
28
31
|
VALUE_TYPES = [:RAW, :CONVERTED, :FORMATTED, :WITH_UNITS]
|
29
32
|
def self.build_json_from_packet(packet)
|
30
33
|
packet.decom
|
@@ -32,24 +35,39 @@ module OpenC3
|
|
32
35
|
|
33
36
|
# Delete the current value table for a target
|
34
37
|
def self.del(target_name:, packet_name:, scope: $openc3_scope)
|
35
|
-
|
38
|
+
key = "#{scope}__tlm__#{target_name}"
|
39
|
+
tgt_pkt_key = key + "__#{packet_name}"
|
40
|
+
@@packet_cache[tgt_pkt_key] = nil
|
41
|
+
Store.hdel(key, packet_name)
|
36
42
|
end
|
37
43
|
|
38
44
|
# Set the current value table for a target, packet
|
39
45
|
def self.set(hash, target_name:, packet_name:, scope: $openc3_scope)
|
40
|
-
|
46
|
+
packet_json = JSON.generate(hash.as_json(:allow_nan => true))
|
47
|
+
key = "#{scope}__tlm__#{target_name}"
|
48
|
+
tgt_pkt_key = key + "__#{packet_name}"
|
49
|
+
@@packet_cache[tgt_pkt_key] = [Time.now, hash]
|
50
|
+
Store.hset(key, packet_name, packet_json)
|
41
51
|
end
|
42
52
|
|
43
53
|
# Get the hash for packet in the CVT
|
44
|
-
|
45
|
-
|
54
|
+
# Note: Does not apply overrides
|
55
|
+
def self.get(target_name:, packet_name:, cache_timeout: 0.1, scope: $openc3_scope)
|
56
|
+
key = "#{scope}__tlm__#{target_name}"
|
57
|
+
tgt_pkt_key = key + "__#{packet_name}"
|
58
|
+
cache_time, hash = @@packet_cache[tgt_pkt_key]
|
59
|
+
now = Time.now
|
60
|
+
return hash if hash and (now - cache_time) < cache_timeout
|
61
|
+
packet = Store.hget(key, packet_name)
|
46
62
|
raise "Packet '#{target_name} #{packet_name}' does not exist" unless packet
|
47
|
-
JSON.parse(packet, :allow_nan => true, :create_additions => true)
|
63
|
+
hash = JSON.parse(packet, :allow_nan => true, :create_additions => true)
|
64
|
+
@@packet_cache[tgt_pkt_key] = [now, hash]
|
65
|
+
hash
|
48
66
|
end
|
49
67
|
|
50
68
|
# Set an item in the current value table
|
51
69
|
def self.set_item(target_name, packet_name, item_name, value, type:, scope: $openc3_scope)
|
52
|
-
hash = get(target_name: target_name, packet_name: packet_name, scope: scope)
|
70
|
+
hash = get(target_name: target_name, packet_name: packet_name, cache_timeout: 0.0, scope: scope)
|
53
71
|
case type
|
54
72
|
when :WITH_UNITS
|
55
73
|
hash["#{item_name}__U"] = value.to_s # WITH_UNITS should always be a string
|
@@ -67,33 +85,13 @@ module OpenC3
|
|
67
85
|
else
|
68
86
|
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
69
87
|
end
|
70
|
-
|
88
|
+
set(hash, target_name: target_name, packet_name: packet_name, scope: scope)
|
71
89
|
end
|
72
90
|
|
73
91
|
# Get an item from the current value table
|
74
|
-
def self.get_item(target_name, packet_name, item_name, type:, scope: $openc3_scope)
|
75
|
-
|
76
|
-
|
77
|
-
case type
|
78
|
-
when :WITH_UNITS
|
79
|
-
types = ["#{item_name}__U", "#{item_name}__F", "#{item_name}__C", item_name]
|
80
|
-
override_key = "#{item_name}__U"
|
81
|
-
when :FORMATTED
|
82
|
-
types = ["#{item_name}__F", "#{item_name}__C", item_name]
|
83
|
-
override_key = "#{item_name}__F"
|
84
|
-
when :CONVERTED
|
85
|
-
types = ["#{item_name}__C", item_name]
|
86
|
-
override_key = "#{item_name}__C"
|
87
|
-
when :RAW
|
88
|
-
types = [item_name]
|
89
|
-
else
|
90
|
-
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
91
|
-
end
|
92
|
-
overrides = Store.hget("#{scope}__override__#{target_name}", packet_name)
|
93
|
-
if overrides
|
94
|
-
result = JSON.parse(overrides, :allow_nan => true, :create_additions => true)[override_key]
|
95
|
-
return result if result
|
96
|
-
end
|
92
|
+
def self.get_item(target_name, packet_name, item_name, type:, cache_timeout: 0.1, scope: $openc3_scope)
|
93
|
+
result, types = self._handle_item_override(target_name, packet_name, item_name, type: type, cache_timeout: cache_timeout, scope: scope)
|
94
|
+
return result if result
|
97
95
|
hash = get(target_name: target_name, packet_name: packet_name, scope: scope)
|
98
96
|
hash.values_at(*types).each do |result|
|
99
97
|
if result
|
@@ -111,18 +109,19 @@ module OpenC3
|
|
111
109
|
# @param items [Array<String>] Items to return. Must be formatted as TGT__PKT__ITEM__TYPE
|
112
110
|
# @param stale_time [Integer] Time in seconds from Time.now that value will be marked stale
|
113
111
|
# @return [Array] Array of values
|
114
|
-
def self.get_tlm_values(items, stale_time: 30, scope: $openc3_scope)
|
115
|
-
now = Time.now
|
112
|
+
def self.get_tlm_values(items, stale_time: 30, cache_timeout: 0.1, scope: $openc3_scope)
|
113
|
+
now = Time.now
|
116
114
|
results = []
|
117
115
|
lookups = []
|
118
116
|
packet_lookup = {}
|
119
117
|
overrides = {}
|
120
118
|
# First generate a lookup hash of all the items represented so we can query the CVT
|
121
|
-
items.each { |item| _parse_item(lookups, overrides, item, scope: scope) }
|
119
|
+
items.each { |item| _parse_item(now, lookups, overrides, item, cache_timeout: cache_timeout, scope: scope) }
|
122
120
|
|
121
|
+
now = now.to_f
|
123
122
|
lookups.each do |target_packet_key, target_name, packet_name, value_keys|
|
124
123
|
unless packet_lookup[target_packet_key]
|
125
|
-
packet_lookup[target_packet_key] = get(target_name: target_name, packet_name: packet_name, scope: scope)
|
124
|
+
packet_lookup[target_packet_key] = get(target_name: target_name, packet_name: packet_name, cache_timeout: cache_timeout, scope: scope)
|
126
125
|
end
|
127
126
|
hash = packet_lookup[target_packet_key]
|
128
127
|
item_result = []
|
@@ -153,6 +152,7 @@ module OpenC3
|
|
153
152
|
end
|
154
153
|
|
155
154
|
# Return all the overrides
|
155
|
+
# Note: Does not use cache to benefit from hgetall
|
156
156
|
def self.overrides(scope: $openc3_scope)
|
157
157
|
overrides = []
|
158
158
|
TargetModel.names(scope: scope).each do |target_name|
|
@@ -207,6 +207,9 @@ module OpenC3
|
|
207
207
|
else
|
208
208
|
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
209
209
|
end
|
210
|
+
|
211
|
+
tgt_pkt_key = "#{scope}__tlm__#{target_name}__#{packet_name}"
|
212
|
+
@@override_cache[tgt_pkt_key] = [Time.now, hash]
|
210
213
|
Store.hset("#{scope}__override__#{target_name}", packet_name, JSON.generate(hash.as_json(:allow_nan => true)))
|
211
214
|
end
|
212
215
|
|
@@ -232,6 +235,9 @@ module OpenC3
|
|
232
235
|
else
|
233
236
|
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
234
237
|
end
|
238
|
+
|
239
|
+
tgt_pkt_key = "#{scope}__tlm__#{target_name}__#{packet_name}"
|
240
|
+
@@override_cache[tgt_pkt_key] = [Time.now, hash]
|
235
241
|
if hash.empty?
|
236
242
|
Store.hdel("#{scope}__override__#{target_name}", packet_name)
|
237
243
|
else
|
@@ -239,16 +245,78 @@ module OpenC3
|
|
239
245
|
end
|
240
246
|
end
|
241
247
|
|
248
|
+
def self.determine_latest_packet_for_item(target_name, item_name, cache_timeout: 0.1, scope: $openc3_scope)
|
249
|
+
item_map = TargetModel.get_item_to_packet_map(target_name, scope: scope)
|
250
|
+
packet_names = item_map[item_name]
|
251
|
+
raise "Item '#{target_name} LATEST #{item_name}' does not exist for scope: #{scope}" unless packet_names
|
252
|
+
|
253
|
+
latest = -1
|
254
|
+
latest_packet_name = nil
|
255
|
+
packet_names.each do |packet_name|
|
256
|
+
hash = get(target_name: target_name, packet_name: packet_name, cache_timeout: cache_timeout, scope: scope)
|
257
|
+
if hash['PACKET_TIMESECONDS'] && hash['PACKET_TIMESECONDS'] > latest
|
258
|
+
latest = hash['PACKET_TIMESECONDS']
|
259
|
+
latest_packet_name = packet_name
|
260
|
+
end
|
261
|
+
end
|
262
|
+
raise "Item '#{target_name} LATEST #{item_name}' does not exist for scope: #{scope}" if latest == -1
|
263
|
+
return latest_packet_name
|
264
|
+
end
|
265
|
+
|
242
266
|
# PRIVATE METHODS
|
243
267
|
|
268
|
+
def self._handle_item_override(target_name, packet_name, item_name, type:, cache_timeout:, scope: $openc3_scope)
|
269
|
+
override_key = item_name
|
270
|
+
types = []
|
271
|
+
case type
|
272
|
+
when :WITH_UNITS
|
273
|
+
types = ["#{item_name}__U", "#{item_name}__F", "#{item_name}__C", item_name]
|
274
|
+
override_key = "#{item_name}__U"
|
275
|
+
when :FORMATTED
|
276
|
+
types = ["#{item_name}__F", "#{item_name}__C", item_name]
|
277
|
+
override_key = "#{item_name}__F"
|
278
|
+
when :CONVERTED
|
279
|
+
types = ["#{item_name}__C", item_name]
|
280
|
+
override_key = "#{item_name}__C"
|
281
|
+
when :RAW
|
282
|
+
types = [item_name]
|
283
|
+
else
|
284
|
+
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
285
|
+
end
|
286
|
+
|
287
|
+
tgt_pkt_key = "#{scope}__tlm__#{target_name}__#{packet_name}"
|
288
|
+
overrides = _get_overrides(Time.now, tgt_pkt_key, {}, target_name, packet_name, cache_timeout: cache_timeout, scope: scope)
|
289
|
+
result = overrides[override_key]
|
290
|
+
return result, types if result
|
291
|
+
return nil, types
|
292
|
+
end
|
293
|
+
|
294
|
+
def self._get_overrides(now, tgt_pkt_key, overrides, target_name, packet_name, cache_timeout:, scope:)
|
295
|
+
cache_time, hash = @@override_cache[tgt_pkt_key]
|
296
|
+
if hash and (now - cache_time) < cache_timeout
|
297
|
+
overrides[tgt_pkt_key] = hash
|
298
|
+
return hash
|
299
|
+
end
|
300
|
+
override_data = Store.hget("#{scope}__override__#{target_name}", packet_name)
|
301
|
+
if override_data
|
302
|
+
hash = JSON.parse(override_data, :allow_nan => true, :create_additions => true)
|
303
|
+
overrides[tgt_pkt_key] = hash
|
304
|
+
else
|
305
|
+
hash = {}
|
306
|
+
overrides[tgt_pkt_key] = {}
|
307
|
+
end
|
308
|
+
@@override_cache[tgt_pkt_key] = [now, hash] # always update
|
309
|
+
return hash
|
310
|
+
end
|
311
|
+
|
244
312
|
# parse item and update lookups with packet_name and target_name and keys
|
245
313
|
# return an ordered array of hash with keys
|
246
|
-
def self._parse_item(lookups, overrides, item, scope:)
|
247
|
-
target_name, packet_name, item_name, value_type = item
|
314
|
+
def self._parse_item(now, lookups, overrides, item, cache_timeout:, scope:)
|
315
|
+
target_name, packet_name, item_name, value_type = item
|
248
316
|
|
249
317
|
# We build lookup keys by including all the less formatted types to gracefully degrade lookups
|
250
318
|
# This allows the user to specify WITH_UNITS and if there is no conversions it will simply return the RAW value
|
251
|
-
case value_type
|
319
|
+
case value_type.to_s
|
252
320
|
when 'RAW'
|
253
321
|
keys = [item_name]
|
254
322
|
when 'CONVERTED'
|
@@ -260,20 +328,15 @@ module OpenC3
|
|
260
328
|
else
|
261
329
|
raise "Unknown value type '#{value_type}'"
|
262
330
|
end
|
263
|
-
|
331
|
+
|
264
332
|
# Check the overrides cache for this target / packet
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
end
|
273
|
-
if overrides[tgt_pkt_key][keys[0]]
|
274
|
-
# Set the result as a Hash to distingish it from the key array and from an overridden Array value
|
275
|
-
keys = {'value' => overrides[tgt_pkt_key][keys[0]]}
|
276
|
-
end
|
333
|
+
tgt_pkt_key = "#{scope}__tlm__#{target_name}__#{packet_name}"
|
334
|
+
_get_overrides(now, tgt_pkt_key, overrides, target_name, packet_name, cache_timeout: cache_timeout, scope: scope) unless overrides[tgt_pkt_key]
|
335
|
+
|
336
|
+
# Set the result as a Hash to distinguish it from the key array and from an overridden Array value
|
337
|
+
value = overrides[tgt_pkt_key][keys[0]]
|
338
|
+
keys = {'value' => value} if value
|
339
|
+
|
277
340
|
lookups << [tgt_pkt_key, target_name, packet_name, keys]
|
278
341
|
end
|
279
342
|
end
|
@@ -44,6 +44,8 @@ module OpenC3
|
|
44
44
|
class TargetModel < Model
|
45
45
|
PRIMARY_KEY = 'openc3_targets'
|
46
46
|
VALID_TYPES = %i(CMD TLM)
|
47
|
+
ITEM_MAP_CACHE_TIMEOUT = 10.0
|
48
|
+
@@item_map_cache = {}
|
47
49
|
|
48
50
|
attr_accessor :folder_name
|
49
51
|
attr_accessor :requires
|
@@ -208,7 +210,7 @@ module OpenC3
|
|
208
210
|
# @return [Array>Hash>] All packet hashes under the target_name
|
209
211
|
def self.packets(target_name, type: :TLM, scope:)
|
210
212
|
raise "Unknown type #{type} for #{target_name}" unless VALID_TYPES.include?(type)
|
211
|
-
raise "Target '#{target_name}' does not exist" unless get(name: target_name, scope: scope)
|
213
|
+
raise "Target '#{target_name}' does not exist for scope: #{scope}" unless get(name: target_name, scope: scope)
|
212
214
|
|
213
215
|
result = []
|
214
216
|
packets = Store.hgetall("#{scope}__openc3#{type.to_s.downcase}__#{target_name}")
|
@@ -268,6 +270,36 @@ module OpenC3
|
|
268
270
|
end
|
269
271
|
end
|
270
272
|
|
273
|
+
def self.get_item_to_packet_map(target_name, scope:)
|
274
|
+
cache_time, item_map = @@item_map_cache[target_name]
|
275
|
+
return item_map if item_map and (Time.now - cache_time) < ITEM_MAP_CACHE_TIMEOUT
|
276
|
+
item_map_key = "#{scope}__#{target_name}__item_to_packet_map"
|
277
|
+
target_name = target_name.upcase
|
278
|
+
json_data = Store.get(item_map_key)
|
279
|
+
if json_data
|
280
|
+
item_map = JSON.parse(json_data, :allow_nan => true, :create_additions => true)
|
281
|
+
else
|
282
|
+
item_map = build_item_to_packet_map(target_name, scope: scope)
|
283
|
+
Store.set(item_map_key, JSON.generate(item_map, :allow_nan => true))
|
284
|
+
end
|
285
|
+
@@item_map_cache[target_name] = [Time.now, item_map]
|
286
|
+
return item_map
|
287
|
+
end
|
288
|
+
|
289
|
+
def self.build_item_to_packet_map(target_name, scope:)
|
290
|
+
item_map = {}
|
291
|
+
packets = packets(target_name, scope: scope)
|
292
|
+
packets.each do |packet|
|
293
|
+
items = packet['items']
|
294
|
+
items.each do |item|
|
295
|
+
item_name = item['name']
|
296
|
+
item_map[item_name] ||= []
|
297
|
+
item_map[item_name] << packet['packet_name']
|
298
|
+
end
|
299
|
+
end
|
300
|
+
return item_map
|
301
|
+
end
|
302
|
+
|
271
303
|
# Called by the PluginModel to allow this class to validate it's top-level keyword: "TARGET"
|
272
304
|
def self.handle_config(parser, keyword, parameters, plugin: nil, needs_dependencies: false, scope:)
|
273
305
|
case keyword
|
@@ -601,6 +633,10 @@ module OpenC3
|
|
601
633
|
model.destroy if model
|
602
634
|
end
|
603
635
|
end
|
636
|
+
# Delete item_map
|
637
|
+
item_map_key = "#{@scope}__#{@name}__item_to_packet_map"
|
638
|
+
Store.del(item_map_key)
|
639
|
+
@@item_map_cache[@name] = nil
|
604
640
|
|
605
641
|
ConfigTopic.write({ kind: 'deleted', type: 'target', name: @name, plugin: @plugin }, scope: @scope)
|
606
642
|
end
|
@@ -731,6 +767,12 @@ module OpenC3
|
|
731
767
|
end
|
732
768
|
Store.hmset("#{@scope}__limits_sets", *sets)
|
733
769
|
|
770
|
+
# Create item_map
|
771
|
+
item_map_key = "#{@scope}__#{@name}__item_to_packet_map"
|
772
|
+
item_map = self.class.build_item_to_packet_map(@name, scope: @scope)
|
773
|
+
Store.set(item_map_key, JSON.generate(item_map, :allow_nan => true))
|
774
|
+
@@item_map_cache[@name] = [Time.now, item_map]
|
775
|
+
|
734
776
|
return system
|
735
777
|
end
|
736
778
|
|
@@ -431,7 +431,7 @@ module OpenC3
|
|
431
431
|
# Parse just to ensure we have valid JSON
|
432
432
|
JSON.parse(data, :allow_nan => true, :create_additions => true)
|
433
433
|
# Only save if the parse was successful
|
434
|
-
ToolConfigModel.save_config(parts[-2], File.basename(config), data, scope: scope, local_mode: false)
|
434
|
+
ToolConfigModel.save_config(parts[-2], File.basename(config, '.json'), data, scope: scope, local_mode: false)
|
435
435
|
rescue JSON::ParserError => error
|
436
436
|
puts "Unable to initialize tool config due to #{error.message}"
|
437
437
|
end
|
data/lib/openc3/version.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
OPENC3_VERSION = '5.9.
|
3
|
+
OPENC3_VERSION = '5.9.1'
|
4
4
|
module OpenC3
|
5
5
|
module Version
|
6
6
|
MAJOR = '5'
|
7
7
|
MINOR = '9'
|
8
|
-
PATCH = '
|
8
|
+
PATCH = '1'
|
9
9
|
OTHER = ''
|
10
|
-
BUILD = '
|
10
|
+
BUILD = 'e60c6e1f7e80f87eae7bc623986940da5449d6ad'
|
11
11
|
end
|
12
|
-
VERSION = '5.9.
|
13
|
-
GEM_VERSION = '5.9.
|
12
|
+
VERSION = '5.9.1'
|
13
|
+
GEM_VERSION = '5.9.1'
|
14
14
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "<%= tool_name %>",
|
3
|
-
"version": "5.9.
|
3
|
+
"version": "5.9.1",
|
4
4
|
"scripts": {
|
5
5
|
"ng": "ng",
|
6
6
|
"start": "ng serve",
|
@@ -22,7 +22,7 @@
|
|
22
22
|
"@angular/platform-browser": "^16.1.3",
|
23
23
|
"@angular/platform-browser-dynamic": "^16.1.3",
|
24
24
|
"@angular/router": "^16.1.3",
|
25
|
-
"@openc3/tool-common": "5.9.
|
25
|
+
"@openc3/tool-common": "5.9.1",
|
26
26
|
"rxjs": "~7.8.0",
|
27
27
|
"single-spa": ">=5.9.5",
|
28
28
|
"single-spa-angular": "^8.1.0",
|