openc3 5.14.2 → 5.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/openc3cli +1 -1
- data/data/config/_id_items.yaml +2 -3
- data/data/config/telemetry_modifiers.yaml +0 -1
- data/lib/openc3/accessors/accessor.rb +3 -3
- data/lib/openc3/accessors/http_accessor.rb +1 -1
- data/lib/openc3/api/cmd_api.rb +17 -6
- data/lib/openc3/api/tlm_api.rb +16 -5
- data/lib/openc3/logs/buffered_packet_log_writer.rb +5 -0
- data/lib/openc3/microservices/interface_microservice.rb +29 -18
- data/lib/openc3/models/cvt_model.rb +9 -4
- data/lib/openc3/models/gem_model.rb +7 -5
- data/lib/openc3/models/metric_model.rb +8 -0
- data/lib/openc3/models/model.rb +21 -6
- data/lib/openc3/models/plugin_model.rb +8 -2
- data/lib/openc3/models/python_package_model.rb +3 -0
- data/lib/openc3/models/scope_model.rb +2 -2
- data/lib/openc3/models/target_model.rb +21 -28
- data/lib/openc3/models/tool_model.rb +2 -2
- data/lib/openc3/packets/json_packet.rb +5 -3
- data/lib/openc3/script/suite_results.rb +9 -9
- data/lib/openc3/topics/command_decom_topic.rb +2 -1
- data/lib/openc3/topics/command_topic.rb +2 -1
- data/lib/openc3/topics/telemetry_topic.rb +7 -2
- data/lib/openc3/utilities/aws_bucket.rb +21 -15
- data/lib/openc3/utilities/bucket.rb +1 -1
- data/lib/openc3/utilities/logger.rb +3 -3
- data/lib/openc3/utilities/process_manager.rb +15 -9
- data/lib/openc3/utilities/store_autoload.rb +29 -2
- data/lib/openc3/utilities/store_queued.rb +23 -24
- data/lib/openc3/version.rb +6 -6
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_vue/package.json +2 -2
- data/templates/widget/package.json +2 -2
- metadata +16 -7
- data/templates/tool_angular/yarn.lock +0 -8155
- data/templates/tool_react/yarn.lock +0 -7201
- data/templates/tool_svelte/yarn.lock +0 -5519
- data/templates/tool_vue/yarn.lock +0 -9455
- data/templates/widget/yarn.lock +0 -9338
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0228b27d56d6fce2f445eb5842ec223be1351aaf09767da803e735ffb80875ec'
|
4
|
+
data.tar.gz: 7f78a835eb8d3d1c678afa7f93490821cac67dcbf3d854ec1973c452b139a647
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 545775f6dd330af7e6e4f566a07ea44f5f5b2e533d2dadb9704e5e1dba142377f4b63dacc89157b0c4b996e20c78851fba4d397d830619fa51ff0a313850935f
|
7
|
+
data.tar.gz: 9eb87fbc7b5410327f0142f1e2bf08ae8070169057a34fbef6eb0f7c9bd846c07aae7e49b70d9b8f4ff5647fe1258155eeb879d0ace4cbe782b1e7b5ca2c8019
|
data/bin/openc3cli
CHANGED
@@ -471,7 +471,7 @@ def load_plugin(plugin_file_path, scope:, plugin_hash_file: nil, force: false)
|
|
471
471
|
OpenC3::LocalMode.update_local_plugin(plugin_file_path, plugin_hash, scope: scope)
|
472
472
|
end
|
473
473
|
rescue => e
|
474
|
-
abort("Error installing plugin: #{scope}: #{plugin_file_path}\n#{e.
|
474
|
+
abort("Error installing plugin: #{scope}: #{plugin_file_path}\n#{e.formatted}")
|
475
475
|
end
|
476
476
|
else
|
477
477
|
# Outside Cluster
|
data/data/config/_id_items.yaml
CHANGED
@@ -4,13 +4,12 @@
|
|
4
4
|
description:
|
5
5
|
Bit size of this telemetry item. Zero or Negative values may be used
|
6
6
|
to indicate that a string fills the packet up to the offset from the end of
|
7
|
-
the packet specified by this value.
|
8
|
-
this is a derived parameter and the Data Type must be set to 'DERIVED'.
|
7
|
+
the packet specified by this value.
|
9
8
|
values: \d+
|
10
9
|
- name: Data Type
|
11
10
|
required: true
|
12
11
|
description: Data Type of this telemetry item
|
13
|
-
values: <%= %w(INT UINT FLOAT STRING BLOCK
|
12
|
+
values: <%= %w(INT UINT FLOAT STRING BLOCK) %>
|
14
13
|
- name: ID Value
|
15
14
|
required: true
|
16
15
|
description: The value of this telemetry item that uniquely identifies this telemetry packet
|
@@ -45,7 +45,6 @@ ID_ITEM:
|
|
45
45
|
required: true
|
46
46
|
description: Bit offset into the telemetry packet of the Most Significant Bit of this item.
|
47
47
|
May be negative to indicate on offset from the end of the packet.
|
48
|
-
Always use a bit offset of 0 for derived item.
|
49
48
|
values: '[-]?\d+'
|
50
49
|
<%= MetaConfigParser.load('_id_items.yaml').to_meta_config_yaml(4) %>
|
51
50
|
APPEND_ID_ITEM:
|
@@ -74,18 +74,18 @@ module OpenC3
|
|
74
74
|
return false
|
75
75
|
end
|
76
76
|
|
77
|
-
# If this is true it will
|
77
|
+
# If this is true it will enforce that COSMOS DERIVED items must have a
|
78
78
|
# write_conversion to be written
|
79
79
|
def enforce_derived_write_conversion(_item)
|
80
80
|
return true
|
81
81
|
end
|
82
82
|
|
83
83
|
def self.read_item(_item, _buffer)
|
84
|
-
raise "Must be defined by subclass"
|
84
|
+
raise "Must be defined by subclass if needed"
|
85
85
|
end
|
86
86
|
|
87
87
|
def self.write_item(_item, _value, _buffer)
|
88
|
-
raise "Must be defined by subclass"
|
88
|
+
raise "Must be defined by subclass if needed"
|
89
89
|
end
|
90
90
|
|
91
91
|
def self.read_items(items, buffer)
|
@@ -176,7 +176,7 @@ module OpenC3
|
|
176
176
|
when 'HTTP_STATUS', 'HTTP_PATH', 'HTTP_METHOD', 'HTTP_PACKET', 'HTTP_ERROR_PACKET', /^HTTP_QUERY_/, /^HTTP_HEADER_/
|
177
177
|
return false
|
178
178
|
else
|
179
|
-
return @body_accessor.enforce_derived_write_conversion
|
179
|
+
return @body_accessor.enforce_derived_write_conversion(item)
|
180
180
|
end
|
181
181
|
end
|
182
182
|
end
|
data/lib/openc3/api/cmd_api.rb
CHANGED
@@ -178,10 +178,21 @@ module OpenC3
|
|
178
178
|
# @since 5.0.6
|
179
179
|
# @param target_name [String] Name of the target
|
180
180
|
# @return [Array<String>] Array of all command packet names
|
181
|
-
def get_all_cmd_names(target_name, scope: $openc3_scope, token: $openc3_token)
|
182
|
-
|
183
|
-
|
184
|
-
|
181
|
+
def get_all_cmd_names(target_name, hidden: false, scope: $openc3_scope, token: $openc3_token)
|
182
|
+
begin
|
183
|
+
packets = get_all_cmds(target_name, scope: scope, token: token)
|
184
|
+
rescue RuntimeError
|
185
|
+
packets = []
|
186
|
+
end
|
187
|
+
names = []
|
188
|
+
packets.each do |packet|
|
189
|
+
if hidden
|
190
|
+
names << packet['packet_name']
|
191
|
+
else
|
192
|
+
names << packet['packet_name'] unless packet['hidden']
|
193
|
+
end
|
194
|
+
end
|
195
|
+
return names
|
185
196
|
end
|
186
197
|
# get_all_command_names is DEPRECATED
|
187
198
|
alias get_all_command_names get_all_cmd_names
|
@@ -474,7 +485,7 @@ module OpenC3
|
|
474
485
|
|
475
486
|
def _build_cmd_output_string(method_name, target_name, cmd_name, cmd_params, packet)
|
476
487
|
output_string = "#{method_name}(\""
|
477
|
-
output_string << target_name + ' ' + cmd_name
|
488
|
+
output_string << (target_name + ' ' + cmd_name)
|
478
489
|
if cmd_params.nil? or cmd_params.empty?
|
479
490
|
output_string << '")'
|
480
491
|
else
|
@@ -511,7 +522,7 @@ module OpenC3
|
|
511
522
|
params << "#{key} #{value}"
|
512
523
|
end
|
513
524
|
params = params.join(", ")
|
514
|
-
output_string << ' with ' + params + '")'
|
525
|
+
output_string << (' with ' + params + '")')
|
515
526
|
end
|
516
527
|
return output_string
|
517
528
|
end
|
data/lib/openc3/api/tlm_api.rb
CHANGED
@@ -139,7 +139,7 @@ module OpenC3
|
|
139
139
|
|
140
140
|
# See if this target has a tlm interface
|
141
141
|
interface_name = nil
|
142
|
-
InterfaceModel.all(scope: scope).each do |
|
142
|
+
InterfaceModel.all(scope: scope).each do |_name, interface|
|
143
143
|
if interface['tlm_target_names'].include? target_name
|
144
144
|
interface_name = interface['name']
|
145
145
|
break
|
@@ -287,10 +287,21 @@ module OpenC3
|
|
287
287
|
# @since 5.0.6
|
288
288
|
# @param target_name [String] Name of the target
|
289
289
|
# @return [Array<String>] Array of all telemetry packet names
|
290
|
-
def get_all_tlm_names(target_name, scope: $openc3_scope, token: $openc3_token)
|
291
|
-
|
292
|
-
|
293
|
-
|
290
|
+
def get_all_tlm_names(target_name, hidden: false, scope: $openc3_scope, token: $openc3_token)
|
291
|
+
begin
|
292
|
+
packets = get_all_tlm(target_name, scope: scope, token: token)
|
293
|
+
rescue RuntimeError
|
294
|
+
packets = []
|
295
|
+
end
|
296
|
+
names = []
|
297
|
+
packets.each do |packet|
|
298
|
+
if hidden
|
299
|
+
names << packet['packet_name']
|
300
|
+
else
|
301
|
+
names << packet['packet_name'] unless packet['hidden']
|
302
|
+
end
|
303
|
+
end
|
304
|
+
return names
|
294
305
|
end
|
295
306
|
alias get_all_telemetry_names get_all_tlm_names
|
296
307
|
|
@@ -80,6 +80,11 @@ module OpenC3
|
|
80
80
|
def buffered_write(entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id = nil, redis_topic = nil, redis_offset = '0-0', received_time_nsec_since_epoch: nil, extra: nil)
|
81
81
|
case entry_type
|
82
82
|
when :RAW_PACKET, :JSON_PACKET
|
83
|
+
# If we have data in the buffer, a file should always be open so that cycle time logic will run
|
84
|
+
unless @file
|
85
|
+
@mutex.synchronize { start_new_file() }
|
86
|
+
end
|
87
|
+
|
83
88
|
@buffer << [entry_type, cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, data, id, redis_topic, redis_offset, received_time_nsec_since_epoch, extra]
|
84
89
|
@buffer.sort! {|entry1, entry2| entry1[4] <=> entry2[4] }
|
85
90
|
if @buffer.length >= @buffer_depth
|
@@ -126,7 +126,7 @@ module OpenC3
|
|
126
126
|
begin
|
127
127
|
@logger.info "#{@interface.name}: interface_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
|
128
128
|
@interface.interface_cmd(params['cmd_name'], *params['cmd_params'])
|
129
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
129
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
130
130
|
rescue => e
|
131
131
|
@logger.error "#{@interface.name}: interface_cmd: #{e.formatted}"
|
132
132
|
next e.message
|
@@ -138,7 +138,7 @@ module OpenC3
|
|
138
138
|
begin
|
139
139
|
@logger.info "#{@interface.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
|
140
140
|
@interface.protocol_cmd(params['cmd_name'], *params['cmd_params'], read_write: params['read_write'], index: params['index'])
|
141
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
141
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
142
142
|
rescue => e
|
143
143
|
@logger.error "#{@interface.name}: protocol_cmd: #{e.formatted}"
|
144
144
|
next e.message
|
@@ -206,7 +206,7 @@ module OpenC3
|
|
206
206
|
@interface.write(command)
|
207
207
|
CommandTopic.write_packet(command, scope: @scope)
|
208
208
|
CommandDecomTopic.write_packet(command, scope: @scope)
|
209
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
209
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
210
210
|
next 'SUCCESS'
|
211
211
|
else
|
212
212
|
next "Interface not connected: #{@interface.name}"
|
@@ -298,7 +298,7 @@ module OpenC3
|
|
298
298
|
begin
|
299
299
|
@logger.info "#{@router.name}: router_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')}"
|
300
300
|
@router.interface_cmd(params['cmd_name'], *params['cmd_params'])
|
301
|
-
RouterStatusModel.set(@router.as_json(:allow_nan => true), scope: @scope)
|
301
|
+
RouterStatusModel.set(@router.as_json(:allow_nan => true), queued: true, scope: @scope)
|
302
302
|
rescue => e
|
303
303
|
@logger.error "#{@router.name}: router_cmd: #{e.formatted}"
|
304
304
|
next e.message
|
@@ -310,7 +310,7 @@ module OpenC3
|
|
310
310
|
begin
|
311
311
|
@logger.info "#{@router.name}: protocol_cmd: #{params['cmd_name']} #{params['cmd_params'].join(' ')} read_write: #{params['read_write']} index: #{params['index']}"
|
312
312
|
@router.protocol_cmd(params['cmd_name'], *params['cmd_params'], read_write: params['read_write'], index: params['index'])
|
313
|
-
RouterStatusModel.set(@router.as_json(:allow_nan => true), scope: @scope)
|
313
|
+
RouterStatusModel.set(@router.as_json(:allow_nan => true), queued: true, scope: @scope)
|
314
314
|
rescue => e
|
315
315
|
@logger.error "#{@router.name}: protoco_cmd: #{e.formatted}"
|
316
316
|
next e.message
|
@@ -335,7 +335,7 @@ module OpenC3
|
|
335
335
|
|
336
336
|
begin
|
337
337
|
@router.write(packet)
|
338
|
-
RouterStatusModel.set(@router.as_json(:allow_nan => true), scope: @scope)
|
338
|
+
RouterStatusModel.set(@router.as_json(:allow_nan => true), queued: true, scope: @scope)
|
339
339
|
next 'SUCCESS'
|
340
340
|
rescue => e
|
341
341
|
@logger.error "#{@router.name}: #{e.formatted}"
|
@@ -352,6 +352,7 @@ module OpenC3
|
|
352
352
|
def initialize(name)
|
353
353
|
@mutex = Mutex.new
|
354
354
|
super(name)
|
355
|
+
|
355
356
|
@interface_or_router = self.class.name.to_s.split("Microservice")[0].upcase.split("::")[-1]
|
356
357
|
if @interface_or_router == 'INTERFACE'
|
357
358
|
@metric.set(name: 'interface_tlm_total', value: @count, type: 'counter')
|
@@ -359,7 +360,6 @@ module OpenC3
|
|
359
360
|
@metric.set(name: 'router_cmd_total', value: @count, type: 'counter')
|
360
361
|
end
|
361
362
|
|
362
|
-
@scope = name.split("__")[0]
|
363
363
|
interface_name = name.split("__")[2]
|
364
364
|
if @interface_or_router == 'INTERFACE'
|
365
365
|
@interface = InterfaceModel.get_model(name: interface_name, scope: @scope).build
|
@@ -400,6 +400,17 @@ module OpenC3
|
|
400
400
|
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
401
401
|
end
|
402
402
|
|
403
|
+
@queued = false
|
404
|
+
@interface.options.each do |option_name, option_values|
|
405
|
+
case option_name.upcase
|
406
|
+
when 'OPTIMIZE_THROUGHPUT'
|
407
|
+
@queued = true
|
408
|
+
update_interval = option_values[0].to_f
|
409
|
+
EphemeralStoreQueued.instance.set_update_interval(update_interval)
|
410
|
+
StoreQueued.instance.set_update_interval(update_interval)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
403
414
|
@interface_thread_sleeper = Sleeper.new
|
404
415
|
@cancel_thread = false
|
405
416
|
@connection_failed_messages = []
|
@@ -432,9 +443,9 @@ module OpenC3
|
|
432
443
|
|
433
444
|
@interface.state = 'ATTEMPTING'
|
434
445
|
if @interface_or_router == 'INTERFACE'
|
435
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
446
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
436
447
|
else
|
437
|
-
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
448
|
+
RouterStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
438
449
|
end
|
439
450
|
@interface # Return the interface/router since we may have recreated it
|
440
451
|
# Need to rescue Exception so we cover LoadError
|
@@ -507,15 +518,15 @@ module OpenC3
|
|
507
518
|
disconnect(false)
|
508
519
|
end
|
509
520
|
if @interface_or_router == 'INTERFACE'
|
510
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
521
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
511
522
|
else
|
512
|
-
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
523
|
+
RouterStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
513
524
|
end
|
514
525
|
@logger.info "#{@interface.name}: Stopped packet reading"
|
515
526
|
end
|
516
527
|
|
517
528
|
def handle_packet(packet)
|
518
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
529
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
519
530
|
packet.received_time = Time.now.sys unless packet.received_time
|
520
531
|
|
521
532
|
if packet.stored
|
@@ -557,7 +568,7 @@ module OpenC3
|
|
557
568
|
unknown_packet.extra = packet.extra
|
558
569
|
packet = unknown_packet
|
559
570
|
json_hash = CvtModel.build_json_from_packet(packet)
|
560
|
-
CvtModel.set(json_hash, target_name: packet.target_name, packet_name: packet.packet_name, scope: @scope)
|
571
|
+
CvtModel.set(json_hash, target_name: packet.target_name, packet_name: packet.packet_name, queued: @queued, scope: @scope)
|
561
572
|
num_bytes_to_print = [UNKNOWN_BYTES_TO_PRINT, packet.length].min
|
562
573
|
data = packet.buffer(false)[0..(num_bytes_to_print - 1)]
|
563
574
|
prefix = data.each_byte.map { | byte | sprintf("%02X", byte) }.join()
|
@@ -566,7 +577,7 @@ module OpenC3
|
|
566
577
|
|
567
578
|
# Write to stream
|
568
579
|
packet.received_count += 1
|
569
|
-
TelemetryTopic.write_packet(packet, scope: @scope)
|
580
|
+
TelemetryTopic.write_packet(packet, queued: @queued, scope: @scope)
|
570
581
|
end
|
571
582
|
|
572
583
|
def handle_connection_failed(connect_error)
|
@@ -629,9 +640,9 @@ module OpenC3
|
|
629
640
|
end
|
630
641
|
@interface.state = 'CONNECTED'
|
631
642
|
if @interface_or_router == 'INTERFACE'
|
632
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
643
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
633
644
|
else
|
634
|
-
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
645
|
+
RouterStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
635
646
|
end
|
636
647
|
@logger.info "#{@interface.name}: Connection Success"
|
637
648
|
end
|
@@ -661,9 +672,9 @@ module OpenC3
|
|
661
672
|
else
|
662
673
|
@interface.state = 'DISCONNECTED'
|
663
674
|
if @interface_or_router == 'INTERFACE'
|
664
|
-
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
675
|
+
InterfaceStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
665
676
|
else
|
666
|
-
RouterStatusModel.set(@interface.as_json(:allow_nan => true), scope: @scope)
|
677
|
+
RouterStatusModel.set(@interface.as_json(:allow_nan => true), queued: true, scope: @scope)
|
667
678
|
end
|
668
679
|
end
|
669
680
|
end
|
@@ -21,6 +21,7 @@
|
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
23
|
require 'openc3/utilities/store'
|
24
|
+
require 'openc3/utilities/store_queued'
|
24
25
|
require 'openc3/models/target_model'
|
25
26
|
|
26
27
|
module OpenC3
|
@@ -42,12 +43,16 @@ module OpenC3
|
|
42
43
|
end
|
43
44
|
|
44
45
|
# Set the current value table for a target, packet
|
45
|
-
def self.set(hash, target_name:, packet_name:, scope: $openc3_scope)
|
46
|
+
def self.set(hash, target_name:, packet_name:, queued: false, scope: $openc3_scope)
|
46
47
|
packet_json = JSON.generate(hash.as_json(:allow_nan => true))
|
47
48
|
key = "#{scope}__tlm__#{target_name}"
|
48
49
|
tgt_pkt_key = key + "__#{packet_name}"
|
49
50
|
@@packet_cache[tgt_pkt_key] = [Time.now, hash]
|
50
|
-
|
51
|
+
if queued
|
52
|
+
StoreQueued.hset(key, packet_name, packet_json)
|
53
|
+
else
|
54
|
+
Store.hset(key, packet_name, packet_json)
|
55
|
+
end
|
51
56
|
end
|
52
57
|
|
53
58
|
# Get the hash for packet in the CVT
|
@@ -68,7 +73,7 @@ module OpenC3
|
|
68
73
|
end
|
69
74
|
|
70
75
|
# Set an item in the current value table
|
71
|
-
def self.set_item(target_name, packet_name, item_name, value, type:, scope: $openc3_scope)
|
76
|
+
def self.set_item(target_name, packet_name, item_name, value, type:, queued: false, scope: $openc3_scope)
|
72
77
|
hash = get(target_name: target_name, packet_name: packet_name, cache_timeout: nil, scope: scope)
|
73
78
|
case type
|
74
79
|
when :WITH_UNITS
|
@@ -87,7 +92,7 @@ module OpenC3
|
|
87
92
|
else
|
88
93
|
raise "Unknown type '#{type}' for #{target_name} #{packet_name} #{item_name}"
|
89
94
|
end
|
90
|
-
set(hash, target_name: target_name, packet_name: packet_name, scope: scope)
|
95
|
+
set(hash, target_name: target_name, packet_name: packet_name, queued: queued, scope: scope)
|
91
96
|
end
|
92
97
|
|
93
98
|
# Get an item from the current value table
|
@@ -102,13 +102,15 @@ module OpenC3
|
|
102
102
|
raise err
|
103
103
|
end
|
104
104
|
|
105
|
-
def self.destroy(name)
|
105
|
+
def self.destroy(name, log_and_raise_needed_errors: true)
|
106
106
|
gem_name, version = self.extract_name_and_version(name)
|
107
107
|
plugin_gem_names = PluginModel.gem_names
|
108
108
|
if plugin_gem_names.include?(name)
|
109
|
-
|
110
|
-
|
111
|
-
|
109
|
+
if log_and_raise_needed_errors
|
110
|
+
message = "Gem file #{name} can't be uninstalled because needed by installed plugin"
|
111
|
+
Logger.error message
|
112
|
+
raise message
|
113
|
+
end
|
112
114
|
else
|
113
115
|
begin
|
114
116
|
Gem::Uninstaller.new(gem_name, {:version => version, :force => true}).uninstall
|
@@ -131,7 +133,7 @@ module OpenC3
|
|
131
133
|
GemModel.names.each do |gem_full_name|
|
132
134
|
gem_name, gem_version = GemModel.extract_name_and_version(gem_full_name)
|
133
135
|
if gem_name == keep_gem_name and gem_version != keep_gem_version
|
134
|
-
GemModel.destroy(gem_full_name)
|
136
|
+
GemModel.destroy(gem_full_name, log_and_raise_needed_errors: false)
|
135
137
|
end
|
136
138
|
end
|
137
139
|
end
|
@@ -42,6 +42,14 @@ module OpenC3
|
|
42
42
|
super("#{scope}#{PRIMARY_KEY}")
|
43
43
|
end
|
44
44
|
|
45
|
+
# Sets (updates) the redis hash of this model
|
46
|
+
# Queued defaults to true for MetricModel
|
47
|
+
def self.set(json, scope:, queued: true)
|
48
|
+
json[:scope] = scope
|
49
|
+
json.transform_keys!(&:to_sym)
|
50
|
+
self.new(**json).create(force: true, queued: queued)
|
51
|
+
end
|
52
|
+
|
45
53
|
def self.destroy(scope:, name:)
|
46
54
|
EphemeralStore.hdel("#{scope}#{PRIMARY_KEY}", name)
|
47
55
|
end
|
data/lib/openc3/models/model.rb
CHANGED
@@ -21,6 +21,7 @@
|
|
21
21
|
# if purchased from OpenC3, Inc.
|
22
22
|
|
23
23
|
require 'openc3/utilities/store'
|
24
|
+
require 'openc3/utilities/store_queued'
|
24
25
|
require 'openc3/config/config_parser'
|
25
26
|
|
26
27
|
module OpenC3
|
@@ -34,6 +35,10 @@ module OpenC3
|
|
34
35
|
Store
|
35
36
|
end
|
36
37
|
|
38
|
+
def self.store_queued
|
39
|
+
StoreQueued
|
40
|
+
end
|
41
|
+
|
37
42
|
# NOTE: The following three methods must be reimplemented by Model subclasses
|
38
43
|
# without primary_key to support other class methods.
|
39
44
|
|
@@ -75,10 +80,10 @@ module OpenC3
|
|
75
80
|
end
|
76
81
|
|
77
82
|
# Sets (updates) the redis hash of this model
|
78
|
-
def self.set(json, scope:)
|
83
|
+
def self.set(json, scope:, queued: false)
|
79
84
|
json[:scope] = scope
|
80
85
|
json.transform_keys!(&:to_sym)
|
81
|
-
self.new(**json).create(force: true)
|
86
|
+
self.new(**json).create(force: true, queued: queued)
|
82
87
|
end
|
83
88
|
|
84
89
|
# @return [Model] Model generated from the passed JSON
|
@@ -134,7 +139,7 @@ module OpenC3
|
|
134
139
|
|
135
140
|
# Update the Redis hash at primary_key and set the field "name"
|
136
141
|
# to the JSON generated via calling as_json
|
137
|
-
def create(update: false, force: false)
|
142
|
+
def create(update: false, force: false, queued: false)
|
138
143
|
unless force
|
139
144
|
existing = self.class.store.hget(@primary_key, @name)
|
140
145
|
if existing
|
@@ -144,12 +149,18 @@ module OpenC3
|
|
144
149
|
end
|
145
150
|
end
|
146
151
|
@updated_at = Time.now.to_nsec_from_epoch
|
147
|
-
|
152
|
+
|
153
|
+
if queued
|
154
|
+
write_store = self.class.store_queued
|
155
|
+
else
|
156
|
+
write_store = self.class.store
|
157
|
+
end
|
158
|
+
write_store.hset(@primary_key, @name, JSON.generate(self.as_json(:allow_nan => true), :allow_nan => true))
|
148
159
|
end
|
149
160
|
|
150
161
|
# Alias for create(update: true)
|
151
|
-
def update
|
152
|
-
create(update: true)
|
162
|
+
def update(force: false, queued: false)
|
163
|
+
create(update: true, force: force, queued: queued)
|
153
164
|
end
|
154
165
|
|
155
166
|
# Deploy the model into the OpenC3 system. Subclasses must implement this
|
@@ -206,5 +217,9 @@ module OpenC3
|
|
206
217
|
def self.store
|
207
218
|
EphemeralStore
|
208
219
|
end
|
220
|
+
|
221
|
+
def self.store_queued
|
222
|
+
EphemeralStoreQueued
|
223
|
+
end
|
209
224
|
end
|
210
225
|
end
|
@@ -183,12 +183,18 @@ module OpenC3
|
|
183
183
|
if File.exist?(File.join(gem_path, 'requirements.txt'))
|
184
184
|
begin
|
185
185
|
pypi_url = get_setting('pypi_url', scope: scope)
|
186
|
+
if pypi_url
|
187
|
+
pypi_url += '/simple'
|
188
|
+
end
|
186
189
|
rescue => e
|
187
190
|
Logger.error("Failed to retrieve pypi_url: #{e.formatted}")
|
188
191
|
ensure
|
189
192
|
if pypi_url.nil?
|
190
193
|
# If Redis isn't running try the ENV, then simply pypi.org/simple
|
191
194
|
pypi_url = ENV['PYPI_URL']
|
195
|
+
if pypi_url
|
196
|
+
pypi_url += '/simple'
|
197
|
+
end
|
192
198
|
pypi_url ||= 'https://pypi.org/simple'
|
193
199
|
end
|
194
200
|
end
|
@@ -288,9 +294,9 @@ module OpenC3
|
|
288
294
|
@needs_dependencies = ConfigParser.handle_true_false(needs_dependencies)
|
289
295
|
end
|
290
296
|
|
291
|
-
def create(update: false, force: false)
|
297
|
+
def create(update: false, force: false, queued: false)
|
292
298
|
@name = @name + "__#{Time.now.utc.strftime("%Y%m%d%H%M%S")}" if not update and not @name.index("__")
|
293
|
-
super(update: update, force: force)
|
299
|
+
super(update: update, force: force, queued: queued)
|
294
300
|
end
|
295
301
|
|
296
302
|
def as_json(*a)
|
@@ -74,6 +74,9 @@ module OpenC3
|
|
74
74
|
rescue
|
75
75
|
# If Redis isn't running try the ENV, then simply pypi.org/simple
|
76
76
|
pypi_url = ENV['PYPI_URL']
|
77
|
+
if pypi_url
|
78
|
+
pypi_url += '/simple'
|
79
|
+
end
|
77
80
|
pypi_url ||= 'https://pypi.org/simple'
|
78
81
|
end
|
79
82
|
Logger.info "Installing python package: #{name_or_path}"
|
@@ -95,11 +95,11 @@ module OpenC3
|
|
95
95
|
@children = []
|
96
96
|
end
|
97
97
|
|
98
|
-
def create(update: false, force: false)
|
98
|
+
def create(update: false, force: false, queued: false)
|
99
99
|
# Ensure there are no "." in the scope name - prevents gems accidently becoming scope names
|
100
100
|
raise "Invalid scope name: #{@name}" if @name !~ /^[a-zA-Z0-9_-]+$/
|
101
101
|
@name = @name.upcase
|
102
|
-
super(update: update, force: force)
|
102
|
+
super(update: update, force: force, queued: queued)
|
103
103
|
end
|
104
104
|
|
105
105
|
def destroy
|