openc3 5.5.0.pre.beta0 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openc3cli +58 -74
  3. data/data/config/item_modifiers.yaml +1 -1
  4. data/data/config/plugins.yaml +5 -0
  5. data/data/config/widgets.yaml +13 -11
  6. data/lib/openc3/api/cmd_api.rb +43 -17
  7. data/lib/openc3/api/tlm_api.rb +37 -4
  8. data/lib/openc3/bridge/bridge.rb +3 -3
  9. data/lib/openc3/bridge/bridge_config.rb +68 -20
  10. data/lib/openc3/interfaces/interface.rb +8 -0
  11. data/lib/openc3/microservices/decom_microservice.rb +0 -3
  12. data/lib/openc3/microservices/interface_microservice.rb +2 -0
  13. data/lib/openc3/microservices/reaction_microservice.rb +0 -1
  14. data/lib/openc3/models/cvt_model.rb +1 -2
  15. data/lib/openc3/models/metadata_model.rb +1 -1
  16. data/lib/openc3/models/microservice_model.rb +1 -1
  17. data/lib/openc3/models/note_model.rb +1 -1
  18. data/lib/openc3/models/plugin_model.rb +14 -7
  19. data/lib/openc3/models/timeline_model.rb +1 -1
  20. data/lib/openc3/models/trigger_group_model.rb +1 -1
  21. data/lib/openc3/packets/packet_item.rb +1 -1
  22. data/lib/openc3/script/storage.rb +5 -5
  23. data/lib/openc3/streams/web_socket_client_stream.rb +0 -1
  24. data/lib/openc3/tools/table_manager/table_manager_core.rb +1 -2
  25. data/lib/openc3/utilities/aws_bucket.rb +22 -4
  26. data/lib/openc3/utilities/bucket_file_cache.rb +3 -2
  27. data/lib/openc3/utilities/bucket_utilities.rb +1 -1
  28. data/lib/openc3/utilities/cli_generator.rb +210 -0
  29. data/lib/openc3/utilities/local_mode.rb +2 -2
  30. data/lib/openc3/utilities/target_file.rb +43 -32
  31. data/lib/openc3/version.rb +5 -5
  32. data/templates/conversion/conversion.rb +43 -0
  33. data/templates/limits_response/response.rb +51 -0
  34. data/templates/microservice/microservices/TEMPLATE/microservice.rb +62 -0
  35. data/templates/plugin/plugin.txt +1 -0
  36. metadata +19 -15
  37. data/templates/plugin-template/plugin.txt +0 -9
  38. /data/templates/{plugin-template → plugin}/LICENSE.txt +0 -0
  39. /data/templates/{plugin-template → plugin}/README.md +0 -0
  40. /data/templates/{plugin-template → plugin}/Rakefile +0 -0
  41. /data/templates/{plugin-template → plugin}/plugin.gemspec +0 -0
  42. /data/templates/{plugin-template → target}/targets/TARGET/cmd_tlm/cmd.txt +0 -0
  43. /data/templates/{plugin-template → target}/targets/TARGET/cmd_tlm/tlm.txt +0 -0
  44. /data/templates/{plugin-template → target}/targets/TARGET/lib/target.rb +0 -0
  45. /data/templates/{plugin-template → target}/targets/TARGET/procedures/procedure.rb +0 -0
  46. /data/templates/{plugin-template → target}/targets/TARGET/screens/status.txt +0 -0
  47. /data/templates/{plugin-template → target}/targets/TARGET/target.txt +0 -0
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/utilities/logger'
@@ -30,28 +30,55 @@ module OpenC3
30
30
  # @return [Hash<String, Interface>] Routers hash
31
31
  attr_accessor :routers
32
32
 
33
- def initialize(filename)
33
+ def initialize(filename, existing_variables = {})
34
34
  @interfaces = {}
35
35
  @routers = {}
36
- process_file(filename)
36
+ process_file(filename, existing_variables)
37
37
  end
38
38
 
39
39
  def self.generate_default(filename)
40
40
  default_config = <<~EOF
41
- # Example Host Bridge Configuration for a Serial Port
42
- #
43
- # INTERFACE <Interface Name> <Interface File> <Interface Params...>
44
- # INTERFACE <Interface Name> serial_interface.rb <Write Port> <Read Port> <Baud Rate> <Parity ODD/EVEN/NONE> <Stop Bits> <Write Timeout> <Read Timeout> <Protocol Name> <Protocol Params>
45
- # INTERFACE <Interface Name> serial_interface.rb <Write Port> <Read Port> <Baud Rate> <Parity ODD/EVEN/NONE> <Stop Bits> <Write Timeout> <Read Timeout> BURST <Discard Leading Bytes> <Sync Pattern> <Add Sync On Write>
46
- # INTERFACE SERIAL_INT serial_interface.rb /dev/ttyS1 /dev/ttyS1 38400 ODD 1 10.0 nil BURST 4 0xDEADBEEF
47
- INTERFACE SERIAL_INT serial_interface.rb COM1 COM1 9600 NONE 1 10.0 nil BURST
41
+ # Write serial port name
42
+ VARIABLE write_port_name COM1
48
43
  #{' '}
49
- # ROUTER <Router Name> <Interface File> <Interface Params...>
50
- # ROUTER SERIAL_ROUTER tcpip_server_interface.rb <Write Port> <Read Port> <Write Timeout> <Read Timeout> <Protocol Name> <Protocol Params>
51
- # ROUTER SERIAL_ROUTER tcpip_server_interface.rb <Write Port> <Read Port> <Write Timeout> <Read Timeout> BURST <Discard Leading Bytes> <Sync Pattern> <Add Sync On Write>
52
- ROUTER SERIAL_ROUTER tcpip_server_interface.rb 2950 2950 10.0 nil BURST
53
- # ROUTE <Interface Name>
54
- ROUTE SERIAL_INT
44
+ # Read serial port name
45
+ VARIABLE read_port_name COM1
46
+ #{' '}
47
+ # Baud Rate
48
+ VARIABLE baud_rate 115200
49
+ #{' '}
50
+ # Parity - NONE, ODD, or EVEN
51
+ VARIABLE parity NONE
52
+ #{' '}
53
+ # Stop bits - 0, 1, or 2
54
+ VARIABLE stop_bits 1
55
+ #{' '}
56
+ # Write Timeout
57
+ VARIABLE write_timeout 10.0
58
+ #{' '}
59
+ # Read Timeout
60
+ VARIABLE read_timeout nil
61
+ #{' '}
62
+ # Flow Control - NONE, or RTSCTS
63
+ VARIABLE flow_control NONE
64
+ #{' '}
65
+ # Data bits per word - Typically 8
66
+ VARIABLE data_bits 8
67
+ #{' '}
68
+ # Port to listen for connections from COSMOS - Plugin must match
69
+ VARIABLE router_port 2950
70
+ #{' '}
71
+ # Port to listen on for connections from COSMOS. Defaults to localhost for security. Will need to be opened
72
+ # if COSMOS is on another machine.
73
+ VARIABLE router_listen_address 127.0.0.1
74
+ #{' '}
75
+ INTERFACE SERIAL_INT serial_interface.rb <%= write_port_name %> <%= read_port_name %> <%= baud_rate %> <%= parity %> <%= stop_bits %> <%= write_timeout %> <%= read_timeout %>
76
+ OPTION FLOW_CONTROL <%= flow_control %>
77
+ OPTION DATA_BITS <%= data_bits %>
78
+ #{' '}
79
+ ROUTER SERIAL_ROUTER tcpip_server_interface.rb <%= router_port %> <%= router_port %> 10.0 nil BURST
80
+ ROUTE SERIAL_INT
81
+ OPTION LISTEN_ADDRESS <%= router_listen_address %>
55
82
  #{' '}
56
83
  EOF
57
84
 
@@ -66,18 +93,39 @@ module OpenC3
66
93
  # Processes a file and adds in the configuration defined in the file
67
94
  #
68
95
  # @param filename [String] The name of the configuration file to parse
69
- # @param recursive [Boolean] Whether process_file is being called
70
- # recursively
71
- def process_file(filename, recursive = false)
96
+ def process_file(filename, existing_variables = {})
72
97
  current_interface_or_router = nil
73
98
  current_type = nil
74
99
  current_interface_log_added = false
75
100
 
76
101
  Logger.info "Processing Bridge configuration in file: #{File.expand_path(filename)}"
77
102
 
103
+ variables = {}
78
104
  parser = ConfigParser.new
79
- parser.parse_file(filename) do |keyword, params|
105
+ parser.parse_file(filename,
106
+ false,
107
+ true,
108
+ false) do |keyword, params|
80
109
  case keyword
110
+ when 'VARIABLE'
111
+ usage = "#{keyword} <Variable Name> <Default Value>"
112
+ parser.verify_num_parameters(2, nil, usage)
113
+ variable_name = params[0]
114
+ value = params[1..-1].join(" ")
115
+ variables[variable_name] = value
116
+ if existing_variables && existing_variables.key?(variable_name)
117
+ variables[variable_name] = existing_variables[variable_name]
118
+ end
119
+ # Ignore everything else during phase 1
120
+ end
121
+ end
122
+
123
+ parser = ConfigParser.new
124
+ parser.parse_file(filename, false, true, true, variables) do |keyword, params|
125
+ case keyword
126
+
127
+ when 'VARIABLE'
128
+ # Ignore during this pass
81
129
 
82
130
  when 'INTERFACE'
83
131
  usage = "INTERFACE <Name> <Filename> <Specific Parameters>"
@@ -25,6 +25,11 @@ require 'openc3/io/raw_logger_pair'
25
25
  require 'openc3/utilities/secrets'
26
26
 
27
27
  module OpenC3
28
+ # Define a class to allow interfaces and protocols to reject commands without
29
+ # disconnecting the interface
30
+ class WriteRejectError < StandardError
31
+ end
32
+
28
33
  # Defines all the attributes and methods common to all interface classes
29
34
  # used by OpenC3.
30
35
  class Interface
@@ -330,6 +335,9 @@ module OpenC3
330
335
  else
331
336
  @write_mutex.synchronize { yield }
332
337
  end
338
+ rescue WriteRejectError => err
339
+ Logger.error("#{@name}: Write rejected by interface: #{err.message}")
340
+ raise err
333
341
  rescue Exception => err
334
342
  Logger.error("#{@name}: Error writing to interface")
335
343
  disconnect()
@@ -95,7 +95,6 @@ module OpenC3
95
95
  # @param log_change [Boolean] Whether to log this limits change event
96
96
  def limits_change_callback(packet, item, old_limits_state, value, log_change)
97
97
  return if @cancel_thread
98
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
99
98
  packet_time = packet.packet_time
100
99
  message = "#{packet.target_name} #{packet.packet_name} #{item.name} = #{value} is #{item.limits.state}"
101
100
  message << " (#{packet.packet_time.sys.formatted})" if packet_time
@@ -136,8 +135,6 @@ module OpenC3
136
135
  @logger.error e.formatted
137
136
  end
138
137
  end
139
-
140
- diff = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start # seconds as a float
141
138
  end
142
139
  end
143
140
  end
@@ -202,6 +202,8 @@ module OpenC3
202
202
  else
203
203
  next "Interface not connected: #{@interface.name}"
204
204
  end
205
+ rescue WriteRejectError => e
206
+ next e.message
205
207
  rescue => e
206
208
  @logger.error "#{@interface.name}: #{e.formatted}"
207
209
  next e.message
@@ -264,7 +264,6 @@ module OpenC3
264
264
  when 'trigger'
265
265
  process_enabled_trigger(data: data)
266
266
  end
267
- current_time = Time.now.to_i
268
267
  rescue StandardError => e
269
268
  @logger.error "ReactionWorker-#{@ident} failed to evaluate kind: #{kind} data: #{data}\n#{e.formatted}"
270
269
  end
@@ -240,11 +240,10 @@ module OpenC3
240
240
  # return an ordered array of hash with keys
241
241
  def self._parse_item(lookups, overrides, item, scope:)
242
242
  target_name, packet_name, item_name, value_type = item.split('__')
243
- raise ArgumentError, "items must be formatted as TGT__PKT__ITEM__TYPE" if target_name.nil? || packet_name.nil? || item_name.nil? || value_type.nil?
244
243
 
245
244
  # We build lookup keys by including all the less formatted types to gracefully degrade lookups
246
245
  # This allows the user to specify WITH_UNITS and if there is no conversions it will simply return the RAW value
247
- case value_type.upcase
246
+ case value_type
248
247
  when 'RAW'
249
248
  keys = [item_name]
250
249
  when 'CONVERTED'
@@ -69,7 +69,7 @@ module OpenC3
69
69
  if @color.nil?
70
70
  @color = '#%06x' % (rand * 0xffffff)
71
71
  end
72
- unless @color =~ /(#*)([0-9,a-f,A-F]{6})/
72
+ unless @color =~ /(#*)([0-9a-fA-F]{6})/
73
73
  raise SortedInputError.new "invalid color, must be in hex format, e.g. #FF0000"
74
74
  end
75
75
  @color = "##{@color}" unless @color.start_with?('#')
@@ -163,7 +163,7 @@ module OpenC3
163
163
  parser.verify_num_parameters(1, 2, usage)
164
164
  begin
165
165
  @ports << [Integer(parameters[0])]
166
- rescue => err # In case Integer fails
166
+ rescue # In case Integer fails
167
167
  raise ConfigParser::Error.new(parser, "Port must be an integer: #{parameters[0]}", usage)
168
168
  end
169
169
  protocol = ConfigParser.handle_nil(parameters[1])
@@ -78,7 +78,7 @@ module OpenC3
78
78
  if @color.nil?
79
79
  @color = '#%06x' % (rand * 0xffffff)
80
80
  end
81
- unless @color =~ /(#*)([0-9,a-f,A-F]{6})/
81
+ unless @color =~ /(#*)([0-9a-fA-F]{6})/
82
82
  raise SortedInputError.new "invalid color, must be in hex format, e.g. #FF0000"
83
83
  end
84
84
  @color = "##{@color}" unless @color.start_with?('#')
@@ -72,7 +72,7 @@ module OpenC3
72
72
  temp_dir = Dir.mktmpdir
73
73
  tf = nil
74
74
  begin
75
- if File.exists?(gem_file_path)
75
+ if File.exist?(gem_file_path)
76
76
  # Load gem to internal gem server
77
77
  OpenC3::GemModel.put(gem_file_path, gem_install: false, scope: scope) unless validate_only
78
78
  else
@@ -122,7 +122,6 @@ module OpenC3
122
122
  if existing_variables && existing_variables.key?(variable_name)
123
123
  variables[variable_name] = existing_variables[variable_name]
124
124
  end
125
- # Ignore everything else during phase 1
126
125
  end
127
126
  end
128
127
 
@@ -162,14 +161,21 @@ module OpenC3
162
161
  gem_path = File.join(temp_dir, "gem")
163
162
  FileUtils.mkdir_p(gem_path)
164
163
  pkg = Gem::Package.new(gem_file_path)
165
- needs_dependencies = pkg.spec.runtime_dependencies.length > 0
166
164
  pkg.extract_files(gem_path)
167
165
  Dir[File.join(gem_path, '**/screens/*.txt')].each do |filename|
168
166
  if File.basename(filename) != File.basename(filename).downcase
169
- raise "Invalid screen name: #{filename}. Screen names must be lowercase."
167
+ raise "Invalid screen filename: #{filename}. Screen filenames must be lowercase."
170
168
  end
171
169
  end
170
+ needs_dependencies = pkg.spec.runtime_dependencies.length > 0
172
171
  needs_dependencies = true if Dir.exist?(File.join(gem_path, 'lib'))
172
+ # If needs_dependencies hasn't already been set we need to scan the plugin.txt
173
+ # to see if they've explicitly set the NEEDS_DEPENDENCIES keyword
174
+ unless needs_dependencies
175
+ if plugin_hash['plugin_txt_lines'].join("\n").include?('NEEDS_DEPENDENCIES')
176
+ needs_dependencies = true
177
+ end
178
+ end
173
179
  if needs_dependencies
174
180
  plugin_model.needs_dependencies = true
175
181
  plugin_model.update unless validate_only
@@ -198,7 +204,7 @@ module OpenC3
198
204
  current_model = nil
199
205
  parser.parse_file(plugin_txt_path, false, true, true, variables) do |keyword, params|
200
206
  case keyword
201
- when 'VARIABLE'
207
+ when 'VARIABLE', 'NEEDS_DEPENDENCIES'
202
208
  # Ignore during phase 2
203
209
  when 'TARGET', 'INTERFACE', 'ROUTER', 'MICROSERVICE', 'TOOL', 'WIDGET'
204
210
  if current_model
@@ -206,12 +212,13 @@ module OpenC3
206
212
  current_model.deploy(gem_path, variables, validate_only: validate_only)
207
213
  current_model = nil
208
214
  end
209
- current_model = OpenC3.const_get((keyword.capitalize + 'Model').intern).handle_config(parser, keyword, params, plugin: plugin_model.name, needs_dependencies: needs_dependencies, scope: scope)
215
+ current_model = OpenC3.const_get((keyword.capitalize + 'Model').intern).handle_config(parser,
216
+ keyword, params, plugin: plugin_model.name, needs_dependencies: needs_dependencies, scope: scope)
210
217
  else
211
218
  if current_model
212
219
  current_model.handle_config(parser, keyword, params)
213
220
  else
214
- raise "Invalid keyword #{keyword} in plugin.txt"
221
+ raise "Invalid keyword '#{keyword}' in plugin.txt"
215
222
  end
216
223
  end
217
224
  end
@@ -91,7 +91,7 @@ module OpenC3
91
91
  if color.nil?
92
92
  color = '#%06x' % (rand * 0xffffff)
93
93
  end
94
- valid_color = color =~ /[0-9,a-f,A-F]{6}/
94
+ valid_color = color =~ /[0-9a-fA-F]{6}/
95
95
  if valid_color.nil?
96
96
  raise RuntimeError.new "invalid color but in hex format. #FF0000"
97
97
  end
@@ -92,7 +92,7 @@ module OpenC3
92
92
  if color.nil?
93
93
  color = '#%06x' % (rand * 0xffffff)
94
94
  end
95
- valid_color = color =~ /[0-9,a-f,A-F]{6}/
95
+ valid_color = color =~ /[0-9a-fA-F]{6}/
96
96
  if valid_color.nil?
97
97
  raise TriggerGroupInputError.new "invalid color must be in hex format. #FF0000"
98
98
  end
@@ -80,7 +80,7 @@ module OpenC3
80
80
 
81
81
  # @return [Hash] Whether or not messages should be printed for this state.
82
82
  # Given as STATE_NAME => true / false.
83
- attr_accessor :messages_disabled
83
+ attr_reader :messages_disabled
84
84
 
85
85
  # Colors associated with states
86
86
  # @return [Hash] State colors given as STATE_NAME => COLOR
@@ -77,7 +77,7 @@ module OpenC3
77
77
  else
78
78
  request.body_stream = io_or_string
79
79
  end
80
- response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
80
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
81
81
  http.request(request) do |response|
82
82
  response.value() # Raises an HTTP error if the response is not 2xx (success)
83
83
  return response
@@ -157,17 +157,17 @@ module OpenC3
157
157
  if $openc3_in_cluster
158
158
  case ENV['OPENC3_CLOUD']
159
159
  when 'local'
160
- uri = URI.parse("http://openc3-minio:9000" + url)
160
+ URI.parse("http://openc3-minio:9000" + url)
161
161
  when 'aws'
162
- uri = URI.parse("https://s3.#{ENV['AWS_REGION']}.amazonaws.com" + url)
162
+ URI.parse("https://s3.#{ENV['AWS_REGION']}.amazonaws.com" + url)
163
163
  when 'gcp'
164
- uri = URI.parse("https://storage.googleapis.com" + url)
164
+ URI.parse("https://storage.googleapis.com" + url)
165
165
  # when 'azure'
166
166
  else
167
167
  raise "Unknown cloud #{ENV['OPENC3_CLOUD']}"
168
168
  end
169
169
  else
170
- uri = URI.parse($api_server.generate_url + url)
170
+ URI.parse($api_server.generate_url + url)
171
171
  end
172
172
  end
173
173
 
@@ -51,7 +51,6 @@ module OpenC3
51
51
  @frame = ::WebSocket::Frame::Incoming::Client.new
52
52
  @handshaked = false
53
53
  @write_socket.write(@handshake.to_s)
54
- start_time = Time.now
55
54
  read() # This should wait for the handshake
56
55
  return true
57
56
  end
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3'
@@ -148,7 +148,6 @@ module OpenC3
148
148
  }
149
149
  col = 0
150
150
  row = 0
151
- num_cols = table.num_columns
152
151
  table.sorted_items.each_with_index do |item, index|
153
152
  next if item.hidden
154
153
  if table.num_columns == 1
@@ -111,7 +111,12 @@ module OpenC3
111
111
  token = nil
112
112
  result = []
113
113
  while true
114
- resp = @client.list_objects_v2(bucket: bucket, prefix: prefix, max_keys: max_request)
114
+ resp = @client.list_objects_v2({
115
+ bucket: bucket,
116
+ max_keys: max_request,
117
+ prefix: prefix,
118
+ continuation_token: token
119
+ })
115
120
  result.concat(resp.contents)
116
121
  break if result.length >= max_total
117
122
  break unless resp.is_truncated
@@ -119,12 +124,12 @@ module OpenC3
119
124
  end
120
125
  # Array of objects with key and size methods
121
126
  result
122
- rescue Aws::S3::Errors::NoSuchBucket => error
127
+ rescue Aws::S3::Errors::NoSuchBucket
123
128
  raise NotFound, "Bucket '#{bucket}' does not exist."
124
129
  end
125
130
 
126
131
  # Lists the files under a specified path
127
- def list_files(bucket:, path:, only_directories: false)
132
+ def list_files(bucket:, path:, only_directories: false, include_head: false)
128
133
  # Trailing slash is important in AWS S3 when listing files
129
134
  # See https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Types/ListObjectsV2Output.html#common_prefixes-instance_method
130
135
  if path[-1] != '/'
@@ -158,6 +163,9 @@ module OpenC3
158
163
  item['name'] = aws_item.key.split('/')[-1]
159
164
  item['modified'] = aws_item.last_modified
160
165
  item['size'] = aws_item.size
166
+ if include_head
167
+ item['head'] = head_object(bucket: bucket, key: aws_item.key)
168
+ end
161
169
  files << item
162
170
  end
163
171
  result = [dirs, files]
@@ -166,10 +174,20 @@ module OpenC3
166
174
  token = resp.next_continuation_token
167
175
  end
168
176
  result
169
- rescue Aws::S3::Errors::NoSuchBucket => error
177
+ rescue Aws::S3::Errors::NoSuchBucket
170
178
  raise NotFound, "Bucket '#{bucket}' does not exist."
171
179
  end
172
180
 
181
+ # get metadata for a specific object
182
+ def head_object(bucket:, key:)
183
+ head = @client.head_object({
184
+ bucket: bucket,
185
+ key: key
186
+ })
187
+ rescue Aws::S3::Errors::NotFound => error
188
+ raise NotFound, "Object: #{bucket}/#{key}"
189
+ end
190
+
173
191
  # put_object fires off the request to store but does not confirm
174
192
  def put_object(bucket:, key:, body:, content_type: nil, cache_control: nil, metadata: nil)
175
193
  @client.put_object(bucket: bucket, key: key, body: body,
@@ -57,10 +57,10 @@ class BucketFile
57
57
  cmd_or_tlm = path_split[2].to_s.upcase
58
58
  target_name = path_split[3].to_s.upcase
59
59
  if stream_mode == 'RAW'
60
- type = (@cmd_or_tlm == 'CMD') ? 'COMMAND' : 'TELEMETRY'
60
+ type = (cmd_or_tlm == 'CMD') ? 'COMMAND' : 'TELEMETRY'
61
61
  else
62
62
  if stream_mode == 'DECOM'
63
- type = (@cmd_or_tlm == 'CMD') ? 'DECOMCMD' : 'DECOM'
63
+ type = (cmd_or_tlm == 'CMD') ? 'DECOMCMD' : 'DECOM'
64
64
  else
65
65
  type = stream_mode # REDUCED_MINUTE, REDUCED_HOUR, or REDUCED_DAY
66
66
  end
@@ -156,6 +156,7 @@ class BucketFileCache
156
156
  @current_disk_usage = 0
157
157
  @queued_bucket_files = []
158
158
  @bucket_file_hash = {}
159
+ bucket_file = nil
159
160
 
160
161
  @thread = Thread.new do
161
162
  client = OpenC3::Bucket.getClient()
@@ -162,7 +162,7 @@ module OpenC3
162
162
 
163
163
  def self.get_file_times(bucket_path)
164
164
  basename = File.basename(bucket_path)
165
- file_start_timestamp, file_end_timestamp, other = basename.split("__")
165
+ file_start_timestamp, file_end_timestamp, _ = basename.split("__")
166
166
  file_start_time = DateTime.strptime(file_start_timestamp, FILE_TIMESTAMP_FORMAT).to_time
167
167
  file_end_time = DateTime.strptime(file_end_timestamp, FILE_TIMESTAMP_FORMAT).to_time
168
168
  return file_start_time, file_end_time