openc3 5.20.0 → 6.0.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 +12 -120
- data/data/config/command_modifiers.yaml +13 -1
- data/data/config/interface_modifiers.yaml +21 -4
- data/data/config/item_modifiers.yaml +1 -1
- data/data/config/microservice.yaml +15 -2
- data/data/config/param_item_modifiers.yaml +1 -1
- data/data/config/parameter_modifiers.yaml +1 -1
- data/data/config/table_manager.yaml +2 -2
- data/data/config/target.yaml +11 -0
- data/data/config/telemetry_modifiers.yaml +17 -1
- data/data/config/tool.yaml +12 -0
- data/data/config/widgets.yaml +13 -17
- data/lib/openc3/accessors/form_accessor.rb +4 -3
- data/lib/openc3/accessors/html_accessor.rb +3 -3
- data/lib/openc3/accessors/http_accessor.rb +13 -13
- data/lib/openc3/accessors/xml_accessor.rb +16 -4
- data/lib/openc3/api/target_api.rb +0 -30
- data/lib/openc3/config/config_parser.rb +6 -3
- data/lib/openc3/core_ext/array.rb +0 -16
- data/lib/openc3/core_ext.rb +0 -1
- data/lib/openc3/interfaces/file_interface.rb +198 -0
- data/lib/openc3/interfaces/http_client_interface.rb +71 -39
- data/lib/openc3/interfaces/http_server_interface.rb +0 -7
- data/lib/openc3/interfaces/interface.rb +2 -0
- data/lib/openc3/interfaces/mqtt_interface.rb +32 -15
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +19 -4
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +7 -0
- data/lib/openc3/interfaces/serial_interface.rb +1 -0
- data/lib/openc3/interfaces.rb +2 -4
- data/lib/openc3/microservices/multi_microservice.rb +3 -3
- data/lib/openc3/migrations/20241208080000_no_critical_cmd.rb +31 -0
- data/lib/openc3/migrations/20241208080001_no_trigger_group.rb +46 -0
- data/lib/openc3/models/interface_model.rb +9 -3
- data/lib/openc3/models/microservice_model.rb +8 -1
- data/lib/openc3/models/plugin_model.rb +6 -1
- data/lib/openc3/models/python_package_model.rb +6 -1
- data/lib/openc3/models/reaction_model.rb +14 -10
- data/lib/openc3/models/scope_model.rb +60 -42
- data/lib/openc3/models/target_model.rb +17 -1
- data/lib/openc3/models/timeline_model.rb +17 -5
- data/lib/openc3/models/tool_model.rb +15 -3
- data/lib/openc3/models/trigger_group_model.rb +6 -3
- data/lib/openc3/operators/microservice_operator.rb +8 -0
- data/lib/openc3/packets/commands.rb +17 -6
- data/lib/openc3/packets/limits.rb +0 -12
- data/lib/openc3/packets/packet.rb +1 -1
- data/lib/openc3/packets/packet_item.rb +30 -36
- data/lib/openc3/packets/structure_item.rb +2 -2
- data/lib/openc3/script/script.rb +0 -10
- data/lib/openc3/script/web_socket_api.rb +2 -2
- data/lib/openc3/streams/mqtt_stream.rb +41 -33
- data/lib/openc3/streams/serial_stream.rb +27 -27
- data/lib/openc3/streams/stream.rb +17 -17
- data/lib/openc3/streams/tcpip_client_stream.rb +1 -1
- data/lib/openc3/streams/tcpip_socket_stream.rb +19 -19
- data/lib/openc3/system/system.rb +1 -1
- data/lib/openc3/system.rb +2 -3
- data/lib/openc3/tools/table_manager/table.rb +2 -2
- data/lib/openc3/tools/table_manager/table_parser.rb +1 -1
- data/lib/openc3/top_level.rb +0 -5
- data/lib/openc3/topics/command_decom_topic.rb +0 -7
- data/lib/openc3/utilities/bucket_utilities.rb +1 -1
- data/lib/openc3/utilities/cli_generator.rb +0 -1
- data/lib/openc3/version.rb +6 -6
- data/templates/plugin/README.md +1 -1
- data/templates/target/targets/TARGET/lib/target.rb +1 -1
- data/templates/tool_angular/package.json +8 -8
- data/templates/tool_angular/src/app/app.component.html +4 -13
- data/templates/tool_angular/src/app/app.component.scss +5 -13
- data/templates/tool_angular/src/app/app.component.ts +5 -4
- data/templates/tool_angular/src/app/custom-overlay-container.ts +2 -2
- data/templates/tool_angular/src/app/openc3-api.d.ts +1 -1
- data/templates/tool_angular/src/main.single-spa.ts +1 -1
- data/templates/tool_react/package.json +1 -0
- data/templates/tool_react/src/root.component.js +1 -1
- data/templates/tool_svelte/package.json +11 -9
- data/templates/tool_svelte/rollup.config.js +2 -0
- data/templates/tool_svelte/src/App.svelte +2 -2
- data/templates/tool_vue/eslint.config.mjs +68 -0
- data/templates/tool_vue/jsconfig.json +1 -1
- data/templates/tool_vue/package.json +26 -43
- data/templates/tool_vue/src/App.vue +3 -5
- data/templates/tool_vue/src/main.js +12 -23
- data/templates/tool_vue/src/router.js +19 -18
- data/templates/tool_vue/src/tools/tool_name/tool_name.vue +2 -2
- data/templates/tool_vue/vite.config.js +52 -0
- data/templates/widget/package.json +19 -26
- data/templates/widget/src/Widget.vue +13 -15
- data/templates/widget/vite.config.js +26 -0
- metadata +10 -41
- data/lib/openc3/core_ext/hash.rb +0 -40
- data/lib/openc3/core_ext/httpclient.rb +0 -11
- data/lib/openc3/interfaces/linc_interface.rb +0 -480
- data/lib/openc3/interfaces/protocols/override_protocol.rb +0 -4
- data/lib/openc3/microservices/critical_cmd_microservice.rb +0 -74
- data/lib/openc3/microservices/reaction_microservice.rb +0 -607
- data/lib/openc3/microservices/timeline_microservice.rb +0 -398
- data/lib/openc3/microservices/trigger_group_microservice.rb +0 -698
- data/lib/openc3/migrations/20230615000000_autonomic.rb +0 -86
- data/lib/openc3/migrations/20240915000000_activity_uuid.rb +0 -28
- data/lib/openc3/migrations/20241016000000_scope_critical_cmd.rb +0 -24
- data/lib/openc3/system/system_config.rb +0 -413
- data/templates/tool_svelte/src/services/api.js +0 -92
- data/templates/tool_svelte/src/services/axios.js +0 -85
- data/templates/tool_svelte/src/services/cable.js +0 -65
- data/templates/tool_svelte/src/services/config-parser.js +0 -198
- data/templates/tool_svelte/src/services/openc3-api.js +0 -606
- data/templates/tool_vue/.eslintrc.js +0 -43
- data/templates/tool_vue/babel.config.json +0 -11
- data/templates/tool_vue/vue.config.js +0 -38
- data/templates/widget/.eslintrc.js +0 -43
- data/templates/widget/babel.config.json +0 -11
- data/templates/widget/vue.config.js +0 -28
- /data/templates/tool_vue/{.prettierrc.js → .prettierrc.cjs} +0 -0
- /data/templates/widget/{.prettierrc.js → .prettierrc.cjs} +0 -0
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'openc3/utilities/migration'
|
2
|
-
require 'openc3/models/trigger_group_model'
|
3
|
-
require 'openc3/models/trigger_model'
|
4
|
-
require 'openc3/models/reaction_model'
|
5
|
-
|
6
|
-
module OpenC3
|
7
|
-
class Autonomic < Migration
|
8
|
-
def self.run
|
9
|
-
ScopeModel.names.each do |scope|
|
10
|
-
puts "Processing scope #{scope}"
|
11
|
-
|
12
|
-
# Update all old TriggerModels just so they work when we delete the ReactionModel
|
13
|
-
# Because the ReactionModel verifies the triggers
|
14
|
-
delete_all_triggers = false
|
15
|
-
groups = TriggerGroupModel.all(scope: scope)
|
16
|
-
groups.each do |key, group_hash|
|
17
|
-
puts "Processing group #{group_hash['name']}"
|
18
|
-
if group_hash.has_key?('color')
|
19
|
-
group_hash.delete('color')
|
20
|
-
group = TriggerGroupModel.from_json(group_hash, name: group_hash['name'], scope: scope)
|
21
|
-
group.update()
|
22
|
-
end
|
23
|
-
TriggerModel.all(group: group_hash['name'], scope: scope).each do |key, model_hash|
|
24
|
-
if model_hash.has_key?('description') or model_hash.has_key?('active')
|
25
|
-
puts "Updating TriggerModel: #{model_hash['name']}"
|
26
|
-
model_hash.delete('description')
|
27
|
-
model_hash.delete('active')
|
28
|
-
model_hash['left'] = {'type' => 'item', 'target' => 'TGT', 'packet' => 'PKT', 'item' => 'ITEM', 'valueType' => 'CONVERTED'}
|
29
|
-
model_hash['operator'] = 'CHANGES'
|
30
|
-
model_hash['right'] = nil
|
31
|
-
TriggerModel.from_json(model_hash, name: model_hash['name'], scope: scope).update()
|
32
|
-
delete_all_triggers = true
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Remove all old ReactionModels
|
38
|
-
ReactionModel.all(scope: scope).each do |key, model_hash|
|
39
|
-
if model_hash.has_key?('description') or model_hash.has_key?('review') or model_hash.has_key?('active')
|
40
|
-
# Can't delete directly because delete calls get which calls from_json which calls new
|
41
|
-
# and at that point we get missing keyword: :triggerLevel (ArgumentError)
|
42
|
-
# So update to add triggerLevel
|
43
|
-
model_hash['triggerLevel'] = 'EDGE'
|
44
|
-
model_hash.delete('description')
|
45
|
-
model_hash.delete('review')
|
46
|
-
model_hash.delete('active')
|
47
|
-
ReactionModel.from_json(model_hash, name: model_hash['name'], scope: scope).update()
|
48
|
-
puts "Deleting ReactionModel: #{model_hash['name']}"
|
49
|
-
ReactionModel.delete(name: model_hash['name'], scope: scope)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Remove all old TriggerModels and TriggerGroupModels
|
54
|
-
if delete_all_triggers
|
55
|
-
groups = TriggerGroupModel.all(scope: scope)
|
56
|
-
groups.each do |key, group_hash|
|
57
|
-
TriggerModel.all(group: group_hash['name'], scope: scope).each do |key, trigger_hash|
|
58
|
-
puts "Deleting TriggerModel: #{trigger_hash['name']}"
|
59
|
-
TriggerModel.delete(name: trigger_hash['name'], group: group_hash['name'], scope: scope)
|
60
|
-
end
|
61
|
-
group = TriggerGroupModel.from_json(group_hash, name: group_hash['name'], scope: scope)
|
62
|
-
group.undeploy()
|
63
|
-
puts "Deleting TriggerGroupModel: #{group_hash['name']}"
|
64
|
-
TriggerGroupModel.delete(name: group_hash['name'], scope: scope)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Create DEFAULT trigger group model
|
69
|
-
model = TriggerGroupModel.get(name: 'DEFAULT', scope: scope)
|
70
|
-
unless model
|
71
|
-
puts "Creating TriggerGroupModel: DEFAULT"
|
72
|
-
model = TriggerGroupModel.new(name: 'DEFAULT', scope: scope)
|
73
|
-
model.create()
|
74
|
-
model.deploy()
|
75
|
-
end
|
76
|
-
end
|
77
|
-
rescue => error
|
78
|
-
puts error.message
|
79
|
-
puts error.backtrace
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
unless ENV['OPENC3_NO_MIGRATE']
|
85
|
-
OpenC3::Autonomic.run
|
86
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'openc3/utilities/migration'
|
2
|
-
require 'openc3/models/scope_model'
|
3
|
-
require 'openc3/models/timeline_model'
|
4
|
-
|
5
|
-
module OpenC3
|
6
|
-
class ActivityUuid < Migration
|
7
|
-
def self.run
|
8
|
-
ScopeModel.names.each do |scope|
|
9
|
-
TimelineModel.names.each do |key|
|
10
|
-
name = key.split('__').last
|
11
|
-
json = Store.zrange("#{scope}#{ActivityModel::PRIMARY_KEY}__#{name}", 0, -1)
|
12
|
-
parsed = json.map { |value| JSON.parse(value, :allow_nan => true, :create_additions => true) }
|
13
|
-
parsed.each_with_index do |activity, index|
|
14
|
-
if activity['uuid'].nil?
|
15
|
-
activity['uuid'] = SecureRandom.uuid
|
16
|
-
Store.zrem("#{scope}#{ActivityModel::PRIMARY_KEY}__#{name}", json[index])
|
17
|
-
Store.zadd("#{scope}#{ActivityModel::PRIMARY_KEY}__#{name}", activity['start'], JSON.generate(activity))
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
unless ENV['OPENC3_NO_MIGRATE']
|
27
|
-
OpenC3::ActivityUuid.run
|
28
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'openc3/utilities/migration'
|
2
|
-
require 'openc3/models/scope_model'
|
3
|
-
|
4
|
-
module OpenC3
|
5
|
-
class ScopeCriticalCmd < Migration
|
6
|
-
def self.run
|
7
|
-
ScopeModel.names.each do |scope|
|
8
|
-
existing_model = MicroserviceModel.get_model(name: "#{scope}__CRITICALCMD__#{scope}", scope: scope)
|
9
|
-
if not existing_model
|
10
|
-
scope_model = ScopeModel.get_model(name: scope)
|
11
|
-
parent = "#{scope}__SCOPEMULTI__#{scope}"
|
12
|
-
scope_model.deploy_critical_cmd_microservice("/notexist", {}, parent)
|
13
|
-
microservice_model = MicroserviceModel.get_model(name: parent, scope: scope)
|
14
|
-
microservice_model.cmd << "#{scope}__CRITICALCMD__#{scope}"
|
15
|
-
microservice_model.update
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
unless ENV['OPENC3_NO_MIGRATE']
|
23
|
-
OpenC3::ScopeCriticalCmd.run
|
24
|
-
end
|
@@ -1,413 +0,0 @@
|
|
1
|
-
# encoding: ascii-8bit
|
2
|
-
|
3
|
-
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
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
|
-
# Modified by OpenC3, Inc.
|
17
|
-
# All changes Copyright 2024, OpenC3, Inc.
|
18
|
-
# All Rights Reserved
|
19
|
-
#
|
20
|
-
# This file may also be used under the terms of a commercial license
|
21
|
-
# if purchased from OpenC3, Inc.
|
22
|
-
|
23
|
-
require 'openc3/config/config_parser'
|
24
|
-
require 'openc3/packets/packet_config'
|
25
|
-
require 'openc3/packets/commands'
|
26
|
-
require 'openc3/packets/telemetry'
|
27
|
-
require 'openc3/packets/limits'
|
28
|
-
require 'openc3/system/target'
|
29
|
-
require 'openc3/logs'
|
30
|
-
require 'fileutils'
|
31
|
-
require 'openc3/utilities/zip'
|
32
|
-
require 'bundler'
|
33
|
-
|
34
|
-
module OpenC3
|
35
|
-
# System is the primary entry point into the OpenC3 framework. It captures
|
36
|
-
# system wide configuration items such as the available ports and paths to
|
37
|
-
# various files used by the system. The #commands, #telemetry, and #limits
|
38
|
-
# class variables are the primary access points for applications. The
|
39
|
-
# #targets variable provides access to all the targets defined by the system.
|
40
|
-
# Its primary responsibily is to load the system configuration file and
|
41
|
-
# create all the Target instances. It also saves and restores configurations
|
42
|
-
# using a hashing checksum over the entire configuration to detect changes.
|
43
|
-
class SystemConfig
|
44
|
-
# @return [String] Base path of the configuration
|
45
|
-
attr_reader :userpath
|
46
|
-
# @return [Boolean] Whether to use sound for alerts
|
47
|
-
attr_reader :sound
|
48
|
-
# @return [Boolean] Whether to use DNS to lookup IP addresses or not
|
49
|
-
attr_reader :use_dns
|
50
|
-
# @return [Hash<String,Target>] Hash of all the known targets
|
51
|
-
attr_reader :targets
|
52
|
-
# @return [Integer] The number of seconds before a telemetry packet is considered stale
|
53
|
-
attr_reader :staleness_seconds
|
54
|
-
# @return [Boolean] Whether to use UTC or local times
|
55
|
-
attr_reader :use_utc
|
56
|
-
# @return [Hash<String,String>] Hash of the text/color to use for the classificaiton banner
|
57
|
-
attr_reader :classificiation_banner
|
58
|
-
|
59
|
-
# @param filename [String] Full path to the system configuration file to
|
60
|
-
# read.
|
61
|
-
def initialize(filename)
|
62
|
-
reset_variables(filename)
|
63
|
-
end
|
64
|
-
|
65
|
-
# Resets the System's internal state to defaults.
|
66
|
-
#
|
67
|
-
# @param filename [String] Path to system.txt config file to process. Defaults to config/system/system.txt
|
68
|
-
def reset_variables(filename)
|
69
|
-
@targets = {}
|
70
|
-
@config = nil
|
71
|
-
@commands = nil
|
72
|
-
@telemetry = nil
|
73
|
-
@limits = nil
|
74
|
-
@sound = false
|
75
|
-
@use_dns = false
|
76
|
-
@staleness_seconds = 30
|
77
|
-
@use_utc = false
|
78
|
-
@meta_init_filename = nil
|
79
|
-
@userpath = File.expand_path(File.join(File.dirname(filename), '..', '..'))
|
80
|
-
process_file(filename, File.join(@userpath, 'config', 'targets'))
|
81
|
-
@initial_filename = filename
|
82
|
-
@initial_config = nil
|
83
|
-
@config_blacklist = {}
|
84
|
-
end
|
85
|
-
|
86
|
-
# Process the system.txt configuration file
|
87
|
-
#
|
88
|
-
# @param filename [String] The configuration file
|
89
|
-
# @param targets_config_dir [String] The configuration directory to
|
90
|
-
# search for the target command and telemetry files.
|
91
|
-
def process_file(filename, targets_config_dir)
|
92
|
-
parser = ConfigParser.new("https://docs.openc3.com/docs")
|
93
|
-
|
94
|
-
# First pass - Everything except targets
|
95
|
-
parser.parse_file(filename) do |keyword, parameters|
|
96
|
-
case keyword
|
97
|
-
when 'AUTO_DECLARE_TARGETS', 'DECLARE_TARGET', 'DECLARE_GEM_TARGET', 'DECLARE_GEM_MULTI_TARGET'
|
98
|
-
# Will be handled by second pass
|
99
|
-
|
100
|
-
when 'PORT', 'LISTEN_HOST', 'CONNECT_HOST', 'PATH', 'DEFAULT_PACKET_LOG_WRITER', 'DEFAULT_PACKET_LOG_READER',
|
101
|
-
'ALLOW_ACCESS', 'ADD_HASH_FILE', 'ADD_MD5_FILE', 'HASHING_ALGORITHM'
|
102
|
-
# Not used by OpenC3 5
|
103
|
-
|
104
|
-
when 'ENABLE_SOUND'
|
105
|
-
usage = "#{keyword}"
|
106
|
-
parser.verify_num_parameters(0, 0, usage)
|
107
|
-
@sound = true
|
108
|
-
|
109
|
-
when 'DISABLE_DNS'
|
110
|
-
usage = "#{keyword}"
|
111
|
-
parser.verify_num_parameters(0, 0, usage)
|
112
|
-
@use_dns = false
|
113
|
-
|
114
|
-
when 'ENABLE_DNS'
|
115
|
-
usage = "#{keyword}"
|
116
|
-
parser.verify_num_parameters(0, 0, usage)
|
117
|
-
@use_dns = true
|
118
|
-
|
119
|
-
when 'STALENESS_SECONDS'
|
120
|
-
parser.verify_num_parameters(1, 1, "#{keyword} <Value in Seconds>")
|
121
|
-
@staleness_seconds = Integer(parameters[0])
|
122
|
-
|
123
|
-
when 'META_INIT'
|
124
|
-
parser.verify_num_parameters(1, 1, "#{keyword} <Filename>")
|
125
|
-
@meta_init_filename = ConfigParser.handle_nil(parameters[0])
|
126
|
-
|
127
|
-
when 'TIME_ZONE_UTC'
|
128
|
-
parser.verify_num_parameters(0, 0, "#{keyword}")
|
129
|
-
@use_utc = true
|
130
|
-
|
131
|
-
when 'CLASSIFICATION'
|
132
|
-
parser.verify_num_parameters(2, 4, "#{keyword} <Display_Text> <Color Name|Red> <Green> <Blue>")
|
133
|
-
# Determine if the OpenC3 color already exists, otherwise create a new one
|
134
|
-
if OpenC3.constants.include? parameters[1].upcase.to_sym
|
135
|
-
# We were given a named color that already exists in OpenC3
|
136
|
-
color = parameters[1].upcase
|
137
|
-
else
|
138
|
-
if parameters.length < 4
|
139
|
-
# We were given a named color, but it didn't exist in OpenC3 already
|
140
|
-
color = OpenC3.getColor(parameters[1].upcase)
|
141
|
-
else
|
142
|
-
# We were given RGB values
|
143
|
-
color = OpenC3.getColor(parameters[1], parameters[2], parameters[3])
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
@classificiation_banner = { 'display_text' => parameters[0],
|
148
|
-
'color' => color }
|
149
|
-
|
150
|
-
else
|
151
|
-
# blank lines will have a nil keyword and should not raise an exception
|
152
|
-
raise parser.error("Unknown keyword '#{keyword}'") if keyword
|
153
|
-
end # case keyword
|
154
|
-
end # parser.parse_file
|
155
|
-
|
156
|
-
# Explicitly set up time to use UTC or local
|
157
|
-
if @use_utc
|
158
|
-
Time.use_utc()
|
159
|
-
else
|
160
|
-
Time.use_local()
|
161
|
-
end
|
162
|
-
|
163
|
-
# Second pass - Process targets
|
164
|
-
process_targets(parser, filename, targets_config_dir)
|
165
|
-
end # def process_file
|
166
|
-
|
167
|
-
# Parse the system.txt configuration file looking for keywords associated
|
168
|
-
# with targets and create all the Target instances in the system.
|
169
|
-
#
|
170
|
-
# @param parser [ConfigParser] Parser created by process_file
|
171
|
-
# @param filename (see #process_file)
|
172
|
-
# @param targets_config_dir (see #process_file)
|
173
|
-
def process_targets(parser, filename, targets_config_dir)
|
174
|
-
parser.parse_file(filename) do |keyword, parameters|
|
175
|
-
case keyword
|
176
|
-
when 'AUTO_DECLARE_TARGETS'
|
177
|
-
usage = "#{keyword}"
|
178
|
-
parser.verify_num_parameters(0, 0, usage)
|
179
|
-
path = File.join(@userpath, 'config', 'targets')
|
180
|
-
unless File.exist? path
|
181
|
-
raise parser.error("#{path} must exist", usage)
|
182
|
-
end
|
183
|
-
|
184
|
-
dirs = []
|
185
|
-
configuration_dir = File.join(@userpath, 'config', 'targets')
|
186
|
-
Dir.foreach(configuration_dir) { |dir_filename| dirs << dir_filename }
|
187
|
-
dirs.sort!
|
188
|
-
dirs.each do |dir_filename|
|
189
|
-
if dir_filename[0] != '.'
|
190
|
-
if dir_filename == dir_filename.upcase
|
191
|
-
# If any of the targets original directory name matches the
|
192
|
-
# current directory then it must have been already processed by
|
193
|
-
# DECLARE_TARGET so we skip it.
|
194
|
-
next if @targets.select { |_name, target| target.original_name == dir_filename }.length > 0
|
195
|
-
next if dir_filename == 'SYSTEM'
|
196
|
-
|
197
|
-
target = Target.new(dir_filename, nil, targets_config_dir)
|
198
|
-
@targets[target.name] = target
|
199
|
-
else
|
200
|
-
raise parser.error("Target folder must be uppercase: '#{dir_filename}'")
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
auto_detect_gem_based_targets()
|
205
|
-
|
206
|
-
when 'DECLARE_TARGET'
|
207
|
-
usage = "#{keyword} <TARGET NAME> <SUBSTITUTE TARGET NAME (Optional)> <TARGET FILENAME (Optional - defaults to target.txt)>"
|
208
|
-
parser.verify_num_parameters(1, 3, usage)
|
209
|
-
target_name = parameters[0].to_s.upcase
|
210
|
-
|
211
|
-
if targets_config_dir
|
212
|
-
folder_name = File.join(targets_config_dir, target_name)
|
213
|
-
else
|
214
|
-
folder_name = File.join(@userpath, 'config', 'targets', target_name)
|
215
|
-
end
|
216
|
-
unless Dir.exist?(folder_name)
|
217
|
-
raise parser.error("Target folder must exist '#{folder_name}'.")
|
218
|
-
end
|
219
|
-
|
220
|
-
substitute_name = nil
|
221
|
-
substitute_name = ConfigParser.handle_nil(parameters[1])
|
222
|
-
if substitute_name
|
223
|
-
substitute_name = substitute_name.to_s.upcase
|
224
|
-
original_name = target_name
|
225
|
-
target_name = substitute_name
|
226
|
-
else
|
227
|
-
original_name = nil
|
228
|
-
end
|
229
|
-
|
230
|
-
target = Target.new(target_name, original_name, targets_config_dir, ConfigParser.handle_nil(parameters[2]))
|
231
|
-
@targets[target.name] = target
|
232
|
-
|
233
|
-
when 'DECLARE_GEM_TARGET'
|
234
|
-
usage = "#{keyword} <GEM NAME> <SUBSTITUTE TARGET NAME (Optional)> <TARGET FILENAME (Optional - defaults to target.txt)>"
|
235
|
-
parser.verify_num_parameters(1, 3, usage)
|
236
|
-
# Remove 'openc3' from the gem name 'openc3-power-supply'
|
237
|
-
target_name = parameters[0].split('-')[1..-1].join('-').to_s.upcase
|
238
|
-
gem_dir = Gem::Specification.find_by_name(parameters[0]).gem_dir
|
239
|
-
substitute_name = nil
|
240
|
-
substitute_name = ConfigParser.handle_nil(parameters[1])
|
241
|
-
if substitute_name
|
242
|
-
substitute_name = substitute_name.to_s.upcase
|
243
|
-
original_name = target_name
|
244
|
-
target_name = substitute_name
|
245
|
-
else
|
246
|
-
original_name = nil
|
247
|
-
end
|
248
|
-
target = Target.new(target_name, original_name, targets_config_dir, ConfigParser.handle_nil(parameters[2]), gem_dir)
|
249
|
-
@targets[target.name] = target
|
250
|
-
|
251
|
-
when 'DECLARE_GEM_MULTI_TARGET'
|
252
|
-
usage = "#{keyword} <GEM NAME> <TARGET NAME> <SUBSTITUTE TARGET NAME (Optional)> <TARGET FILENAME (Optional - defaults to target.txt)>"
|
253
|
-
parser.verify_num_parameters(2, 4, usage)
|
254
|
-
target_name = parameters[1].to_s.upcase
|
255
|
-
gem_dir = Gem::Specification.find_by_name(parameters[0]).gem_dir
|
256
|
-
gem_dir = File.join(gem_dir, target_name)
|
257
|
-
substitute_name = nil
|
258
|
-
substitute_name = ConfigParser.handle_nil(parameters[2])
|
259
|
-
if substitute_name
|
260
|
-
substitute_name = substitute_name.to_s.upcase
|
261
|
-
original_name = target_name
|
262
|
-
target_name = substitute_name
|
263
|
-
else
|
264
|
-
original_name = nil
|
265
|
-
end
|
266
|
-
target = Target.new(target_name, original_name, targets_config_dir, ConfigParser.handle_nil(parameters[3]), gem_dir)
|
267
|
-
@targets[target.name] = target
|
268
|
-
|
269
|
-
end # case keyword
|
270
|
-
end # parser.parse_file
|
271
|
-
|
272
|
-
# Make sure SYSTEM target is always present and added last
|
273
|
-
unless @targets.key?('SYSTEM')
|
274
|
-
target = Target.new('SYSTEM', nil, targets_config_dir)
|
275
|
-
@targets[target.name] = target
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
protected
|
280
|
-
|
281
|
-
def unzip(zip_file_name)
|
282
|
-
zip_dir = File.join(@paths['TMP'], File.basename(zip_file_name, ".*"))
|
283
|
-
# Only unzip if we have to. We assume the unzipped directory structure is
|
284
|
-
# intact. If not they'll get a popop with the errors encountered when
|
285
|
-
# loading the configuration.
|
286
|
-
unless File.exist? zip_dir
|
287
|
-
Zip::File.open(zip_file_name) do |zip_file|
|
288
|
-
zip_file.each do |entry|
|
289
|
-
path = File.join(@paths['TMP'], entry.name)
|
290
|
-
FileUtils.mkdir_p(File.dirname(path))
|
291
|
-
zip_file.extract(entry, path) unless File.exist?(path)
|
292
|
-
end
|
293
|
-
end
|
294
|
-
end
|
295
|
-
zip_dir
|
296
|
-
end
|
297
|
-
|
298
|
-
# A helper method to make the zip writing recursion work
|
299
|
-
def write_zip_entries(base_dir, entries, zip_path, io)
|
300
|
-
io.add(zip_path, base_dir) # Add the directory whether it has entries or not
|
301
|
-
entries.each do |e|
|
302
|
-
zip_file_path = File.join(zip_path, e)
|
303
|
-
disk_file_path = File.join(base_dir, e)
|
304
|
-
if File.directory? disk_file_path
|
305
|
-
recursively_deflate_directory(disk_file_path, io, zip_file_path)
|
306
|
-
else
|
307
|
-
put_into_archive(disk_file_path, io, zip_file_path)
|
308
|
-
end
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
def recursively_deflate_directory(disk_file_path, io, zip_file_path)
|
313
|
-
io.add(zip_file_path, disk_file_path)
|
314
|
-
entries = Dir.entries(disk_file_path) - %w(. ..)
|
315
|
-
write_zip_entries(disk_file_path, entries, zip_file_path, io)
|
316
|
-
end
|
317
|
-
|
318
|
-
def put_into_archive(disk_file_path, io, zip_file_path)
|
319
|
-
io.get_output_stream(zip_file_path) do |f|
|
320
|
-
data = nil
|
321
|
-
File.open(disk_file_path, 'rb') do |file|
|
322
|
-
data = file.read
|
323
|
-
end
|
324
|
-
f.write(data)
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
def auto_detect_gem_based_targets
|
329
|
-
Bundler.load.specs.each do |spec|
|
330
|
-
spec_name_split = spec.name.split('-')
|
331
|
-
if spec_name_split.length > 1 && (spec_name_split[0] == 'openc3')
|
332
|
-
# search for multiple targets packaged in a single gem
|
333
|
-
dirs = []
|
334
|
-
Dir.foreach(spec.gem_dir) { |dir_filename| dirs << dir_filename }
|
335
|
-
dirs.sort!
|
336
|
-
dirs.each do |dir_filename|
|
337
|
-
if dir_filename == "."
|
338
|
-
# check the base directory
|
339
|
-
curr_dir = spec.gem_dir
|
340
|
-
target_name = spec_name_split[1..-1].join('-').to_s.upcase
|
341
|
-
else
|
342
|
-
# check for targets in other directories 1 level deep
|
343
|
-
next if dir_filename[0] == '.' # skip dot directories and ".."
|
344
|
-
next if dir_filename != dir_filename.upcase # skip non uppercase directories
|
345
|
-
|
346
|
-
curr_dir = File.join(spec.gem_dir, dir_filename)
|
347
|
-
target_name = dir_filename
|
348
|
-
end
|
349
|
-
# check for the cmd_tlm directory - if it has it, then we have found a target
|
350
|
-
if File.directory?(File.join(curr_dir, 'cmd_tlm'))
|
351
|
-
# If any of the targets original directory name matches the
|
352
|
-
# current directory then it must have been already processed by
|
353
|
-
# DECLARE_TARGET so we skip it.
|
354
|
-
next if @targets.select { |_name, target| target.original_name == target_name }.length > 0
|
355
|
-
|
356
|
-
target = Target.new(target_name, nil, nil, nil, spec.gem_dir)
|
357
|
-
@targets[target.name] = target
|
358
|
-
end
|
359
|
-
end
|
360
|
-
end
|
361
|
-
end
|
362
|
-
rescue Bundler::GemfileNotFound
|
363
|
-
# No Gemfile - so no gem based targets
|
364
|
-
end
|
365
|
-
|
366
|
-
def save_configuration
|
367
|
-
configuration = find_configuration(@config.name)
|
368
|
-
configuration = File.join(@paths['SAVED_CONFIG'], File.build_timestamped_filename([@config.name], '.zip')) unless configuration
|
369
|
-
unless File.exist?(configuration)
|
370
|
-
configuration_tmp = File.join(@paths['SAVED_CONFIG'], File.build_timestamped_filename(['tmp_' + @config.name], '.zip.tmp'))
|
371
|
-
begin
|
372
|
-
Zip.continue_on_exists_proc = true
|
373
|
-
Zip::File.open(configuration_tmp, Zip::File::CREATE) do |zipfile|
|
374
|
-
zip_file_path = File.basename(configuration, ".zip")
|
375
|
-
zipfile.mkdir zip_file_path
|
376
|
-
|
377
|
-
# Copy target files into archive
|
378
|
-
zip_targets = []
|
379
|
-
@targets.each do |_target_name, target|
|
380
|
-
entries = Dir.entries(target.dir) - %w(. ..)
|
381
|
-
zip_target = File.join(zip_file_path, target.original_name)
|
382
|
-
# Check the stored list of targets. We can't ask the zip file
|
383
|
-
# itself because it's in progress and hasn't been saved
|
384
|
-
unless zip_targets.include?(zip_target)
|
385
|
-
write_zip_entries(target.dir, entries, zip_target, zipfile)
|
386
|
-
zip_targets << zip_target
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
# Create custom system.txt file
|
391
|
-
zipfile.get_output_stream(File.join(zip_file_path, 'system.txt')) do |file|
|
392
|
-
@targets.each do |_target_name, target|
|
393
|
-
target_filename = File.basename(target.filename)
|
394
|
-
target_filename = nil unless File.exist?(target.filename)
|
395
|
-
# Create a newline character since Zip opens files in binary mode
|
396
|
-
newline = Kernel.is_windows? ? "\r\n" : "\n"
|
397
|
-
if target.substitute
|
398
|
-
file.write "DECLARE_TARGET #{target.original_name} #{target.name} #{target_filename}#{newline}"
|
399
|
-
else
|
400
|
-
file.write "DECLARE_TARGET #{target.name} nil #{target_filename}#{newline}"
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end
|
404
|
-
end
|
405
|
-
File.rename(configuration_tmp, configuration)
|
406
|
-
File.chmod(0444, configuration) # Mark readonly
|
407
|
-
rescue Exception => e
|
408
|
-
Logger.error "Problem saving configuration to #{configuration}: #{e.class}:#{e.message}\n#{e.backtrace.join("\n")}\n"
|
409
|
-
end
|
410
|
-
end
|
411
|
-
end
|
412
|
-
end
|
413
|
-
end
|
@@ -1,92 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
3
|
-
# All Rights Reserved.
|
4
|
-
#
|
5
|
-
# This program is free software; you can modify and/or redistribute it
|
6
|
-
# under the terms of the GNU Affero General Public License
|
7
|
-
# as published by the Free Software Foundation; version 3 with
|
8
|
-
# attribution addendums as found in the LICENSE.txt
|
9
|
-
#
|
10
|
-
# This program is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
-
# GNU Affero General Public License for more details.
|
14
|
-
|
15
|
-
# Modified by OpenC3, Inc.
|
16
|
-
# All changes Copyright 2022, OpenC3, Inc.
|
17
|
-
# All Rights Reserved
|
18
|
-
#
|
19
|
-
# This file may also be used under the terms of a commercial license
|
20
|
-
# if purchased from OpenC3, Inc.
|
21
|
-
*/
|
22
|
-
|
23
|
-
import axios from './axios.js'
|
24
|
-
|
25
|
-
const request = async function (
|
26
|
-
method,
|
27
|
-
url,
|
28
|
-
{ data, params = {}, headers, noAuth = false, noScope = false } = {}
|
29
|
-
) {
|
30
|
-
if (!noAuth) {
|
31
|
-
try {
|
32
|
-
let refreshed = await OpenC3Auth.updateToken(
|
33
|
-
OpenC3Auth.defaultMinValidity
|
34
|
-
)
|
35
|
-
if (refreshed) {
|
36
|
-
OpenC3Auth.setTokens()
|
37
|
-
}
|
38
|
-
} catch (error) {
|
39
|
-
OpenC3Auth.login()
|
40
|
-
}
|
41
|
-
headers['Authorization'] = localStorage.openc3Token
|
42
|
-
}
|
43
|
-
if (!noScope && !params['scope']) {
|
44
|
-
params['scope'] = window.openc3Scope
|
45
|
-
}
|
46
|
-
return axios({
|
47
|
-
method,
|
48
|
-
url,
|
49
|
-
data,
|
50
|
-
params,
|
51
|
-
headers,
|
52
|
-
})
|
53
|
-
}
|
54
|
-
|
55
|
-
const acceptOnlyDefaultHeaders = {
|
56
|
-
Accept: 'application/json',
|
57
|
-
}
|
58
|
-
|
59
|
-
const fullDefaultHeaders = {
|
60
|
-
...acceptOnlyDefaultHeaders,
|
61
|
-
'Content-Type': 'application/json',
|
62
|
-
}
|
63
|
-
|
64
|
-
export default {
|
65
|
-
get: function (
|
66
|
-
path,
|
67
|
-
{ params, headers = acceptOnlyDefaultHeaders, noScope, noAuth } = {}
|
68
|
-
) {
|
69
|
-
return request('get', path, { params, headers, noScope, noAuth })
|
70
|
-
},
|
71
|
-
|
72
|
-
put: function (
|
73
|
-
path,
|
74
|
-
{ data, params, headers = fullDefaultHeaders, noScope, noAuth } = {}
|
75
|
-
) {
|
76
|
-
return request('put', path, { data, params, headers, noScope, noAuth })
|
77
|
-
},
|
78
|
-
|
79
|
-
post: function (
|
80
|
-
path,
|
81
|
-
{ data, params, headers = fullDefaultHeaders, noScope, noAuth } = {}
|
82
|
-
) {
|
83
|
-
return request('post', path, { data, params, headers, noScope, noAuth })
|
84
|
-
},
|
85
|
-
|
86
|
-
delete: function (
|
87
|
-
path,
|
88
|
-
{ params, headers = acceptOnlyDefaultHeaders, noScope, noAuth } = {}
|
89
|
-
) {
|
90
|
-
return request('delete', path, { params, headers, noScope, noAuth })
|
91
|
-
},
|
92
|
-
}
|