openc3 5.0.8 → 5.0.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of openc3 might be problematic. Click here for more details.

@@ -24,6 +24,7 @@ require 'openc3/models/microservice_model'
24
24
  require 'openc3/topics/limits_event_topic'
25
25
  require 'openc3/topics/config_topic'
26
26
  require 'openc3/system'
27
+ require 'openc3/utilities/local_mode'
27
28
  require 'openc3/utilities/s3'
28
29
  require 'openc3/utilities/zip'
29
30
  require 'fileutils'
@@ -87,29 +88,36 @@ module OpenC3
87
88
  targets = self.all(scope: scope)
88
89
  targets.each { |target_name, target| target['modified'] = false }
89
90
 
90
- rubys3_client = Aws::S3::Client.new
91
- token = nil
92
- while true
93
- resp = rubys3_client.list_objects_v2({
94
- bucket: 'config',
95
- max_keys: 1000,
96
- # The trailing slash is important!
97
- prefix: "#{scope}/targets_modified/",
98
- delimiter: '/',
99
- continuation_token: token
100
- })
101
- resp.common_prefixes.each do |item|
102
- # Results look like DEFAULT/targets_modified/INST/
103
- # so split on '/' and pull out the last value
104
- target_name = item.prefix.split('/')[-1]
105
- # A target could have been deleted without removing the modified files
106
- # Thus we have to check for the existance of the target_name key
107
- if targets.has_key?(target_name)
108
- targets[target_name]['modified'] = true
91
+ if ENV['OPENC3_LOCAL_MODE']
92
+ modified_targets = OpenC3::LocalMode.modified_targets(scope: scope)
93
+ modified_targets.each do |target_name|
94
+ targets[target_name]['modified'] = true if targets[target_name]
95
+ end
96
+ else
97
+ rubys3_client = Aws::S3::Client.new
98
+ token = nil
99
+ while true
100
+ resp = rubys3_client.list_objects_v2({
101
+ bucket: 'config',
102
+ max_keys: 1000,
103
+ # The trailing slash is important!
104
+ prefix: "#{scope}/targets_modified/",
105
+ delimiter: '/',
106
+ continuation_token: token
107
+ })
108
+ resp.common_prefixes.each do |item|
109
+ # Results look like DEFAULT/targets_modified/INST/
110
+ # so split on '/' and pull out the last value
111
+ target_name = item.prefix.split('/')[-1]
112
+ # A target could have been deleted without removing the modified files
113
+ # Thus we have to check for the existance of the target_name key
114
+ if targets.has_key?(target_name)
115
+ targets[target_name]['modified'] = true
116
+ end
109
117
  end
118
+ break unless resp.is_truncated
119
+ token = resp.next_continuation_token
110
120
  end
111
- break unless resp.is_truncated
112
- token = resp.next_continuation_token
113
121
  end
114
122
  # Sort (which turns hash to array) and return hash
115
123
  # This enables a consistent listing of the targets
@@ -117,31 +125,41 @@ module OpenC3
117
125
  end
118
126
 
119
127
  # Given target's modified file list
120
- def self.modified_files(name, scope:)
128
+ def self.modified_files(target_name, scope:)
121
129
  modified = []
122
- rubys3_client = Aws::S3::Client.new
123
- token = nil
124
- while true
125
- resp = rubys3_client.list_objects_v2({
126
- bucket: 'config',
127
- max_keys: 1000,
128
- # The trailing slash is important!
129
- prefix: "#{scope}/targets_modified/#{name}/",
130
- continuation_token: token
131
- })
132
- resp.contents.each do |item|
133
- # Results look like DEFAULT/targets_modified/INST/procedures/new.rb
134
- # so split on '/' and ignore the first two values
135
- modified << item.key.split('/')[2..-1].join('/')
130
+
131
+ if ENV['OPENC3_LOCAL_MODE']
132
+ modified = OpenC3::LocalMode.modified_files(target_name, scope: scope)
133
+ else
134
+ rubys3_client = Aws::S3::Client.new
135
+ token = nil
136
+ while true
137
+ resp = rubys3_client.list_objects_v2({
138
+ bucket: 'config',
139
+ max_keys: 1000,
140
+ # The trailing slash is important!
141
+ prefix: "#{scope}/targets_modified/#{target_name}/",
142
+ continuation_token: token
143
+ })
144
+ resp.contents.each do |item|
145
+ # Results look like DEFAULT/targets_modified/INST/procedures/new.rb
146
+ # so split on '/' and ignore the first two values
147
+ modified << item.key.split('/')[2..-1].join('/')
148
+ end
149
+ break unless resp.is_truncated
150
+ token = resp.next_continuation_token
136
151
  end
137
- break unless resp.is_truncated
138
- token = resp.next_continuation_token
139
152
  end
140
153
  # Sort to enable a consistent listing of the modified files
141
154
  modified.sort
142
155
  end
143
156
 
144
- def self.delete_modified(name, scope:)
157
+ def self.delete_modified(target_name, scope:)
158
+ if ENV['OPENC3_LOCAL_MODE']
159
+ OpenC3::LocalMode.delete_modified(target_name, scope: scope)
160
+ end
161
+
162
+ # Delete the remote files as well
145
163
  rubys3_client = Aws::S3::Client.new
146
164
  token = nil
147
165
  while true
@@ -149,7 +167,7 @@ module OpenC3
149
167
  bucket: 'config',
150
168
  max_keys: 1000,
151
169
  # The trailing slash is important!
152
- prefix: "#{scope}/targets_modified/#{name}/",
170
+ prefix: "#{scope}/targets_modified/#{target_name}/",
153
171
  continuation_token: token
154
172
  })
155
173
  resp.contents.each do |item|
@@ -158,41 +176,40 @@ module OpenC3
158
176
  break unless resp.is_truncated
159
177
  token = resp.next_continuation_token
160
178
  end
161
- # rubys3_client = Aws::S3::Client.new
162
- # prefix = "#{scope}/targets_modified/#{name}/"
163
- # rubys3_client.list_objects(bucket: 'config', prefix: prefix).contents.each do |object|
164
- # rubys3_client.delete_object(bucket: 'config', key: object.key)
165
- # end
166
179
  end
167
180
 
168
- def self.download(name, scope:)
181
+ def self.download(target_name, scope:)
169
182
  tmp_dir = Dir.mktmpdir
170
- zip_filename = File.join(tmp_dir, "#{name}.zip")
183
+ zip_filename = File.join(tmp_dir, "#{target_name}.zip")
171
184
  Zip.continue_on_exists_proc = true
172
185
  zip = Zip::File.open(zip_filename, Zip::File::CREATE)
173
186
 
174
- rubys3_client = Aws::S3::Client.new
175
- token = nil
176
- # The trailing slash is important!
177
- prefix = "#{scope}/targets_modified/#{name}/"
178
- while true
179
- resp = rubys3_client.list_objects_v2({
180
- bucket: 'config',
181
- max_keys: 1000,
182
- prefix: prefix,
183
- continuation_token: token
184
- })
185
- resp.contents.each do |item|
186
- # item.key looks like DEFAULT/targets_modified/INST/screens/blah.txt
187
- base_path = item.key.sub(prefix, '') # remove prefix
188
- local_path = File.join(tmp_dir, base_path)
189
- # Ensure dir structure exists, get_object fails if not
190
- FileUtils.mkdir_p(File.dirname(local_path))
191
- rubys3_client.get_object(bucket: 'config', key: item.key, response_target: local_path)
192
- zip.add(base_path, local_path)
187
+ if ENV['OPENC3_LOCAL_MODE']
188
+ OpenC3::LocalMode.zip_target(target_name, zip, scope: scope)
189
+ else
190
+ rubys3_client = Aws::S3::Client.new
191
+ token = nil
192
+ # The trailing slash is important!
193
+ prefix = "#{scope}/targets_modified/#{target_name}/"
194
+ while true
195
+ resp = rubys3_client.list_objects_v2({
196
+ bucket: 'config',
197
+ max_keys: 1000,
198
+ prefix: prefix,
199
+ continuation_token: token
200
+ })
201
+ resp.contents.each do |item|
202
+ # item.key looks like DEFAULT/targets_modified/INST/screens/blah.txt
203
+ base_path = item.key.sub(prefix, '') # remove prefix
204
+ local_path = File.join(tmp_dir, base_path)
205
+ # Ensure dir structure exists, get_object fails if not
206
+ FileUtils.mkdir_p(File.dirname(local_path))
207
+ rubys3_client.get_object(bucket: 'config', key: item.key, response_target: local_path)
208
+ zip.add(base_path, local_path)
209
+ end
210
+ break unless resp.is_truncated
211
+ token = resp.next_continuation_token
193
212
  end
194
- break unless resp.is_truncated
195
- token = resp.next_continuation_token
196
213
  end
197
214
  zip.close
198
215
 
@@ -178,14 +178,40 @@ module OpenC3
178
178
  when 'ParameterTypeSet', 'EnumerationList', 'ParameterSet', 'ContainerSet',
179
179
  'EntryList', 'DefaultCalibrator', 'DefaultAlarm', 'RestrictionCriteria',
180
180
  'ComparisonList', 'MetaCommandSet', 'ArgumentTypeSet', 'ArgumentList',
181
- 'ArgumentAssignmentList', 'LocationInContainerInBits'
181
+ 'ArgumentAssignmentList', 'LocationInContainerInBits', 'ReferenceTime'
182
182
  # Do Nothing
183
183
 
184
+ when 'ErrorDetectCorrect'
185
+ # TODO: Setup an algorithm to calculate the CRC
186
+ exponents = []
187
+ xtce_recurse_element(element) do |crc_element|
188
+ if crc_element.name == 'CRC'
189
+ xtce_recurse_element(crc_element) do |poly_element|
190
+ if poly_element['Polynomial']
191
+ xtce_recurse_element(poly_element) do |term_element|
192
+ if term_element['Term']
193
+ exponents << term_element['exponent'].to_i
194
+ end
195
+ true
196
+ end
197
+ end
198
+ true
199
+ end
200
+ end
201
+ true
202
+ end
203
+ @current_type.xtce_encoding = 'IntegerDataEncoding'
204
+ @current_type.signed = 'false'
205
+ return false # Already recursed
206
+
184
207
  when 'EnumeratedParameterType', 'EnumeratedArgumentType',
185
208
  'IntegerParameterType', 'IntegerArgumentType',
186
209
  'FloatParameterType', 'FloatArgumentType',
187
210
  'StringParameterType', 'StringArgumentType',
188
- 'BinaryParameterType', 'BinaryArgumentType'
211
+ 'BinaryParameterType', 'BinaryArgumentType',
212
+ 'BooleanParameterType', 'BooleanArgumentType',
213
+ 'AbsoluteTimeParameterType', 'AbsoluteTimeArgumentType',
214
+ 'RelativeTimeParameterType', 'RelativeTimeArgumentType'
189
215
  @current_type = create_new_type(element)
190
216
  @current_type.endianness = :BIG_ENDIAN
191
217
 
@@ -204,6 +230,20 @@ module OpenC3
204
230
  when 'BinaryParameterType', 'BinaryArgumentType'
205
231
  @current_type.xtce_encoding = 'BinaryDataEncoding'
206
232
  @current_type.sizeInBits = 8 # This is undocumented but appears to be the design
233
+ when 'BooleanParameterType', 'BooleanArgumentType'
234
+ @current_type.xtce_encoding = 'StringDataEncoding'
235
+ @current_type.sizeInBits = 8 # This is undocumented but appears to be the design
236
+ @current_type.states ||= {}
237
+ if element.attributes['zeroStringValue'] && element.attributes['oneStringValue']
238
+ @current_type.states[element.attributes['zeroStringValue'].value] = 0
239
+ @current_type.states[element.attributes['oneStringValue'].value] = 1
240
+ else
241
+ @current_type.states['FALSE'] = 0
242
+ @current_type.states['TRUE'] = 1
243
+ end
244
+ # No defaults for the time types
245
+ # when 'AbsoluteTimeParameterType', 'AbsoluteTimeArgumentType',
246
+ # when'RelativeTimeParameterType', 'RelativeTimeArgumentType'
207
247
  end
208
248
 
209
249
  when 'ArrayParameterType', 'ArrayArgumentType'
@@ -251,7 +291,7 @@ module OpenC3
251
291
 
252
292
  return false # Already recursed
253
293
 
254
- when "SizeInBits"
294
+ when 'SizeInBits'
255
295
  xtce_recurse_element(element) do |block_element|
256
296
  if block_element.name == 'FixedValue'
257
297
  @current_type.sizeInBits = Integer(block_element.text)
@@ -326,6 +366,26 @@ module OpenC3
326
366
  @current_type.states ||= {}
327
367
  @current_type.states[element['label']] = Integer(element['value'])
328
368
 
369
+ when 'Encoding'
370
+ if element.attributes['units']
371
+ @current_type.units_full = element.attributes['units'].value
372
+ # Could do a better job mapping units to abbreviations
373
+ @current_type.units = element.attributes['units'].value[0]
374
+ end
375
+ # TODO: Not sure if this is correct
376
+ # if @current_type.attributes['scale'] || @current_type.attributes['offset']
377
+ # @current_type.conversion ||= PolynomialConversion.new()
378
+ # if @current_type.attributes['offset']
379
+ # @current_type.conversion.coeffs[0] = @current_type.attributes['offset']
380
+ # end
381
+ # if @current_type.attributes['scale']
382
+ # @current_type.conversion.coeffs[1] = @current_type.attributes['scale']
383
+ # end
384
+ # end
385
+
386
+ when 'Epoch'
387
+ # TODO: How to handle this ... it affects the conversion applied
388
+
329
389
  when 'IntegerDataEncoding', 'FloatDataEncoding', 'StringDataEncoding', 'BinaryDataEncoding'
330
390
  @current_type.xtce_encoding = element.name
331
391
  element.attributes.each do |att_name, att|
@@ -340,6 +400,11 @@ module OpenC3
340
400
  @current_type.endianness = :LITTLE_ENDIAN
341
401
  end
342
402
 
403
+ # Ensure if the encoding is a string we convert state values to strings
404
+ if @current_type.xtce_encoding == 'StringDataEncoding' && @current_type.states
405
+ @current_type.states.transform_values!(&:to_s)
406
+ end
407
+
343
408
  when 'Parameter'
344
409
  @current_parameter = OpenStruct.new
345
410
  element.attributes.each do |att_name, att|
@@ -34,7 +34,7 @@ module OpenC3
34
34
  OpenC3::Logger.info "Deleting #{delete_path}"
35
35
  response = $api_server.request('delete', endpoint, query: {bucket: 'config'}, scope: scope)
36
36
  if response.nil? || response.code != 200
37
- raise "Failed to delete #{delete_path}. Note: #{scope}/targets is read-only."
37
+ raise "Failed to delete #{delete_path}"
38
38
  end
39
39
  rescue => error
40
40
  raise "Failed deleting #{path} due to #{error.message}"
@@ -48,7 +48,13 @@ module OpenC3
48
48
  # @param io_or_string [Io or String] IO object
49
49
  def put_target_file(path, io_or_string, scope: $openc3_scope)
50
50
  raise "Disallowed path modifier '..' found in #{path}" if path.include?('..')
51
+
51
52
  upload_path = "#{scope}/targets_modified/#{path}"
53
+
54
+ if ENV['OPENC3_LOCAL_MODE'] and $openc3_in_cluster
55
+ OpenC3::LocalMode.put_target_file(upload_path, io_or_string, scope: scope)
56
+ end
57
+
52
58
  endpoint = "/openc3-api/storage/upload/#{upload_path}"
53
59
  OpenC3::Logger.info "Writing #{upload_path}"
54
60
  result = _get_presigned_request(endpoint, scope: scope)
@@ -86,6 +92,17 @@ module OpenC3
86
92
  # Loop to allow redo when switching from modified to original
87
93
  loop do
88
94
  begin
95
+ if part == "targets_modified" and ENV['OPENC3_LOCAL_MODE']
96
+ local_file = OpenC3::LocalMode.open_local_file(path, scope: scope)
97
+ if local_file
98
+ file = Tempfile.new('target', binmode: true)
99
+ file.write(local_file.read)
100
+ local_file.close
101
+ file.rewind
102
+ return file if local_file
103
+ end
104
+ end
105
+
89
106
  return _get_storage_file("#{part}/#{path}", scope: scope)
90
107
  rescue => error
91
108
  if part == "targets_modified"