openc3 5.20.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openc3cli +12 -120
  3. data/data/config/command_modifiers.yaml +13 -1
  4. data/data/config/interface_modifiers.yaml +21 -4
  5. data/data/config/item_modifiers.yaml +1 -1
  6. data/data/config/microservice.yaml +15 -2
  7. data/data/config/param_item_modifiers.yaml +1 -1
  8. data/data/config/parameter_modifiers.yaml +1 -1
  9. data/data/config/table_manager.yaml +2 -2
  10. data/data/config/target.yaml +11 -0
  11. data/data/config/telemetry_modifiers.yaml +17 -1
  12. data/data/config/tool.yaml +12 -0
  13. data/data/config/widgets.yaml +13 -17
  14. data/lib/openc3/accessors/form_accessor.rb +4 -3
  15. data/lib/openc3/accessors/html_accessor.rb +3 -3
  16. data/lib/openc3/accessors/http_accessor.rb +13 -13
  17. data/lib/openc3/accessors/xml_accessor.rb +16 -4
  18. data/lib/openc3/api/target_api.rb +0 -30
  19. data/lib/openc3/config/config_parser.rb +6 -3
  20. data/lib/openc3/core_ext/array.rb +0 -16
  21. data/lib/openc3/core_ext.rb +0 -1
  22. data/lib/openc3/interfaces/file_interface.rb +198 -0
  23. data/lib/openc3/interfaces/http_client_interface.rb +71 -39
  24. data/lib/openc3/interfaces/http_server_interface.rb +0 -7
  25. data/lib/openc3/interfaces/interface.rb +2 -0
  26. data/lib/openc3/interfaces/mqtt_interface.rb +32 -15
  27. data/lib/openc3/interfaces/mqtt_stream_interface.rb +19 -4
  28. data/lib/openc3/interfaces/protocols/crc_protocol.rb +7 -0
  29. data/lib/openc3/interfaces/serial_interface.rb +1 -0
  30. data/lib/openc3/interfaces.rb +2 -4
  31. data/lib/openc3/microservices/multi_microservice.rb +3 -3
  32. data/lib/openc3/migrations/20241208080000_no_critical_cmd.rb +31 -0
  33. data/lib/openc3/migrations/20241208080001_no_trigger_group.rb +46 -0
  34. data/lib/openc3/models/interface_model.rb +9 -3
  35. data/lib/openc3/models/microservice_model.rb +8 -1
  36. data/lib/openc3/models/plugin_model.rb +6 -1
  37. data/lib/openc3/models/python_package_model.rb +6 -1
  38. data/lib/openc3/models/reaction_model.rb +14 -10
  39. data/lib/openc3/models/scope_model.rb +60 -42
  40. data/lib/openc3/models/target_model.rb +17 -1
  41. data/lib/openc3/models/timeline_model.rb +17 -5
  42. data/lib/openc3/models/tool_model.rb +15 -3
  43. data/lib/openc3/models/trigger_group_model.rb +6 -3
  44. data/lib/openc3/operators/microservice_operator.rb +8 -0
  45. data/lib/openc3/packets/commands.rb +17 -6
  46. data/lib/openc3/packets/limits.rb +0 -12
  47. data/lib/openc3/packets/packet.rb +1 -1
  48. data/lib/openc3/packets/packet_item.rb +30 -36
  49. data/lib/openc3/packets/structure_item.rb +2 -2
  50. data/lib/openc3/script/script.rb +0 -10
  51. data/lib/openc3/script/web_socket_api.rb +2 -2
  52. data/lib/openc3/streams/mqtt_stream.rb +41 -33
  53. data/lib/openc3/streams/serial_stream.rb +27 -27
  54. data/lib/openc3/streams/stream.rb +17 -17
  55. data/lib/openc3/streams/tcpip_client_stream.rb +1 -1
  56. data/lib/openc3/streams/tcpip_socket_stream.rb +19 -19
  57. data/lib/openc3/system/system.rb +1 -1
  58. data/lib/openc3/system.rb +2 -3
  59. data/lib/openc3/tools/table_manager/table.rb +2 -2
  60. data/lib/openc3/tools/table_manager/table_parser.rb +1 -1
  61. data/lib/openc3/top_level.rb +0 -5
  62. data/lib/openc3/topics/command_decom_topic.rb +0 -7
  63. data/lib/openc3/utilities/bucket_utilities.rb +1 -1
  64. data/lib/openc3/utilities/cli_generator.rb +0 -1
  65. data/lib/openc3/version.rb +6 -6
  66. data/templates/plugin/README.md +1 -1
  67. data/templates/target/targets/TARGET/lib/target.rb +1 -1
  68. data/templates/tool_angular/package.json +8 -8
  69. data/templates/tool_angular/src/app/app.component.html +4 -13
  70. data/templates/tool_angular/src/app/app.component.scss +5 -13
  71. data/templates/tool_angular/src/app/app.component.ts +5 -4
  72. data/templates/tool_angular/src/app/custom-overlay-container.ts +2 -2
  73. data/templates/tool_angular/src/app/openc3-api.d.ts +1 -1
  74. data/templates/tool_angular/src/main.single-spa.ts +1 -1
  75. data/templates/tool_react/package.json +1 -0
  76. data/templates/tool_react/src/root.component.js +1 -1
  77. data/templates/tool_svelte/package.json +11 -9
  78. data/templates/tool_svelte/rollup.config.js +2 -0
  79. data/templates/tool_svelte/src/App.svelte +2 -2
  80. data/templates/tool_vue/eslint.config.mjs +68 -0
  81. data/templates/tool_vue/jsconfig.json +1 -1
  82. data/templates/tool_vue/package.json +26 -43
  83. data/templates/tool_vue/src/App.vue +3 -5
  84. data/templates/tool_vue/src/main.js +12 -23
  85. data/templates/tool_vue/src/router.js +19 -18
  86. data/templates/tool_vue/src/tools/tool_name/tool_name.vue +2 -2
  87. data/templates/tool_vue/vite.config.js +52 -0
  88. data/templates/widget/package.json +19 -26
  89. data/templates/widget/src/Widget.vue +13 -15
  90. data/templates/widget/vite.config.js +26 -0
  91. metadata +10 -41
  92. data/lib/openc3/core_ext/hash.rb +0 -40
  93. data/lib/openc3/core_ext/httpclient.rb +0 -11
  94. data/lib/openc3/interfaces/linc_interface.rb +0 -480
  95. data/lib/openc3/interfaces/protocols/override_protocol.rb +0 -4
  96. data/lib/openc3/microservices/critical_cmd_microservice.rb +0 -74
  97. data/lib/openc3/microservices/reaction_microservice.rb +0 -607
  98. data/lib/openc3/microservices/timeline_microservice.rb +0 -398
  99. data/lib/openc3/microservices/trigger_group_microservice.rb +0 -698
  100. data/lib/openc3/migrations/20230615000000_autonomic.rb +0 -86
  101. data/lib/openc3/migrations/20240915000000_activity_uuid.rb +0 -28
  102. data/lib/openc3/migrations/20241016000000_scope_critical_cmd.rb +0 -24
  103. data/lib/openc3/system/system_config.rb +0 -413
  104. data/templates/tool_svelte/src/services/api.js +0 -92
  105. data/templates/tool_svelte/src/services/axios.js +0 -85
  106. data/templates/tool_svelte/src/services/cable.js +0 -65
  107. data/templates/tool_svelte/src/services/config-parser.js +0 -198
  108. data/templates/tool_svelte/src/services/openc3-api.js +0 -606
  109. data/templates/tool_vue/.eslintrc.js +0 -43
  110. data/templates/tool_vue/babel.config.json +0 -11
  111. data/templates/tool_vue/vue.config.js +0 -38
  112. data/templates/widget/.eslintrc.js +0 -43
  113. data/templates/widget/babel.config.json +0 -11
  114. data/templates/widget/vue.config.js +0 -28
  115. /data/templates/tool_vue/{.prettierrc.js → .prettierrc.cjs} +0 -0
  116. /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
- }