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
@@ -89,6 +89,18 @@ module OpenC3
|
|
89
89
|
# @return [String] Base data for building packet
|
90
90
|
attr_reader :template
|
91
91
|
|
92
|
+
# @return [Array<Target Name, Packet Name>] Related response packet
|
93
|
+
attr_accessor :response
|
94
|
+
|
95
|
+
# @return [Array<Target Name, Packet Name>] Related error response packet
|
96
|
+
attr_accessor :error_response
|
97
|
+
|
98
|
+
# @return [Array<Target Name, Screen Name>] Related telemetry screen
|
99
|
+
attr_accessor :screen
|
100
|
+
|
101
|
+
# @return [Array<Array<Target Name, Packet Name, Item Name>>] Related items
|
102
|
+
attr_accessor :related_items
|
103
|
+
|
92
104
|
# Valid format types
|
93
105
|
VALUE_TYPES = [:RAW, :CONVERTED, :FORMATTED, :WITH_UNITS]
|
94
106
|
|
@@ -297,6 +309,10 @@ module OpenC3
|
|
297
309
|
@config_name
|
298
310
|
end
|
299
311
|
|
312
|
+
def clear_config_name
|
313
|
+
@config_name = nil
|
314
|
+
end
|
315
|
+
|
300
316
|
# (see Structure#buffer=)
|
301
317
|
def buffer=(buffer)
|
302
318
|
synchronize() do
|
@@ -306,7 +322,6 @@ module OpenC3
|
|
306
322
|
Logger.instance.error "#{@target_name} #{@packet_name} received with actual packet length of #{buffer.length} but defined length of #{@defined_length}"
|
307
323
|
end
|
308
324
|
@read_conversion_cache.clear if @read_conversion_cache
|
309
|
-
process()
|
310
325
|
end
|
311
326
|
end
|
312
327
|
|
@@ -861,6 +876,33 @@ module OpenC3
|
|
861
876
|
item.description = 'OpenC3 packet received count'
|
862
877
|
end
|
863
878
|
|
879
|
+
# Reset the packet to just derived items
|
880
|
+
def clear_all_non_derived_items
|
881
|
+
@defined_length = 0
|
882
|
+
@defined_length_bits = 0
|
883
|
+
@pos_bit_size = 0
|
884
|
+
@neg_bit_size = 0
|
885
|
+
@fixed_size = true
|
886
|
+
@short_buffer_allowed = false
|
887
|
+
@id_items = nil
|
888
|
+
@limits_items = nil
|
889
|
+
new_items = {}
|
890
|
+
new_sorted_items = []
|
891
|
+
@items.each do |name, item|
|
892
|
+
if item.data_type == :DERIVED
|
893
|
+
new_items[name] = item
|
894
|
+
end
|
895
|
+
end
|
896
|
+
@sorted_items.each do |item|
|
897
|
+
if item.data_type == :DERIVED
|
898
|
+
new_sorted_items << item
|
899
|
+
end
|
900
|
+
end
|
901
|
+
@items = new_items
|
902
|
+
@sorted_items = new_sorted_items
|
903
|
+
clear_config_name()
|
904
|
+
end
|
905
|
+
|
864
906
|
# Enable limits on an item by name
|
865
907
|
#
|
866
908
|
# @param name [String] Name of the item to enable limits
|
@@ -1008,6 +1050,13 @@ module OpenC3
|
|
1008
1050
|
else
|
1009
1051
|
config << "COMMAND #{@target_name.to_s.quote_if_necessary} #{@packet_name.to_s.quote_if_necessary} #{@default_endianness} \"#{@description}\"\n"
|
1010
1052
|
end
|
1053
|
+
if @accessor.class.to_s != 'OpenC3::BinaryAccessor'
|
1054
|
+
config << " ACCESSOR #{@accessor.class.to_s} #{@accessor.args.map { |a| a.to_s.quote_if_necessary }.join(" ")}\n"
|
1055
|
+
end
|
1056
|
+
# TODO: Add TEMPLATE_ENCODED so this can always be done inline regardless of content
|
1057
|
+
if @template
|
1058
|
+
config << " TEMPLATE '#{@template}'"
|
1059
|
+
end
|
1011
1060
|
config << " ALLOW_SHORT\n" if @short_buffer_allowed
|
1012
1061
|
config << " HAZARDOUS #{@hazardous_description.to_s.quote_if_necessary}\n" if @hazardous
|
1013
1062
|
config << " DISABLE_MESSAGES\n" if @messages_disabled
|
@@ -1025,7 +1074,7 @@ module OpenC3
|
|
1025
1074
|
|
1026
1075
|
if @meta
|
1027
1076
|
@meta.each do |key, values|
|
1028
|
-
config << " META #{key.to_s.quote_if_necessary} #{values.map { |a| a
|
1077
|
+
config << " META #{key.to_s.quote_if_necessary} #{values.map { |a| a.to_s.quote_if_necessary }.join(" ")}\n"
|
1029
1078
|
end
|
1030
1079
|
end
|
1031
1080
|
|
@@ -1043,6 +1092,20 @@ module OpenC3
|
|
1043
1092
|
end
|
1044
1093
|
end
|
1045
1094
|
|
1095
|
+
if @response
|
1096
|
+
config << " RESPONSE #{@response[0].to_s.quote_if_necessary} #{@response[1].to_s.quote_if_necessary}"
|
1097
|
+
end
|
1098
|
+
if @error_response
|
1099
|
+
config << " ERROR_RESPONSE #{@error_response[0].to_s.quote_if_necessary} #{@error_response[1].to_s.quote_if_necessary}"
|
1100
|
+
end
|
1101
|
+
if @screen
|
1102
|
+
config << " SCREEN #{@screen[0].to_s.quote_if_necessary} #{@screen[1].to_s.quote_if_necessary}"
|
1103
|
+
end
|
1104
|
+
if @related_items
|
1105
|
+
@related_items.each do |target_name, packet_name, item_name|
|
1106
|
+
config << " RELATED_ITEM #{target_name.to_s.quote_if_necessary} #{packet_name.to_s.quote_if_necessary} #{item_name.to_s.quote_if_necessary}"
|
1107
|
+
end
|
1108
|
+
end
|
1046
1109
|
config
|
1047
1110
|
end
|
1048
1111
|
|
@@ -1086,6 +1149,18 @@ module OpenC3
|
|
1086
1149
|
items << item.as_json(*a)
|
1087
1150
|
end
|
1088
1151
|
end
|
1152
|
+
if @response
|
1153
|
+
config['response'] = @response
|
1154
|
+
end
|
1155
|
+
if @error_response
|
1156
|
+
config['error_response'] = @error_response
|
1157
|
+
end
|
1158
|
+
if @screen
|
1159
|
+
config['screen'] = @screen
|
1160
|
+
end
|
1161
|
+
if @related_items
|
1162
|
+
config['related_items'] = @related_items
|
1163
|
+
end
|
1089
1164
|
|
1090
1165
|
config
|
1091
1166
|
end
|
@@ -1117,6 +1192,19 @@ module OpenC3
|
|
1117
1192
|
hash['items'].each do |item|
|
1118
1193
|
packet.define(PacketItem.from_json(item))
|
1119
1194
|
end
|
1195
|
+
if hash['response']
|
1196
|
+
packet.response = hash['response']
|
1197
|
+
end
|
1198
|
+
if hash['error_response']
|
1199
|
+
packet.error_response = hash['error_response']
|
1200
|
+
end
|
1201
|
+
if hash['screen']
|
1202
|
+
packet.screen = hash['screen']
|
1203
|
+
end
|
1204
|
+
if hash['related_items']
|
1205
|
+
packet.related_items = hash['related_items']
|
1206
|
+
end
|
1207
|
+
|
1120
1208
|
packet
|
1121
1209
|
end
|
1122
1210
|
|
@@ -1144,8 +1232,6 @@ module OpenC3
|
|
1144
1232
|
json_hash
|
1145
1233
|
end
|
1146
1234
|
|
1147
|
-
protected
|
1148
|
-
|
1149
1235
|
# Performs packet specific processing on the packet.
|
1150
1236
|
# Intended to only be run once for each packet received
|
1151
1237
|
def process(buffer = @buffer)
|
@@ -1156,6 +1242,8 @@ module OpenC3
|
|
1156
1242
|
end
|
1157
1243
|
end
|
1158
1244
|
|
1245
|
+
protected
|
1246
|
+
|
1159
1247
|
def handle_limits_states(item, value)
|
1160
1248
|
# Retrieve limits state for the given value
|
1161
1249
|
limits_state = item.state_colors[value]
|
@@ -214,7 +214,8 @@ module OpenC3
|
|
214
214
|
'PARAMETER', 'ID_ITEM', 'ID_PARAMETER', 'ARRAY_ITEM', 'ARRAY_PARAMETER', 'APPEND_ITEM',\
|
215
215
|
'APPEND_PARAMETER', 'APPEND_ID_ITEM', 'APPEND_ID_PARAMETER', 'APPEND_ARRAY_ITEM',\
|
216
216
|
'APPEND_ARRAY_PARAMETER', 'ALLOW_SHORT', 'HAZARDOUS', 'PROCESSOR', 'META',\
|
217
|
-
'DISABLE_MESSAGES', 'HIDDEN', 'DISABLED', 'ACCESSOR', 'TEMPLATE', 'TEMPLATE_FILE'
|
217
|
+
'DISABLE_MESSAGES', 'HIDDEN', 'DISABLED', 'ACCESSOR', 'TEMPLATE', 'TEMPLATE_FILE',\
|
218
|
+
'RESPONSE', 'ERROR_RESPONSE', 'SCREEN', 'RELATED_ITEM'
|
218
219
|
raise parser.error("No current packet for #{keyword}") unless @current_packet
|
219
220
|
|
220
221
|
process_current_packet(parser, keyword, params)
|
@@ -460,7 +461,30 @@ module OpenC3
|
|
460
461
|
rescue Exception => err
|
461
462
|
raise parser.error(err)
|
462
463
|
end
|
464
|
+
|
465
|
+
when 'RESPONSE'
|
466
|
+
usage = "#{keyword} <Target Name> <Packet Name>"
|
467
|
+
parser.verify_num_parameters(2, 2, usage)
|
468
|
+
@current_packet.response = [params[0].upcase, params[1].upcase]
|
469
|
+
|
470
|
+
when 'ERROR_RESPONSE'
|
471
|
+
usage = "#{keyword} <Target Name> <Packet Name>"
|
472
|
+
parser.verify_num_parameters(2, 2, usage)
|
473
|
+
@current_packet.error_response = [params[0].upcase, params[1].upcase]
|
474
|
+
|
475
|
+
when 'SCREEN'
|
476
|
+
usage = "#{keyword} <Target Name> <Screen Name>"
|
477
|
+
parser.verify_num_parameters(2, 2, usage)
|
478
|
+
@current_packet.screen = [params[0].upcase, params[1].upcase]
|
479
|
+
|
480
|
+
when 'RELATED_ITEM'
|
481
|
+
usage = "#{keyword} <Target Name> <Packet Name> <Item Name>"
|
482
|
+
parser.verify_num_parameters(3, 3, usage)
|
483
|
+
@current_packet.related_items ||= []
|
484
|
+
@current_packet.related_items << [params[0].upcase, params[1].upcase, params[2].upcase]
|
485
|
+
|
463
486
|
end
|
487
|
+
|
464
488
|
end
|
465
489
|
|
466
490
|
def process_current_item(parser, keyword, params)
|
@@ -525,6 +525,17 @@ module OpenC3
|
|
525
525
|
# Private implementation details
|
526
526
|
###########################################################################
|
527
527
|
|
528
|
+
# This must be here for custom microservices that might block.
|
529
|
+
# Overriden by running_script.rb for script sleep
|
530
|
+
def openc3_script_sleep(sleep_time = nil)
|
531
|
+
if sleep_time
|
532
|
+
sleep(sleep_time)
|
533
|
+
else
|
534
|
+
prompt("Press any key to continue...")
|
535
|
+
end
|
536
|
+
return false
|
537
|
+
end
|
538
|
+
|
528
539
|
# Creates a string with the parameters upcased
|
529
540
|
def _upcase(target_name, packet_name, item_name)
|
530
541
|
"#{target_name.upcase} #{packet_name.upcase} #{item_name.upcase}"
|
data/lib/openc3/script/script.rb
CHANGED
@@ -93,17 +93,8 @@ module OpenC3
|
|
93
93
|
$script_runner_api_server = nil
|
94
94
|
end
|
95
95
|
|
96
|
-
# This isn't part of the public API because users should use wait()
|
97
|
-
def openc3_script_sleep(sleep_time = nil)
|
98
|
-
if sleep_time
|
99
|
-
sleep(sleep_time)
|
100
|
-
else
|
101
|
-
prompt("Press any key to continue...")
|
102
|
-
end
|
103
|
-
return false
|
104
|
-
end
|
105
|
-
|
106
96
|
# Internal method used in scripts when encountering a hazardous command
|
97
|
+
# Not part of public APIs but must be implemented here
|
107
98
|
def prompt_for_hazardous(target_name, cmd_name, hazardous_description)
|
108
99
|
loop do
|
109
100
|
message = "Warning: Command #{target_name} #{cmd_name} is Hazardous. "
|
@@ -140,6 +131,7 @@ module OpenC3
|
|
140
131
|
default = ''
|
141
132
|
if blank_or_default != true && blank_or_default != false
|
142
133
|
question << " (default = #{blank_or_default})"
|
134
|
+
default = blank_or_default.to_s
|
143
135
|
allow_blank = true
|
144
136
|
else
|
145
137
|
allow_blank = blank_or_default
|
@@ -150,7 +142,9 @@ module OpenC3
|
|
150
142
|
answer.chomp!
|
151
143
|
break if allow_blank
|
152
144
|
end
|
153
|
-
|
145
|
+
if answer.empty? and !default.empty?
|
146
|
+
answer = default
|
147
|
+
end
|
154
148
|
return answer
|
155
149
|
end
|
156
150
|
|
@@ -162,7 +156,7 @@ module OpenC3
|
|
162
156
|
|
163
157
|
def message_box(string, *buttons, **options)
|
164
158
|
print "#{string} (#{buttons.join(", ")}): "
|
165
|
-
print "Details: #{details}\n" if details
|
159
|
+
print "Details: #{details}\n" if options['details']
|
166
160
|
gets.chomp
|
167
161
|
end
|
168
162
|
|
@@ -160,5 +160,24 @@ module OpenC3
|
|
160
160
|
@pipe_writer.write('.')
|
161
161
|
@connected = false
|
162
162
|
end
|
163
|
+
|
164
|
+
def set_option(option_name, option_values)
|
165
|
+
option_name_upcase = option_name.upcase
|
166
|
+
|
167
|
+
case option_name_upcase
|
168
|
+
when 'KEEPALIVE'
|
169
|
+
@write_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
|
170
|
+
@read_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
|
171
|
+
when 'KEEPCNT'
|
172
|
+
@write_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT, Integer(option_values[0]))
|
173
|
+
@read_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT, Integer(option_values[0]))
|
174
|
+
when 'KEEPIDLE'
|
175
|
+
@write_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE, Integer(option_values[0]))
|
176
|
+
@read_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE, Integer(option_values[0]))
|
177
|
+
when 'KEEPINTVL'
|
178
|
+
@write_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL, Integer(option_values[0]))
|
179
|
+
@read_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL, Integer(option_values[0]))
|
180
|
+
end
|
181
|
+
end
|
163
182
|
end
|
164
183
|
end
|
data/lib/openc3/system/system.rb
CHANGED
@@ -92,6 +92,18 @@ module OpenC3
|
|
92
92
|
zip_file.extract(entry, path) unless File.exist?(path)
|
93
93
|
end
|
94
94
|
end
|
95
|
+
|
96
|
+
# Now add any modifications in targets_modified/TARGET/cmd_tlm
|
97
|
+
# This adds support for remembering dynamically created packets
|
98
|
+
# target.txt must be configured to either use all files in cmd_tlm folder (default)
|
99
|
+
# or have a predetermined empty file like dynamic_tlm.txt
|
100
|
+
bucket_path = "#{scope}/targets_modified/#{target_name}/cmd_tlm"
|
101
|
+
dirs, files = bucket.list_files(bucket: ENV['OPENC3_CONFIG_BUCKET'], path: bucket_path)
|
102
|
+
files.each do |file|
|
103
|
+
bucket_key = File.join(bucket_path, file['name'])
|
104
|
+
local_path = "#{base_dir}/targets/#{target_name}/cmd_tlm/#{file['name']}"
|
105
|
+
bucket.get_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: bucket_key, path: local_path)
|
106
|
+
end
|
95
107
|
end
|
96
108
|
|
97
109
|
# Build System from targets
|
@@ -119,7 +131,7 @@ module OpenC3
|
|
119
131
|
# @param target_names [Array of target names]
|
120
132
|
# @param target_config_dir Directory where target config folders are
|
121
133
|
def initialize(target_names, target_config_dir)
|
122
|
-
OpenC3.add_to_search_path(target_config_dir, true)
|
134
|
+
OpenC3.add_to_search_path(target_config_dir, true) if target_config_dir
|
123
135
|
@targets = {}
|
124
136
|
@packet_config = PacketConfig.new
|
125
137
|
@commands = Commands.new(@packet_config)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2024 OpenC3, Inc.
|
4
4
|
# All Rights Reserved.
|
5
5
|
#
|
6
6
|
# This program is free software; you can modify and/or redistribute it
|
@@ -116,6 +116,20 @@ module OpenC3
|
|
116
116
|
false
|
117
117
|
end
|
118
118
|
|
119
|
+
if @@language == 'py'
|
120
|
+
# If we're using Python create a requirements.txt and list it in the gemspec
|
121
|
+
# However, don't write over an existing file they may have already created
|
122
|
+
unless File.exist?("requirements.txt")
|
123
|
+
File.open("requirements.txt", 'w') do |file|
|
124
|
+
file.puts "# Python dependencies"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
gemspec_filename = Dir['*.gemspec'][0]
|
128
|
+
gemspec = File.read(gemspec_filename)
|
129
|
+
gemspec.gsub!('plugin.txt', 'plugin.txt requirements.txt')
|
130
|
+
File.write(gemspec_filename, gemspec)
|
131
|
+
end
|
132
|
+
|
119
133
|
# Add this target to plugin.txt
|
120
134
|
File.open("plugin.txt", 'a') do |file|
|
121
135
|
file.puts <<~DOC
|
@@ -252,7 +252,7 @@ module OpenC3
|
|
252
252
|
# New install of same plugin - Leave it alone
|
253
253
|
end
|
254
254
|
else
|
255
|
-
# No
|
255
|
+
# No existing instance.json, but we found the same gem
|
256
256
|
# This shouldn't happen without users using this wrong
|
257
257
|
# We will update
|
258
258
|
found = true
|
@@ -0,0 +1,126 @@
|
|
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/utilities/store'
|
20
|
+
|
21
|
+
module OpenC3
|
22
|
+
class StoreQueued
|
23
|
+
# Variable that holds the singleton instance
|
24
|
+
@instance = nil
|
25
|
+
|
26
|
+
# Mutex used to ensure that only one instance is created
|
27
|
+
@@instance_mutex = Mutex.new
|
28
|
+
|
29
|
+
# Get the singleton instance
|
30
|
+
# Sets the update interval to 1 second by default
|
31
|
+
def self.instance(update_interval = 1) # seconds
|
32
|
+
return @instance if @instance
|
33
|
+
|
34
|
+
@@instance_mutex.synchronize do
|
35
|
+
@instance ||= self.new(update_interval)
|
36
|
+
return @instance
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Delegate all unknown class methods to delegate to the instance
|
41
|
+
def self.method_missing(message, *args, **kwargs, &)
|
42
|
+
self.instance.public_send(message, *args, **kwargs, &)
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(update_interval)
|
46
|
+
@update_interval = update_interval
|
47
|
+
@store = store_instance()
|
48
|
+
# Queue to hold the store requests
|
49
|
+
@store_queue = Queue.new
|
50
|
+
# Sleeper used to delay update thread
|
51
|
+
@update_sleeper = Sleeper.new
|
52
|
+
|
53
|
+
at_exit() do
|
54
|
+
shutdown()
|
55
|
+
end
|
56
|
+
|
57
|
+
# Thread used to call methods on the store
|
58
|
+
@update_thread = OpenC3.safe_thread(self.class.to_s) do
|
59
|
+
store_thread_body()
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def store_thread_body
|
64
|
+
while true
|
65
|
+
start_time = Time.now
|
66
|
+
|
67
|
+
unless @store_queue.empty?
|
68
|
+
# Pipeline the requests to redis to improve performance
|
69
|
+
@store.pipelined do
|
70
|
+
while !@store_queue.empty?
|
71
|
+
action = @store_queue.pop()
|
72
|
+
@store.method_missing(action.message, *action.args, **action.kwargs, &action.block)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Only check whether to update at a set interval
|
78
|
+
run_time = Time.now - start_time
|
79
|
+
sleep_time = @update_interval - run_time
|
80
|
+
sleep_time = 0 if sleep_time < 0
|
81
|
+
break if @update_sleeper.sleep(sleep_time)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def shutdown
|
86
|
+
@update_sleeper.cancel if @update_sleeper
|
87
|
+
OpenC3.kill_thread(self, @update_thread) if @update_thread
|
88
|
+
@update_thread = nil
|
89
|
+
# Drain the queue before shutdown
|
90
|
+
unless @store_queue.empty?
|
91
|
+
# Pipeline the requests to redis to improve performance
|
92
|
+
@store.pipelined do
|
93
|
+
while !@store_queue.empty?
|
94
|
+
action = @store_queue.pop()
|
95
|
+
@store.method_missing(action.message, *action.args, **action.kwargs, &action.block)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Record the message for pipelining by the thread
|
102
|
+
def method_missing(message, *args, **kwargs, &block)
|
103
|
+
o = OpenStruct.new
|
104
|
+
o.message = message
|
105
|
+
o.args = args
|
106
|
+
o.kwargs = kwargs
|
107
|
+
o.block = block
|
108
|
+
@store_queue.push(o)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns the store we're working with
|
112
|
+
def store_instance
|
113
|
+
Store.instance
|
114
|
+
end
|
115
|
+
|
116
|
+
def graceful_kill
|
117
|
+
# Do nothing
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class EphemeralStoreQueued < StoreQueued
|
122
|
+
def store_instance
|
123
|
+
EphemeralStore.instance
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/openc3/version.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
|
-
OPENC3_VERSION = '5.
|
3
|
+
OPENC3_VERSION = '5.14.0'
|
4
4
|
module OpenC3
|
5
5
|
module Version
|
6
6
|
MAJOR = '5'
|
7
|
-
MINOR = '
|
7
|
+
MINOR = '14'
|
8
8
|
PATCH = '0'
|
9
9
|
OTHER = ''
|
10
|
-
BUILD = '
|
10
|
+
BUILD = 'dd31e4853fa50ed08ee3100e43e75849617d0a47'
|
11
11
|
end
|
12
|
-
VERSION = '5.
|
13
|
-
GEM_VERSION = '5.
|
12
|
+
VERSION = '5.14.0'
|
13
|
+
GEM_VERSION = '5.14.0'
|
14
14
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
2
|
|
3
3
|
# Create the overall gemspec
|
4
|
-
|
4
|
+
Gem::Specification.new do |s|
|
5
5
|
s.name = '<%= plugin_name %>'
|
6
6
|
s.summary = 'OpenC3 <%= plugin_name %> plugin'
|
7
7
|
s.description = <<-EOF
|
@@ -10,7 +10,7 @@ spec = Gem::Specification.new do |s|
|
|
10
10
|
s.license = 'MIT'
|
11
11
|
s.authors = ['Anonymous']
|
12
12
|
s.email = ['name@domain.com']
|
13
|
-
s.homepage = 'https://github.com/OpenC3/
|
13
|
+
s.homepage = 'https://github.com/OpenC3/cosmos'
|
14
14
|
s.platform = Gem::Platform::RUBY
|
15
15
|
|
16
16
|
if ENV['VERSION']
|
@@ -0,0 +1 @@
|
|
1
|
+
Put image files in this directory for use in Telemetry Viewer Canvas Image widgets such as CANVASIMAGE and CANVASIMAGEVALUE.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "<%= tool_name %>",
|
3
|
-
"version": "5.
|
3
|
+
"version": "5.14.0",
|
4
4
|
"scripts": {
|
5
5
|
"ng": "ng",
|
6
6
|
"start": "ng serve",
|
@@ -12,23 +12,23 @@
|
|
12
12
|
},
|
13
13
|
"private": true,
|
14
14
|
"dependencies": {
|
15
|
-
"@openc3/tool-common": "5.
|
16
|
-
"@angular/animations": "^17.0.
|
17
|
-
"@angular/cdk": "^17.0.
|
18
|
-
"@angular/common": "^17.0.
|
19
|
-
"@angular/compiler": "^17.0.
|
20
|
-
"@angular/core": "^17.0.
|
21
|
-
"@angular/forms": "^17.0.
|
22
|
-
"@angular/material": "17.0.
|
23
|
-
"@angular/platform-browser": "^17.0.
|
24
|
-
"@angular/platform-browser-dynamic": "^17.0.
|
25
|
-
"@angular/router": "^17.0.
|
26
|
-
"@astrouxds/astro-web-components": "7.
|
15
|
+
"@openc3/tool-common": "5.14.0",
|
16
|
+
"@angular/animations": "^17.0.8",
|
17
|
+
"@angular/cdk": "^17.0.4",
|
18
|
+
"@angular/common": "^17.0.8",
|
19
|
+
"@angular/compiler": "^17.0.8",
|
20
|
+
"@angular/core": "^17.0.8",
|
21
|
+
"@angular/forms": "^17.0.8",
|
22
|
+
"@angular/material": "17.0.4",
|
23
|
+
"@angular/platform-browser": "^17.0.8",
|
24
|
+
"@angular/platform-browser-dynamic": "^17.0.8",
|
25
|
+
"@angular/router": "^17.0.8",
|
26
|
+
"@astrouxds/astro-web-components": "7.20.0",
|
27
27
|
"rxjs": "~7.8.0",
|
28
|
-
"single-spa": "
|
28
|
+
"single-spa": "5.9.5",
|
29
29
|
"single-spa-angular": "^9.0.1",
|
30
30
|
"tslib": "^2.6.2",
|
31
|
-
"zone.js": "~0.14.
|
31
|
+
"zone.js": "~0.14.3"
|
32
32
|
},
|
33
33
|
"devDependencies": {
|
34
34
|
"@angular-builders/custom-webpack": "17.0.0",
|