openc3 5.11.3 → 5.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/bin/openc3cli +26 -12
  4. data/data/config/_id_items.yaml +6 -4
  5. data/data/config/_id_params.yaml +9 -6
  6. data/data/config/_items.yaml +6 -4
  7. data/data/config/_params.yaml +3 -2
  8. data/data/config/interface_modifiers.yaml +1 -1
  9. data/data/config/microservice.yaml +10 -1
  10. data/data/config/plugins.yaml +13 -3
  11. data/data/config/target.yaml +9 -0
  12. data/data/config/target_config.yaml +12 -0
  13. data/data/config/tool.yaml +12 -3
  14. data/lib/openc3/api/api.rb +1 -1
  15. data/lib/openc3/api/cmd_api.rb +24 -24
  16. data/lib/openc3/api/config_api.rb +12 -12
  17. data/lib/openc3/api/limits_api.rb +4 -3
  18. data/lib/openc3/api/settings_api.rb +5 -2
  19. data/lib/openc3/api/tlm_api.rb +7 -10
  20. data/lib/openc3/conversions/unix_time_conversion.rb +8 -6
  21. data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -7
  22. data/lib/openc3/io/json_drb.rb +3 -2
  23. data/lib/openc3/io/json_rpc.rb +6 -6
  24. data/lib/openc3/logs/buffered_packet_log_writer.rb +4 -2
  25. data/lib/openc3/logs/packet_log_writer.rb +22 -7
  26. data/lib/openc3/microservices/cleanup_microservice.rb +8 -1
  27. data/lib/openc3/microservices/decom_microservice.rb +1 -1
  28. data/lib/openc3/microservices/interface_microservice.rb +2 -2
  29. data/lib/openc3/microservices/microservice.rb +5 -2
  30. data/lib/openc3/microservices/reaction_microservice.rb +1 -0
  31. data/lib/openc3/microservices/timeline_microservice.rb +7 -5
  32. data/lib/openc3/migrations/20231022000000_tlm_viewer_config.rb +22 -0
  33. data/lib/openc3/models/activity_model.rb +21 -3
  34. data/lib/openc3/models/cvt_model.rb +2 -1
  35. data/lib/openc3/models/gem_model.rb +4 -1
  36. data/lib/openc3/models/interface_model.rb +11 -5
  37. data/lib/openc3/models/metadata_model.rb +11 -0
  38. data/lib/openc3/models/microservice_model.rb +16 -3
  39. data/lib/openc3/models/model.rb +18 -0
  40. data/lib/openc3/models/note_model.rb +11 -0
  41. data/lib/openc3/models/plugin_model.rb +18 -0
  42. data/lib/openc3/models/python_package_model.rb +104 -0
  43. data/lib/openc3/models/scope_model.rb +2 -0
  44. data/lib/openc3/models/sorted_model.rb +17 -8
  45. data/lib/openc3/models/target_model.rb +53 -18
  46. data/lib/openc3/models/tool_config_model.rb +9 -3
  47. data/lib/openc3/models/tool_model.rb +22 -7
  48. data/lib/openc3/models/widget_model.rb +19 -3
  49. data/lib/openc3/operators/microservice_operator.rb +2 -0
  50. data/lib/openc3/packets/limits.rb +6 -18
  51. data/lib/openc3/packets/packet.rb +1 -0
  52. data/lib/openc3/packets/parsers/format_string_parser.rb +4 -4
  53. data/lib/openc3/packets/parsers/limits_parser.rb +4 -4
  54. data/lib/openc3/packets/parsers/limits_response_parser.rb +5 -5
  55. data/lib/openc3/packets/parsers/processor_parser.rb +4 -4
  56. data/lib/openc3/packets/parsers/state_parser.rb +3 -3
  57. data/lib/openc3/script/api_shared.rb +50 -32
  58. data/lib/openc3/script/calendar.rb +109 -0
  59. data/lib/openc3/script/commands.rb +1 -8
  60. data/lib/openc3/script/{gems.rb → packages.rb} +20 -16
  61. data/lib/openc3/script/script.rb +49 -38
  62. data/lib/openc3/system/system.rb +2 -0
  63. data/lib/openc3/system/target.rb +10 -1
  64. data/lib/openc3/top_level.rb +2 -2
  65. data/lib/openc3/utilities/aws_bucket.rb +3 -2
  66. data/lib/openc3/utilities/bucket_file_cache.rb +1 -1
  67. data/lib/openc3/utilities/local_mode.rb +3 -1
  68. data/lib/openc3/utilities/logger.rb +1 -1
  69. data/lib/openc3/utilities/ruby_lex_utils.rb +0 -8
  70. data/lib/openc3/version.rb +6 -6
  71. data/templates/tool_angular/package.json +14 -14
  72. data/templates/tool_angular/yarn.lock +282 -129
  73. data/templates/tool_react/package.json +11 -11
  74. data/templates/tool_react/yarn.lock +353 -300
  75. data/templates/tool_svelte/package.json +12 -12
  76. data/templates/tool_svelte/src/services/openc3-api.js +16 -60
  77. data/templates/tool_svelte/yarn.lock +338 -212
  78. data/templates/tool_vue/package.json +9 -9
  79. data/templates/tool_vue/yarn.lock +55 -41
  80. data/templates/widget/package.json +10 -10
  81. data/templates/widget/yarn.lock +59 -45
  82. metadata +36 -5
@@ -67,22 +67,19 @@ module OpenC3
67
67
  # @param type [Symbol] Telemetry type, :RAW, :CONVERTED (default), :FORMATTED, or :WITH_UNITS
68
68
  # @return [Object] The telemetry value formatted as requested
69
69
  def tlm(*args, type: :CONVERTED, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
70
- target_name, packet_name, item_name = tlm_process_args(args, 'tlm', cache_timeout: cache_timeout, scope: scope)
70
+ target_name, packet_name, item_name = _tlm_process_args(args, 'tlm', cache_timeout: cache_timeout, scope: scope)
71
71
  authorize(permission: 'tlm', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
72
72
  CvtModel.get_item(target_name, packet_name, item_name, type: type.intern, cache_timeout: cache_timeout, scope: scope)
73
73
  end
74
74
 
75
- # @deprecated Use tlm with type: :RAW
76
75
  def tlm_raw(*args, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
77
76
  tlm(*args, type: :RAW, cache_timeout: cache_timeout, scope: scope, token: token)
78
77
  end
79
78
 
80
- # @deprecated Use tlm with type: :FORMATTED
81
79
  def tlm_formatted(*args, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
82
80
  tlm(*args, type: :FORMATTED, cache_timeout: cache_timeout, scope: scope, token: token)
83
81
  end
84
82
 
85
- # @deprecated Use tlm with type: :WITH_UNITS
86
83
  def tlm_with_units(*args, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
87
84
  tlm(*args, type: :WITH_UNITS, cache_timeout: cache_timeout, scope: scope, token: token)
88
85
  end
@@ -108,7 +105,7 @@ module OpenC3
108
105
  # @param args [String|Array<String>] See the description for calling style
109
106
  # @param type [Symbol] Telemetry type, :RAW, :CONVERTED (default), :FORMATTED, or :WITH_UNITS
110
107
  def set_tlm(*args, type: :CONVERTED, scope: $openc3_scope, token: $openc3_token)
111
- target_name, packet_name, item_name, value = set_tlm_process_args(args, __method__, scope: scope)
108
+ target_name, packet_name, item_name, value = _set_tlm_process_args(args, __method__, scope: scope)
112
109
  authorize(permission: 'tlm_set', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
113
110
  CvtModel.set_item(target_name, packet_name, item_name, value, type: type.intern, scope: scope)
114
111
  end
@@ -169,7 +166,7 @@ module OpenC3
169
166
  # description).
170
167
  # @param type [Symbol] Telemetry type, :ALL (default), :RAW, :CONVERTED, :FORMATTED, :WITH_UNITS
171
168
  def override_tlm(*args, type: :ALL, scope: $openc3_scope, token: $openc3_token)
172
- target_name, packet_name, item_name, value = set_tlm_process_args(args, __method__, scope: scope)
169
+ target_name, packet_name, item_name, value = _set_tlm_process_args(args, __method__, scope: scope)
173
170
  authorize(permission: 'tlm_set', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
174
171
  CvtModel.override(target_name, packet_name, item_name, value, type: type.intern, scope: scope)
175
172
  end
@@ -194,7 +191,7 @@ module OpenC3
194
191
  # @param type [Symbol] Telemetry type, :ALL (default), :RAW, :CONVERTED, :FORMATTED, :WITH_UNITS
195
192
  # Also takes :ALL which means to normalize all telemetry types
196
193
  def normalize_tlm(*args, type: :ALL, scope: $openc3_scope, token: $openc3_token)
197
- target_name, packet_name, item_name = tlm_process_args(args, __method__, scope: scope)
194
+ target_name, packet_name, item_name = _tlm_process_args(args, __method__, scope: scope)
198
195
  authorize(permission: 'tlm_set', target_name: target_name, packet_name: packet_name, scope: scope, token: token)
199
196
  CvtModel.normalize(target_name, packet_name, item_name, type: type.intern, scope: scope)
200
197
  end
@@ -389,7 +386,7 @@ module OpenC3
389
386
  # Get the transmit counts for telemetry packets
390
387
  #
391
388
  # @param target_packets [Array<Array<String, String>>] Array of arrays containing target_name, packet_name
392
- # @return [Numeric] Transmit count for the command
389
+ # @return [Array<Numeric>] Receive count for the telemetry packets
393
390
  def get_tlm_cnts(target_packets, scope: $openc3_scope, token: $openc3_token)
394
391
  authorize(permission: 'system', scope: scope, token: token)
395
392
  counts = []
@@ -430,7 +427,7 @@ module OpenC3
430
427
  return nil
431
428
  end
432
429
 
433
- def tlm_process_args(args, method_name, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
430
+ def _tlm_process_args(args, method_name, cache_timeout: 0.1, scope: $openc3_scope, token: $openc3_token)
434
431
  case args.length
435
432
  when 1
436
433
  target_name, packet_name, item_name = extract_fields_from_tlm_text(args[0])
@@ -456,7 +453,7 @@ module OpenC3
456
453
  return [target_name, packet_name, item_name]
457
454
  end
458
455
 
459
- def set_tlm_process_args(args, method_name, scope: $openc3_scope, token: $openc3_token)
456
+ def _set_tlm_process_args(args, method_name, scope: $openc3_scope, token: $openc3_token)
460
457
  case args.length
461
458
  when 1
462
459
  target_name, packet_name, item_name, value = extract_fields_from_set_tlm_text(args[0])
@@ -31,30 +31,32 @@ module OpenC3
31
31
  # represents the number of seconds since the UNIX time epoch
32
32
  # @param microseconds_item_name [String] The telemetry item in the packet
33
33
  # which represents microseconds
34
- def initialize(seconds_item_name, microseconds_item_name = nil)
34
+ def initialize(seconds_item_name, microseconds_item_name = nil, seconds_type = 'RAW', microseconds_type = 'RAW')
35
35
  super()
36
36
  @seconds_item_name = seconds_item_name
37
37
  @microseconds_item_name = microseconds_item_name
38
38
  @converted_type = :RUBY_TIME
39
39
  @converted_bit_size = 0
40
+ @seconds_type = seconds_type.to_sym
41
+ @microseconds_type = microseconds_type.to_sym
40
42
  end
41
43
 
42
44
  # @param (see Conversion#call)
43
45
  # @return [Float] Packet time in seconds since UNIX epoch
44
46
  def call(value, packet, buffer)
45
47
  if @microseconds_item_name
46
- return Time.at(packet.read(@seconds_item_name, :RAW, buffer), packet.read(@microseconds_item_name, :RAW, buffer)).sys
48
+ return Time.at(packet.read(@seconds_item_name, @seconds_type, buffer), packet.read(@microseconds_item_name, @microseconds_type, buffer)).sys
47
49
  else
48
- return Time.at(packet.read(@seconds_item_name, :RAW, buffer), 0).sys
50
+ return Time.at(packet.read(@seconds_item_name, @seconds_type, buffer), 0).sys
49
51
  end
50
52
  end
51
53
 
52
54
  # @return [String] The name of the class followed by the time conversion
53
55
  def to_s
54
56
  if @microseconds_item_name
55
- return "Time.at(packet.read('#{@seconds_item_name}', :RAW, buffer), packet.read('#{@microseconds_item_name}', :RAW, buffer)).sys"
57
+ return "Time.at(packet.read('#{@seconds_item_name}', :#{@seconds_type}, buffer), packet.read('#{@microseconds_item_name}', :#{@microseconds_type}, buffer)).sys"
56
58
  else
57
- return "Time.at(packet.read('#{@seconds_item_name}', :RAW, buffer), 0).sys"
59
+ return "Time.at(packet.read('#{@seconds_item_name}', :#{@seconds_type}, buffer), 0).sys"
58
60
  end
59
61
  end
60
62
 
@@ -66,7 +68,7 @@ module OpenC3
66
68
 
67
69
  def as_json(*a)
68
70
  result = super(*a)
69
- result['params'] = [@seconds_item_name, @microseconds_item_name]
71
+ result['params'] = [@seconds_item_name, @microseconds_item_name, @seconds_type, @microseconds_type]
70
72
  result
71
73
  end
72
74
  end # class UnixTimeConversion
@@ -500,13 +500,6 @@ module OpenC3
500
500
  write_to_clients(:write_raw, data) if data
501
501
  end
502
502
 
503
- def interface_disconnect(interface_info)
504
- Logger.info "#{@name}: Tcpip server lost write connection to "\
505
- "#{interface_info.hostname}(#{interface_info.host_ip}):#{interface_info.port}"
506
- interface_info.interface.disconnect
507
- interface_info.interface.stream_log_pair.stop if interface_info.interface.stream_log_pair
508
- end
509
-
510
503
  def write_thread_hook(packet)
511
504
  packet # By default just return the packet
512
505
  end
@@ -28,7 +28,8 @@ require 'drb/drb'
28
28
  require 'set'
29
29
  require 'openc3/io/json_rpc'
30
30
  require 'openc3/io/json_drb_rack'
31
- require 'rack/handler/puma'
31
+ require 'rackup'
32
+ require 'puma'
32
33
 
33
34
  # Add methods to the Puma::Launcher and Puma::Single class so we can tell
34
35
  # if the server has been started.
@@ -150,7 +151,7 @@ module OpenC3
150
151
  }
151
152
 
152
153
  # The run call will block until the server is stopped.
153
- Rack::Handler::Puma.run(JsonDrbRack.new(self), server_config) do |server|
154
+ Rackup::Handler::Puma.run(JsonDrbRack.new(self), server_config) do |server|
154
155
  @server_mutex.synchronize do
155
156
  @server = server
156
157
  end
@@ -36,9 +36,9 @@ end
36
36
 
37
37
  class Struct #:nodoc:
38
38
  def as_json(options = nil)
39
- pairs = []
40
- self.each_pair { |k, v| pairs << k.to_s; pairs << v.as_json(options) }
41
- Hash[*pairs]
39
+ hash = {}
40
+ self.each_pair { |k, v| hash[k.to_s] = v.as_json(options) }
41
+ hash
42
42
  end
43
43
  end
44
44
 
@@ -115,9 +115,9 @@ end
115
115
 
116
116
  class Hash
117
117
  def as_json(options = nil) #:nodoc:
118
- pairs = []
119
- self.each { |k, v| pairs << k.to_s; pairs << v.as_json(options) }
120
- Hash[*pairs]
118
+ hash = {}
119
+ self.each {|k,v| hash[k.to_s] = v.as_json(options) }
120
+ hash
121
121
  end
122
122
  end
123
123
 
@@ -44,7 +44,8 @@ module OpenC3
44
44
  cycle_hour = nil,
45
45
  cycle_minute = nil,
46
46
  enforce_time_order = true,
47
- buffer_depth = 60 # Default assumes 1 minute of 1Hz data
47
+ buffer_depth = 60, # Default assumes 1 minute of 1Hz data
48
+ scope: $openc3_scope
48
49
  )
49
50
  super(
50
51
  remote_log_directory,
@@ -54,7 +55,8 @@ module OpenC3
54
55
  cycle_size,
55
56
  cycle_hour,
56
57
  cycle_minute,
57
- enforce_time_order
58
+ enforce_time_order,
59
+ scope: scope
58
60
  )
59
61
  @buffer_depth = Integer(buffer_depth)
60
62
  @buffer = []
@@ -22,6 +22,7 @@
22
22
 
23
23
  require 'openc3/logs/log_writer'
24
24
  require 'openc3/logs/packet_log_constants'
25
+ require 'openc3/models/target_model'
25
26
  require 'cbor'
26
27
 
27
28
  module OpenC3
@@ -52,7 +53,8 @@ module OpenC3
52
53
  cycle_size = 1_000_000_000,
53
54
  cycle_hour = nil,
54
55
  cycle_minute = nil,
55
- enforce_time_order = true
56
+ enforce_time_order = true,
57
+ scope: $openc3_scope
56
58
  )
57
59
  super(
58
60
  remote_log_directory,
@@ -73,6 +75,9 @@ module OpenC3
73
75
  @target_indexes = {}
74
76
  @next_target_index = 0
75
77
  @data_format = :CBOR # Default to CBOR for improved compression
78
+ @target_id_cache = {}
79
+ @packet_id_cache = {}
80
+ @scope = scope
76
81
  end
77
82
 
78
83
  # Write a packet to the log file.
@@ -171,8 +176,14 @@ module OpenC3
171
176
  @tlm_packet_table[target_name] = target_table
172
177
  end
173
178
  id = nil
174
- target = System.targets[target_name]
175
- id = target.id if target
179
+ unless ENV['OPENC3_NO_STORE']
180
+ id = @target_id_cache[target_name]
181
+ unless id
182
+ target = TargetModel.get(name: target_name, scope: @scope)
183
+ id = target["id"] if target
184
+ @target_id_cache[target_name] = id
185
+ end
186
+ end
176
187
  write_entry(:TARGET_DECLARATION, cmd_or_tlm, target_name, packet_name, nil, nil, nil, id)
177
188
  end
178
189
 
@@ -187,10 +198,14 @@ module OpenC3
187
198
 
188
199
  id = nil
189
200
  begin
190
- if cmd_or_tlm == :CMD
191
- id = System.commands.packet(target_nam, packet_name).config_name
192
- else
193
- id = System.telemetry.packet(target_name, packet_name).config_name
201
+ unless ENV['OPENC3_NO_STORE']
202
+ cache_key = "#{cmd_or_tlm}__#{target_name}__#{packet_name}"
203
+ id = @packet_id_cache[cache_key]
204
+ unless id
205
+ target_model_packet = TargetModel.packet(target_name, packet_name, type: cmd_or_tlm, scope: @scope)
206
+ id = target_model_packet["config_name"] if target_model_packet
207
+ @packet_id_cache[cache_key] = id
208
+ end
194
209
  end
195
210
  rescue
196
211
  # No packet def
@@ -49,7 +49,14 @@ module OpenC3
49
49
  if oldest_list.length > 0
50
50
  @state = 'DELETING_OBJECTS'
51
51
  oldest_list.each_slice(1000) do |slice|
52
- bucket.delete_objects(bucket: ENV['OPENC3_LOGS_BUCKET'], keys: slice)
52
+ # The delete_objects function utilizes an MD5 hash when verifying the checksums, which is not
53
+ # FIPS compliant (https://github.com/aws/aws-sdk-ruby/issues/2645).
54
+ # delete_object does NOT require an MD5 hash and will work on FIPS compliant systems. It is
55
+ # probably less performant, but we can instead delete each item one at a time.
56
+ # bucket.delete_objects(bucket: ENV['OPENC3_LOGS_BUCKET'], keys: slice)
57
+ slice.each do |item|
58
+ bucket.delete_object(bucket: ENV['OPENC3_LOGS_BUCKET'], key: item)
59
+ end
53
60
  @logger.debug("Cleanup deleted #{slice.length} log files")
54
61
  @delete_count += slice.length
55
62
  @metric.set(name: 'cleanup_delete_total', value: @delete_count, type: 'counter')
@@ -34,7 +34,7 @@ module OpenC3
34
34
  # Should only be one target, but there might be multiple decom microservices for a given target
35
35
  # First Decom microservice has no number in the name
36
36
  if @name =~ /__DECOM__/
37
- @topics << "#{scope}__DECOMINTERFACE__{#{@target_names[0]}}"
37
+ @topics << "#{@scope}__DECOMINTERFACE__{#{@target_names[0]}}"
38
38
  end
39
39
  Topic.update_topic_offsets(@topics)
40
40
  System.telemetry.limits_change_callback = method(:limits_change_callback)
@@ -348,13 +348,13 @@ module OpenC3
348
348
  def initialize(name)
349
349
  @mutex = Mutex.new
350
350
  super(name)
351
+ @interface_or_router = self.class.name.to_s.split("Microservice")[0].upcase.split("::")[-1]
351
352
  if @interface_or_router == 'INTERFACE'
352
353
  @metric.set(name: 'interface_tlm_total', value: @count, type: 'counter')
353
354
  else
354
355
  @metric.set(name: 'router_cmd_total', value: @count, type: 'counter')
355
356
  end
356
357
 
357
- @interface_or_router = self.class.name.to_s.split("Microservice")[0].upcase.split("::")[-1]
358
358
  @scope = name.split("__")[0]
359
359
  interface_name = name.split("__")[2]
360
360
  if @interface_or_router == 'INTERFACE'
@@ -553,7 +553,7 @@ module OpenC3
553
553
  unknown_packet.extra = packet.extra
554
554
  packet = unknown_packet
555
555
  json_hash = CvtModel.build_json_from_packet(packet)
556
- CvtModel.set(json_hash, target_name: packet.target_name, packet_name: packet.packet_name, scope: scope)
556
+ CvtModel.set(json_hash, target_name: packet.target_name, packet_name: packet.packet_name, scope: @scope)
557
557
  num_bytes_to_print = [UNKNOWN_BYTES_TO_PRINT, packet.length].min
558
558
  data = packet.buffer(false)[0..(num_bytes_to_print - 1)]
559
559
  prefix = data.each_byte.map { | byte | sprintf("%02X", byte) }.join()
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2023, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -79,7 +79,7 @@ module OpenC3
79
79
  end
80
80
 
81
81
  def initialize(name, is_plugin: false)
82
- Logger.info("Microservice running from: ruby #{$0} #{ARGV.join(" ")}")
82
+ @shutdown_complete = false
83
83
  raise "Microservice must be named" unless name
84
84
 
85
85
  @name = name
@@ -120,6 +120,7 @@ module OpenC3
120
120
  # Get configuration for any targets
121
121
  @target_names = @config["target_names"]
122
122
  @target_names ||= []
123
+ # NOTE: setup_targets doesn't do anything if @target_names is empty
123
124
  System.setup_targets(@target_names, @temp_dir, scope: @scope) unless is_plugin
124
125
 
125
126
  # Use at_exit to shutdown cleanly no matter how we die
@@ -199,6 +200,7 @@ module OpenC3
199
200
  end
200
201
 
201
202
  def shutdown
203
+ return if @shutdown_complete
202
204
  @logger.info("Shutting down microservice: #{@name}")
203
205
  @cancel_thread = true
204
206
  @microservice_status_sleeper.cancel if @microservice_status_sleeper
@@ -206,6 +208,7 @@ module OpenC3
206
208
  FileUtils.remove_entry(@temp_dir) if File.exist?(@temp_dir)
207
209
  @metric.shutdown
208
210
  @logger.info("Shutting down microservice complete: #{@name}")
211
+ @shutdown_complete = true
209
212
  end
210
213
  end
211
214
  end
@@ -229,6 +229,7 @@ module OpenC3
229
229
 
230
230
  def get_token(username)
231
231
  if ENV['OPENC3_API_CLIENT'].nil?
232
+ ENV['OPENC3_API_PASSWORD'] ||= ENV['OPENC3_SERVICE_PASSWORD']
232
233
  return OpenC3Authentication.new().token
233
234
  else
234
235
  # Check for offline access token
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2023, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -43,6 +43,7 @@ module OpenC3
43
43
 
44
44
  def get_token(username)
45
45
  if ENV['OPENC3_API_CLIENT'].nil?
46
+ ENV['OPENC3_API_PASSWORD'] ||= ENV['OPENC3_SERVICE_PASSWORD']
46
47
  return OpenC3Authentication.new().token
47
48
  else
48
49
  # Check for offline access token
@@ -125,7 +126,8 @@ module OpenC3
125
126
 
126
127
  def clear_expired(activity)
127
128
  begin
128
- ActivityModel.range_destroy(name: @timeline_name, scope: @scope, min: activity.start, max: activity.stop)
129
+ num = ActivityModel.range_destroy(name: @timeline_name, scope: @scope, min: activity.start, max: activity.stop)
130
+ @logger.info "#{@timeline_name} clear_expired removed #{num} items from #{activity.start} to #{activity.stop}"
129
131
  activity.add_event(status: 'completed')
130
132
  rescue StandardError => e
131
133
  @logger.error "#{@timeline_name} clear_expired failed > #{activity.as_json(:allow_nan => true)} #{e.message}"
@@ -231,15 +233,15 @@ module OpenC3
231
233
  @logger.info "#{@timeline_name} timeine manager exiting"
232
234
  end
233
235
 
234
- # Add task to remove events older than 7 time
236
+ # Add task to remove events older than 7 days
235
237
  def add_expire_activity
236
238
  now = Time.now.to_i
237
239
  @expire = now + 3_000
238
240
  activity = ActivityModel.new(
239
241
  name: @timeline_name,
240
242
  scope: @scope,
241
- start: (now - 86_400 * 7),
242
- stop: (now - 82_800 * 7),
243
+ start: 0,
244
+ stop: (now - 86_400 * 7),
243
245
  kind: 'EXPIRE',
244
246
  data: {}
245
247
  )
@@ -0,0 +1,22 @@
1
+ require 'openc3/utilities/migration'
2
+ require 'openc3/models/tool_config_model'
3
+
4
+ module OpenC3
5
+ class TlmViewerConfig < Migration
6
+ def self.run
7
+ ScopeModel.names.each do |scope|
8
+ # Get all existing ToolConfigModels and change keys from tlm_viewer to telemetry_viewer
9
+ names = ToolConfigModel.list_configs('tlm_viewer')
10
+ names.each do |name|
11
+ config = ToolConfigModel.load_config('tlm_viewer', name)
12
+ ToolConfigModel.save_config('telemetry_viewer', name, config)
13
+ ToolConfigModel.delete_config('tlm_viewer', name)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ unless ENV['OPENC3_NO_MIGRATE']
21
+ OpenC3::TlmViewerConfig.run
22
+ end
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2023, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -94,13 +94,31 @@ module OpenC3
94
94
  # Remove one member from a sorted set.
95
95
  # @return [Integer] count of the members removed
96
96
  def self.destroy(name:, scope:, score:)
97
- Store.zremrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", score, score)
97
+ result = Store.zremrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", score, score)
98
+ notification = {
99
+ # start / stop to match SortedModel
100
+ 'data' => JSON.generate({'start' => score}),
101
+ 'kind' => 'deleted',
102
+ 'type' => 'activity',
103
+ 'timeline' => name
104
+ }
105
+ TimelineTopic.write_activity(notification, scope: scope)
106
+ return result
98
107
  end
99
108
 
100
109
  # Remove members from min to max of the sorted set.
101
110
  # @return [Integer] count of the members removed
102
111
  def self.range_destroy(name:, scope:, min:, max:)
103
- Store.zremrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", min, max)
112
+ result = Store.zremrangebyscore("#{scope}#{PRIMARY_KEY}__#{name}", min, max)
113
+ notification = {
114
+ # start / stop to match SortedModel
115
+ 'data' => JSON.generate({'start' => min, 'stop' => max}),
116
+ 'kind' => 'deleted',
117
+ 'type' => 'activity',
118
+ 'timeline' => name
119
+ }
120
+ TimelineTopic.write_activity(notification, scope: scope)
121
+ return result
104
122
  end
105
123
 
106
124
  # @return [ActivityModel] Model generated from the passed JSON
@@ -237,10 +237,11 @@ module OpenC3
237
237
  end
238
238
 
239
239
  tgt_pkt_key = "#{scope}__tlm__#{target_name}__#{packet_name}"
240
- @@override_cache[tgt_pkt_key] = [Time.now, hash]
241
240
  if hash.empty?
241
+ @@override_cache.delete(tgt_pkt_key)
242
242
  Store.hdel("#{scope}__override__#{target_name}", packet_name)
243
243
  else
244
+ @@override_cache[tgt_pkt_key] = [Time.now, hash]
244
245
  Store.hset("#{scope}__override__#{target_name}", packet_name, JSON.generate(hash.as_json(:allow_nan => true)))
245
246
  end
246
247
  end
@@ -27,6 +27,7 @@ require 'rubygems'
27
27
  require 'rubygems/uninstaller'
28
28
  require 'tempfile'
29
29
  require 'openc3/utilities/process_manager'
30
+ require 'openc3/api/api'
30
31
  require 'pathname'
31
32
 
32
33
  module OpenC3
@@ -35,6 +36,8 @@ module OpenC3
35
36
  # and destroy to allow interaction with gem files from the PluginModel and
36
37
  # the GemsController.
37
38
  class GemModel
39
+ include Api
40
+
38
41
  def self.names
39
42
  result = Pathname.new("#{ENV['GEM_HOME']}/gems").children.select { |c| c.directory? }.collect { |p| File.basename(p) + '.gem' }
40
43
  return result.sort
@@ -53,7 +56,7 @@ module OpenC3
53
56
  FileUtils.cp(gem_file_path, "#{ENV['GEM_HOME']}/cache/#{File.basename(gem_file_path)}")
54
57
  if gem_install
55
58
  Logger.info "Installing gem: #{gem_filename}"
56
- result = OpenC3::ProcessManager.instance.spawn(["ruby", "/openc3/bin/openc3cli", "geminstall", gem_filename, scope], "gem_install", gem_filename, Time.now + 3600.0, scope: scope)
59
+ result = OpenC3::ProcessManager.instance.spawn(["ruby", "/openc3/bin/openc3cli", "geminstall", gem_filename, scope], "package_install", gem_filename, Time.now + 3600.0, scope: scope)
57
60
  return result.name
58
61
  end
59
62
  else
@@ -145,7 +145,13 @@ module OpenC3
145
145
  unless @cmd
146
146
  type = self.class._get_type
147
147
  microservice_name = "#{@scope}__#{type}__#{@name}"
148
- @cmd = ["ruby", "#{type.downcase}_microservice.rb", microservice_name]
148
+ if config_params[0] and File.extname(config_params[0]) == '.py'
149
+ work_dir.sub!('openc3/lib', 'openc3/python')
150
+ @cmd = ["python", "#{type.downcase}_microservice.py", microservice_name]
151
+ else
152
+ # If there are no config_params we assume ruby
153
+ @cmd = ["ruby", "#{type.downcase}_microservice.rb", microservice_name]
154
+ end
149
155
  end
150
156
  @work_dir = work_dir
151
157
  @ports = ports
@@ -417,7 +423,7 @@ module OpenC3
417
423
  # Respawn the microservice
418
424
  type = self.class._get_type
419
425
  microservice_name = "#{@scope}__#{type}__#{@name}"
420
- microservice = MicroserviceModel.get_model(name: microservice_name, scope: scope)
426
+ microservice = MicroserviceModel.get_model(name: microservice_name, scope: @scope)
421
427
  microservice.target_names.delete(target_name) unless @target_names.include?(target_name)
422
428
  microservice.update
423
429
  end
@@ -432,11 +438,11 @@ module OpenC3
432
438
 
433
439
  if unmap_old
434
440
  # Remove from old interface
435
- all_interfaces = InterfaceModel.all(scope: scope)
441
+ all_interfaces = InterfaceModel.all(scope: @scope)
436
442
  old_interface = nil
437
443
  all_interfaces.each do |old_interface_name, old_interface_details|
438
444
  if old_interface_details['target_names'].include?(target_name)
439
- old_interface = InterfaceModel.from_json(old_interface_details, scope: scope)
445
+ old_interface = InterfaceModel.from_json(old_interface_details, scope: @scope)
440
446
  old_interface.unmap_target(target_name, cmd_only: cmd_only, tlm_only: tlm_only) if old_interface
441
447
  end
442
448
  end
@@ -451,7 +457,7 @@ module OpenC3
451
457
  # Respawn the microservice
452
458
  type = self.class._get_type
453
459
  microservice_name = "#{@scope}__#{type}__#{@name}"
454
- microservice = MicroserviceModel.get_model(name: microservice_name, scope: scope)
460
+ microservice = MicroserviceModel.get_model(name: microservice_name, scope: @scope)
455
461
  microservice.target_names << target_name unless microservice.target_names.include?(target_name)
456
462
  microservice.update
457
463
  end
@@ -33,6 +33,17 @@ module OpenC3
33
33
  "#{scope}#{PRIMARY_KEY}"
34
34
  end
35
35
 
36
+ def self.notify(scope:, kind:, start:, stop: nil)
37
+ json = {'type' => METADATA_TYPE, 'start' => start}
38
+ json['stop'] = stop if stop
39
+ notification = {
40
+ 'data' => JSON.generate(json),
41
+ 'kind' => kind,
42
+ 'type' => 'calendar',
43
+ }
44
+ CalendarTopic.write_entry(notification, scope: scope)
45
+ end
46
+
36
47
  attr_reader :color, :metadata, :constraints, :type
37
48
 
38
49
  # @param [Integer] start - Time metadata is active in seconds from Epoch
@@ -42,6 +42,7 @@ module OpenC3
42
42
  attr_accessor :parent
43
43
  attr_accessor :secrets
44
44
  attr_accessor :prefix
45
+ attr_accessor :disable_erb
45
46
 
46
47
  # NOTE: The following three class methods are used by the ModelController
47
48
  # and are reimplemented to enable various Model class methods to work
@@ -101,6 +102,7 @@ module OpenC3
101
102
  needs_dependencies: false,
102
103
  secrets: [],
103
104
  prefix: nil,
105
+ disable_erb: nil,
104
106
  scope:
105
107
  )
106
108
  parts = name.split("__")
@@ -125,6 +127,7 @@ module OpenC3
125
127
  @needs_dependencies = needs_dependencies
126
128
  @secrets = secrets
127
129
  @prefix = prefix
130
+ @disable_erb = disable_erb
128
131
  @bucket = Bucket.getClient()
129
132
  end
130
133
 
@@ -145,7 +148,8 @@ module OpenC3
145
148
  'plugin' => @plugin,
146
149
  'needs_dependencies' => @needs_dependencies,
147
150
  'secrets' => @secrets.as_json(*a),
148
- 'prefix' => @prefix
151
+ 'prefix' => @prefix,
152
+ 'disable_erb' => @disable_erb
149
153
  }
150
154
  end
151
155
 
@@ -201,6 +205,12 @@ module OpenC3
201
205
  when 'ROUTE_PREFIX'
202
206
  parser.verify_num_parameters(1, 1, "#{keyword} <Route Prefix>")
203
207
  @prefix = parameters[0]
208
+ when 'DISABLE_ERB'
209
+ # 0 to unlimited parameters
210
+ @disable_erb ||= []
211
+ if parameters
212
+ @disable_erb.concat(parameters)
213
+ end
204
214
  else
205
215
  raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Microservice: #{keyword} #{parameters.join(" ")}")
206
216
  end
@@ -220,8 +230,11 @@ module OpenC3
220
230
 
221
231
  # Load microservice files
222
232
  data = File.read(filename, mode: "rb")
223
- OpenC3.set_working_dir(File.dirname(filename)) do
224
- data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
233
+ erb_disabled = check_disable_erb(filename)
234
+ unless erb_disabled
235
+ OpenC3.set_working_dir(File.dirname(filename)) do
236
+ data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
237
+ end
225
238
  end
226
239
  unless validate_only
227
240
  @bucket.put_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: key, body: data)