openc3 5.20.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
-
}
|