openc3 5.11.3 → 5.13.0

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.

Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/bin/openc3cli +29 -15
  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/graph_settings.yaml +1 -1
  9. data/data/config/interface_modifiers.yaml +1 -1
  10. data/data/config/item_modifiers.yaml +1 -2
  11. data/data/config/microservice.yaml +10 -1
  12. data/data/config/parameter_modifiers.yaml +13 -14
  13. data/data/config/plugins.yaml +13 -3
  14. data/data/config/screen.yaml +1 -2
  15. data/data/config/target.yaml +9 -0
  16. data/data/config/target_config.yaml +14 -6
  17. data/data/config/tool.yaml +12 -3
  18. data/lib/openc3/api/api.rb +1 -1
  19. data/lib/openc3/api/cmd_api.rb +123 -59
  20. data/lib/openc3/api/config_api.rb +12 -12
  21. data/lib/openc3/api/limits_api.rb +4 -3
  22. data/lib/openc3/api/settings_api.rb +5 -2
  23. data/lib/openc3/api/tlm_api.rb +70 -34
  24. data/lib/openc3/conversions/unix_time_conversion.rb +8 -6
  25. data/lib/openc3/interfaces/mqtt_interface.rb +11 -9
  26. data/lib/openc3/interfaces/mqtt_stream_interface.rb +78 -0
  27. data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -7
  28. data/lib/openc3/io/json_drb.rb +3 -2
  29. data/lib/openc3/io/json_rpc.rb +6 -6
  30. data/lib/openc3/logs/buffered_packet_log_writer.rb +4 -2
  31. data/lib/openc3/logs/packet_log_reader.rb +2 -2
  32. data/lib/openc3/logs/packet_log_writer.rb +22 -7
  33. data/lib/openc3/logs/text_log_writer.rb +3 -2
  34. data/lib/openc3/microservices/cleanup_microservice.rb +8 -1
  35. data/lib/openc3/microservices/decom_microservice.rb +1 -1
  36. data/lib/openc3/microservices/interface_microservice.rb +2 -2
  37. data/lib/openc3/microservices/microservice.rb +5 -2
  38. data/lib/openc3/microservices/reaction_microservice.rb +1 -0
  39. data/lib/openc3/microservices/timeline_microservice.rb +7 -5
  40. data/lib/openc3/microservices/trigger_group_microservice.rb +2 -1
  41. data/lib/openc3/migrations/20231022000000_tlm_viewer_config.rb +22 -0
  42. data/lib/openc3/models/activity_model.rb +21 -3
  43. data/lib/openc3/models/cvt_model.rb +2 -1
  44. data/lib/openc3/models/gem_model.rb +4 -1
  45. data/lib/openc3/models/interface_model.rb +11 -5
  46. data/lib/openc3/models/metadata_model.rb +11 -0
  47. data/lib/openc3/models/microservice_model.rb +16 -3
  48. data/lib/openc3/models/model.rb +18 -0
  49. data/lib/openc3/models/note_model.rb +11 -0
  50. data/lib/openc3/models/plugin_model.rb +56 -4
  51. data/lib/openc3/models/python_package_model.rb +104 -0
  52. data/lib/openc3/models/scope_model.rb +2 -0
  53. data/lib/openc3/models/sorted_model.rb +17 -8
  54. data/lib/openc3/models/target_model.rb +53 -18
  55. data/lib/openc3/models/tool_config_model.rb +9 -3
  56. data/lib/openc3/models/tool_model.rb +22 -7
  57. data/lib/openc3/models/widget_model.rb +19 -3
  58. data/lib/openc3/operators/microservice_operator.rb +2 -0
  59. data/lib/openc3/packets/json_packet.rb +46 -15
  60. data/lib/openc3/packets/limits.rb +6 -18
  61. data/lib/openc3/packets/packet.rb +1 -0
  62. data/lib/openc3/packets/packet_config.rb +2 -1
  63. data/lib/openc3/packets/parsers/format_string_parser.rb +4 -4
  64. data/lib/openc3/packets/parsers/limits_parser.rb +4 -4
  65. data/lib/openc3/packets/parsers/limits_response_parser.rb +5 -5
  66. data/lib/openc3/packets/parsers/processor_parser.rb +4 -4
  67. data/lib/openc3/packets/parsers/state_parser.rb +3 -3
  68. data/lib/openc3/packets/parsers/xtce_parser.rb +5 -1
  69. data/lib/openc3/script/api_shared.rb +81 -63
  70. data/lib/openc3/script/calendar.rb +109 -0
  71. data/lib/openc3/script/commands.rb +18 -19
  72. data/lib/openc3/script/limits.rb +1 -1
  73. data/lib/openc3/script/{gems.rb → packages.rb} +20 -16
  74. data/lib/openc3/script/script.rb +49 -38
  75. data/lib/openc3/script/storage.rb +4 -4
  76. data/lib/openc3/script/web_socket_api.rb +2 -2
  77. data/lib/openc3/streams/mqtt_stream.rb +109 -0
  78. data/lib/openc3/system/system.rb +2 -0
  79. data/lib/openc3/system/target.rb +10 -1
  80. data/lib/openc3/top_level.rb +2 -2
  81. data/lib/openc3/utilities/aws_bucket.rb +3 -2
  82. data/lib/openc3/utilities/bucket_file_cache.rb +1 -1
  83. data/lib/openc3/utilities/cli_generator.rb +33 -20
  84. data/lib/openc3/utilities/local_mode.rb +5 -3
  85. data/lib/openc3/utilities/logger.rb +18 -17
  86. data/lib/openc3/utilities/process_manager.rb +1 -1
  87. data/lib/openc3/utilities/ruby_lex_utils.rb +0 -8
  88. data/lib/openc3/version.rb +6 -6
  89. data/templates/conversion/conversion.py +28 -0
  90. data/templates/conversion/conversion.rb +1 -18
  91. data/templates/limits_response/response.py +37 -0
  92. data/templates/limits_response/response.rb +0 -17
  93. data/templates/microservice/microservices/TEMPLATE/microservice.py +54 -0
  94. data/templates/microservice/microservices/TEMPLATE/microservice.rb +0 -7
  95. data/templates/plugin/.gitignore +1 -0
  96. data/templates/target/targets/TARGET/lib/target.py +9 -0
  97. data/templates/target/targets/TARGET/procedures/procedure.py +3 -0
  98. data/templates/tool_angular/package.json +22 -21
  99. data/templates/tool_angular/yarn.lock +2319 -3156
  100. data/templates/tool_react/package.json +16 -16
  101. data/templates/tool_react/yarn.lock +763 -645
  102. data/templates/tool_svelte/package.json +15 -14
  103. data/templates/tool_svelte/src/services/openc3-api.js +33 -82
  104. data/templates/tool_svelte/yarn.lock +748 -538
  105. data/templates/tool_vue/package.json +15 -14
  106. data/templates/tool_vue/yarn.lock +150 -64
  107. data/templates/widget/package.json +14 -13
  108. data/templates/widget/yarn.lock +133 -58
  109. metadata +60 -7
@@ -22,10 +22,10 @@ module OpenC3
22
22
  module Script
23
23
  private
24
24
 
25
- def gem_list(scope: $openc3_scope)
25
+ def package_list(scope: $openc3_scope)
26
26
  response_body = nil
27
27
  begin
28
- endpoint = "/openc3-api/gems?scope=#{scope}"
28
+ endpoint = "/openc3-api/packages?scope=#{scope}"
29
29
  uri = URI.parse($api_server.generate_url + endpoint)
30
30
  auth = $api_server.generate_auth
31
31
 
@@ -41,20 +41,21 @@ module OpenC3
41
41
  end
42
42
  end
43
43
  rescue => error
44
- raise "gem_list failed due to #{error.formatted}\nResponse:\n#{response_body}"
44
+ raise "package_list failed due to #{error.formatted}\nResponse:\n#{response_body}"
45
45
  end
46
46
  end
47
+ alias gem_list package_list
47
48
 
48
- def gem_install(file_path, scope: $openc3_scope)
49
+ def package_install(file_path, scope: $openc3_scope)
49
50
  response_body = nil
50
51
  begin
51
- endpoint = "/openc3-api/gems?scope=#{scope}"
52
+ endpoint = "/openc3-api/packages?scope=#{scope}"
52
53
  uri = URI.parse($api_server.generate_url + endpoint)
53
54
  auth = $api_server.generate_auth
54
55
 
55
56
  File.open(file_path, 'rb') do |file|
56
57
  request = Net::HTTP::Post.new(uri)
57
- form_data = [["gem", file]]
58
+ form_data = [["package", file]]
58
59
  request.set_form(form_data, "multipart/form-data")
59
60
  request['User-Agent'] = JsonDRbObject::USER_AGENT
60
61
  request['Authorization'] = auth.token
@@ -67,14 +68,15 @@ module OpenC3
67
68
  end
68
69
  end
69
70
  rescue => error
70
- raise "gem_install failed due to #{error.formatted}\nResponse:\n#{response_body}"
71
+ raise "package_install failed due to #{error.formatted}\nResponse:\n#{response_body}"
71
72
  end
72
73
  end
74
+ alias gem_install package_install
73
75
 
74
- def gem_uninstall(gem_name, scope: $openc3_scope)
76
+ def package_uninstall(package_name, scope: $openc3_scope)
75
77
  response_body = nil
76
78
  begin
77
- endpoint = "/openc3-api/gems/#{gem_name}?scope=#{scope}"
79
+ endpoint = "/openc3-api/packages/#{package_name}?scope=#{scope}"
78
80
  uri = URI.parse($api_server.generate_url + endpoint)
79
81
  auth = $api_server.generate_auth
80
82
  request = Net::HTTP::Delete.new(uri)
@@ -84,22 +86,24 @@ module OpenC3
84
86
  http.request(request) do |response|
85
87
  response_body = response.body
86
88
  response.value() # Raises an HTTP error if the response is not 2xx (success)
87
- return true
89
+ return response_body.remove_quotes
88
90
  end
89
91
  end
90
92
  rescue => error
91
- raise "gem_uninstall failed due to #{error.formatted}\nResponse:\n#{response_body}"
93
+ raise "package_uninstall failed due to #{error.formatted}\nResponse:\n#{response_body}"
92
94
  end
93
95
  end
96
+ alias package_uninstall package_uninstall
94
97
 
95
- def gem_status(process_name, scope: $openc3_scope)
98
+ def package_status(process_name, scope: $openc3_scope)
96
99
  return plugin_status(process_name, scope: scope)
97
100
  end
101
+ alias gem_status package_status
98
102
 
99
- def gem_download(gem_name, local_file_path, scope: $openc3_scope)
103
+ def package_download(package_name, local_file_path, scope: $openc3_scope)
100
104
  response_body = nil
101
105
  begin
102
- endpoint = "/openc3-api/gems/#{gem_name}/download?scope=#{scope}"
106
+ endpoint = "/openc3-api/packages/#{package_name}/download?scope=#{scope}"
103
107
  uri = URI.parse($api_server.generate_url + endpoint)
104
108
  auth = $api_server.generate_auth
105
109
  request = Net::HTTP::Post.new(uri)
@@ -117,9 +121,9 @@ module OpenC3
117
121
  end
118
122
  end
119
123
  rescue => error
120
- raise "gem_uninstall failed due to #{error.formatted}\nResponse:\n#{response_body}"
124
+ raise "package_download failed due to #{error.formatted}\nResponse:\n#{response_body}"
121
125
  end
122
126
  end
123
-
127
+ alias gem_download package_download
124
128
  end
125
129
  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
@@ -24,6 +24,7 @@ require 'openc3'
24
24
  require 'openc3/api/api'
25
25
  require 'openc3/io/json_drb_object'
26
26
  require 'openc3/script/api_shared'
27
+ require 'openc3/script/calendar'
27
28
  require 'openc3/script/metadata'
28
29
  require 'openc3/script/commands'
29
30
  require 'openc3/script/telemetry'
@@ -33,7 +34,7 @@ require 'openc3/script/screen'
33
34
  require 'openc3/script/script_runner'
34
35
  require 'openc3/script/storage'
35
36
  require 'openc3/script/web_socket_api'
36
- require 'openc3/script/gems'
37
+ require 'openc3/script/packages'
37
38
  require 'openc3/script/plugins'
38
39
  require 'openc3/utilities/authentication'
39
40
 
@@ -92,27 +93,48 @@ module OpenC3
92
93
  $script_runner_api_server = nil
93
94
  end
94
95
 
96
+ # This isn't part of the public API because users should use wait()
97
+ def openc3_script_sleep(sleep_time = nil)
98
+ if sleep_time
99
+ sleep(sleep_time)
100
+ else
101
+ prompt("Press any key to continue...")
102
+ end
103
+ return false
104
+ end
105
+
106
+ # Internal method used in scripts when encountering a hazardous command
107
+ def prompt_for_hazardous(target_name, cmd_name, hazardous_description)
108
+ loop do
109
+ message = "Warning: Command #{target_name} #{cmd_name} is Hazardous. "
110
+ message << "\n#{hazardous_description}\n" if hazardous_description
111
+ message << "Send? (y): "
112
+ print message
113
+ answer = gets.chomp
114
+ if answer.downcase == 'y'
115
+ return true
116
+ end
117
+ end
118
+ end
119
+
120
+ ###########################################################################
121
+ # START PUBLIC API
122
+ ###########################################################################
123
+
95
124
  def disconnect_script
96
125
  $disconnect = true
97
126
  end
98
127
 
128
+ # DEPRECATED
99
129
  def play_wav_file(wav_filename)
100
130
  # NOOP
101
131
  end
102
132
 
133
+ # DEPRECATED
103
134
  def status_bar(message)
104
135
  # NOOP
105
136
  end
106
137
 
107
- def openc3_script_sleep(sleep_time = nil)
108
- if sleep_time
109
- sleep(sleep_time)
110
- else
111
- prompt("Press any key to continue...")
112
- end
113
- return false
114
- end
115
-
116
138
  def ask_string(question, blank_or_default = false, password = false)
117
139
  answer = ''
118
140
  default = ''
@@ -174,19 +196,6 @@ module OpenC3
174
196
  _file_dialog(title, message, filter)
175
197
  end
176
198
 
177
- def prompt_for_hazardous(target_name, cmd_name, hazardous_description)
178
- loop do
179
- message = "Warning: Command #{target_name} #{cmd_name} is Hazardous. "
180
- message << "\n#{hazardous_description}\n" if hazardous_description
181
- message << "Send? (y): "
182
- print message
183
- answer = gets.chomp
184
- if answer.downcase == 'y'
185
- return true
186
- end
187
- end
188
- end
189
-
190
199
  def prompt(string, text_color: nil, background_color: nil, font_size: nil, font_family: nil, details: nil)
191
200
  print "#{string}: "
192
201
  print "Details: #{details}\n" if details
@@ -200,6 +209,10 @@ module OpenC3
200
209
  def run_mode
201
210
  # NOOP
202
211
  end
212
+
213
+ ###########################################################################
214
+ # END PUBLIC API
215
+ ###########################################################################
203
216
  end
204
217
 
205
218
  # Provides a proxy to the JsonDRbObject which communicates with the API server
@@ -253,18 +266,18 @@ module OpenC3
253
266
  when :request
254
267
  @json_drb.request(*method_params, **kw_params)
255
268
  else
269
+ # If :disconnect is there delete it and return the value
270
+ # If it is not there, delete returns nil
271
+ disconnect = kw_params.delete(:disconnect)
256
272
  if $disconnect
257
- result = nil
258
- # If :disconnect is there delete it and return the value
259
- # If it is not there, delete returns nil
260
- disconnect = kw_params.delete(:disconnect)
273
+ return disconnect if disconnect
261
274
  # The only commands allowed through in disconnect mode are read-only
262
275
  # Thus we allow the get, list, tlm and limits_enabled and subscribe methods
263
276
  if method_name =~ /\w*_get$|^get_\w*|\w*_list$|^list_\w*|^tlm|^limits_enabled$|^subscribe$/
264
- result = @json_drb.method_missing(method_name, *method_params, **kw_params)
277
+ return @json_drb.method_missing(method_name, *method_params, **kw_params)
278
+ else
279
+ return nil
265
280
  end
266
- # If they overrode the return value using the disconnect keyword then return that
267
- return disconnect ? disconnect : result
268
281
  else
269
282
  @json_drb.method_missing(method_name, *method_params, **kw_params)
270
283
  end
@@ -317,14 +330,12 @@ module OpenC3
317
330
 
318
331
  def request(*method_params, **kw_params)
319
332
  kw_params[:scope] = $openc3_scope unless kw_params[:scope]
320
- if $disconnect
321
- result = nil
322
- # If :disconnect is there delete it and return the value
323
- # If it is not there, delete returns nil
324
- disconnect = kw_params.delete(:disconnect)
325
-
333
+ # If :disconnect is there delete it and return the value
334
+ # If it is not there, delete returns nil
335
+ disconnect = kw_params.delete(:disconnect)
336
+ if $disconnect and disconnect
326
337
  # If they overrode the return value using the disconnect keyword then return that
327
- return disconnect ? disconnect : result
338
+ return disconnect
328
339
  else
329
340
  @json_api.request(*method_params, **kw_params)
330
341
  end
@@ -37,7 +37,7 @@ module OpenC3
37
37
  # Only delete from the targets_modified
38
38
  delete_path = "#{scope}/targets_modified/#{path}"
39
39
  endpoint = "/openc3-api/storage/delete/#{delete_path}"
40
- OpenC3::Logger.info "Deleting #{delete_path}"
40
+ puts "Deleting #{delete_path}"
41
41
  # Pass the name of the ENV variable name where we pull the actual bucket name
42
42
  response = $api_server.request('delete', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
43
43
  if response.nil? || response.status != 200
@@ -65,7 +65,7 @@ module OpenC3
65
65
 
66
66
  endpoint = "/openc3-api/storage/upload/#{upload_path}"
67
67
  result = _get_presigned_request(endpoint, scope: scope)
68
- OpenC3::Logger.info "Writing #{upload_path}"
68
+ puts "Writing #{upload_path}"
69
69
 
70
70
  # Try to put the file
71
71
  begin
@@ -104,7 +104,7 @@ module OpenC3
104
104
  if part == "targets_modified" and ENV['OPENC3_LOCAL_MODE']
105
105
  local_file = OpenC3::LocalMode.open_local_file(path, scope: scope)
106
106
  if local_file
107
- OpenC3::Logger.info "Reading local #{scope}/#{part}/#{path}"
107
+ puts "Reading local #{scope}/#{part}/#{path}"
108
108
  file = Tempfile.new('target', binmode: true)
109
109
  file.filename = path
110
110
  file.write(local_file.read)
@@ -138,7 +138,7 @@ module OpenC3
138
138
 
139
139
  endpoint = "/openc3-api/storage/download/#{scope}/#{path}"
140
140
  result = _get_presigned_request(endpoint, scope: scope)
141
- OpenC3::Logger.info "Reading #{scope}/#{path}"
141
+ puts "Reading #{scope}/#{path}"
142
142
 
143
143
  # Try to get the file
144
144
  uri = _get_uri(result['url'])
@@ -217,14 +217,14 @@ module OpenC3
217
217
 
218
218
  # Log Messages WebSocket
219
219
  class MessagesWebSocketApi < CmdTlmWebSocketApi
220
- def initialize(history_count: 0, start_time: nil, end_time: nil, severity: nil, types: nil, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
220
+ def initialize(history_count: 0, start_time: nil, end_time: nil, level: nil, types: nil, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
221
221
  @identifier = {
222
222
  channel: "MessagesChannel",
223
223
  history_count: history_count
224
224
  }
225
225
  @identifier['start_time'] = start_time if start_time
226
226
  @identifier['end_time'] = end_time if end_time
227
- @identifier['severity'] = severity if severity
227
+ @identifier['level'] = level if level
228
228
  @identifier['types'] = types if types
229
229
  super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
230
230
  end
@@ -0,0 +1,109 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2023 OpenC3, Inc.
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
+ # This file may also be used under the terms of a commercial license
17
+ # if purchased from OpenC3, Inc.
18
+
19
+ require 'openc3/interfaces/mqtt_interface' # For MQTT patches
20
+ require 'openc3/streams/stream'
21
+ require 'openc3/config/config_parser'
22
+
23
+ module OpenC3
24
+ class MqttStream < Stream
25
+ attr_reader :hostname
26
+ attr_reader :port
27
+ attr_reader :ssl
28
+ attr_reader :write_topic
29
+ attr_reader :read_topic
30
+ attr_accessor :username
31
+ attr_accessor :password
32
+ attr_accessor :cert
33
+ attr_accessor :key
34
+ attr_accessor :ca_file
35
+
36
+ def initialize(hostname, port = 1883, ssl = false, write_topic = nil, read_topic = nil)
37
+ super()
38
+
39
+ @hostname = hostname
40
+ @port = Integer(port)
41
+ @ssl = ConfigParser.handle_true_false(ssl)
42
+ @write_topic = ConfigParser.handle_nil(write_topic)
43
+ @read_topic = ConfigParser.handle_nil(read_topic)
44
+ @connected = false
45
+
46
+ @username = nil
47
+ @password = nil
48
+ @cert = nil
49
+ @key = nil
50
+ @ca_file = nil
51
+
52
+ # Mutex on write is needed to protect from commands coming in from more
53
+ # than one tool
54
+ @write_mutex = Mutex.new
55
+ end
56
+
57
+ # @return [String] Returns a binary string of data from the read_topic
58
+ def read
59
+ raise "Attempt to read from write only stream" unless @read_topic
60
+
61
+ # No read mutex is needed because reads happen serially
62
+ _, data = @client.get
63
+ if data.nil? or data.length <= 0
64
+ Logger.info "MqttStream: read returned nil" if data.nil?
65
+ Logger.info "MqttStream: read returned 0 bytes" if not data.nil? and data.length <= 0
66
+ return nil
67
+ end
68
+
69
+ return data
70
+ end
71
+
72
+ # @param data [String] A binary string of data to write to the write_topic
73
+ def write(data)
74
+ raise "Attempt to write to read only stream" unless @write_topic
75
+
76
+ @write_mutex.synchronize do
77
+ @client.publish(@write_topic, data)
78
+ end
79
+ end
80
+
81
+ # Connect the stream
82
+ def connect
83
+ @client = MQTT::Client.new
84
+ @client.host = @hostname
85
+ @client.port = @port
86
+ @client.ssl = @ssl
87
+ @client.username = @username if @username
88
+ @client.password = @password if @password
89
+ @client.cert = @cert if @cert
90
+ @client.key = @key if @key
91
+ @client.ca_file = @ca_file.path if @ca_file
92
+ @client.connect
93
+ @client.subscribe(@read_topic) if @read_topic
94
+ @connected = true
95
+ end
96
+
97
+ def connected?
98
+ @connected
99
+ end
100
+
101
+ def disconnect
102
+ if @connected
103
+ @client.disconnect
104
+ @client = nil
105
+ @connected = false
106
+ end
107
+ end
108
+ end
109
+ end
@@ -73,6 +73,8 @@ module OpenC3
73
73
  end
74
74
 
75
75
  def self.setup_targets(target_names, base_dir, scope:)
76
+ # Nothing to do if there are no targets
77
+ return if target_names.nil? or target_names.length == 0
76
78
  if @@instance.nil?
77
79
  FileUtils.mkdir_p("#{base_dir}/targets")
78
80
  bucket = Bucket.getClient()
@@ -32,6 +32,9 @@ module OpenC3
32
32
  # the system processes the target.
33
33
  attr_reader :name
34
34
 
35
+ # @return [String] Programming language. Must be 'ruby' or 'python'.
36
+ attr_reader :language
37
+
35
38
  # @return [Array<String>] List of filenames that must be required by Ruby
36
39
  # before parsing the command and telemetry definitions for this target
37
40
  attr_reader :requires
@@ -83,6 +86,7 @@ module OpenC3
83
86
  # @param path [String] Path to the target directory
84
87
  # @param gem_path [String] Path to the gem file or nil if there is no gem
85
88
  def initialize(target_name, path, gem_path = nil)
89
+ @language = 'ruby'
86
90
  @requires = []
87
91
  @ignored_parameters = []
88
92
  @ignored_items = []
@@ -110,10 +114,15 @@ module OpenC3
110
114
  #
111
115
  # @param filename [String] The target configuration file to parse
112
116
  def process_file(filename)
113
- Logger.instance.info "Processing target definition in file '#{filename}'"
117
+ Logger.instance.info "Processing ruby target definition in file '#{filename}'"
114
118
  parser = ConfigParser.new("https://openc3.com/docs/v5/target")
115
119
  parser.parse_file(filename) do |keyword, parameters|
116
120
  case keyword
121
+ when 'LANGUAGE'
122
+ usage = "#{keyword} <ruby | python>"
123
+ parser.verify_num_parameters(1, 1, usage)
124
+ @language = parameters[0].downcase
125
+
117
126
  when 'REQUIRE'
118
127
  usage = "#{keyword} <FILENAME>"
119
128
  parser.verify_num_parameters(1, 1, usage)
@@ -232,8 +232,7 @@ module OpenC3
232
232
  def self.create_log_file(filename, log_dir = nil)
233
233
  log_file = nil
234
234
  begin
235
- # The following code goes inside a begin rescue because it reads the
236
- # system.txt configuration file. If this has an error we won't be able
235
+ # If this has an error we won't be able
237
236
  # to determine the log path but we still want to write the log.
238
237
  log_dir = System.instance.paths['LOGS'] unless log_dir
239
238
  # Make sure the log directory exists
@@ -310,6 +309,7 @@ module OpenC3
310
309
  file.puts "GEMRC: #{ENV['GEMRC']}"
311
310
  file.puts "RI_DEVKIT: #{ENV['RI_DEVKIT']}"
312
311
  file.puts "GEM_HOME: #{ENV['GEM_HOME']}"
312
+ file.puts "PYTHONUSERBASE: #{ENV['PYTHONUSERBASE']}"
313
313
  file.puts "PATH: #{ENV['PATH']}"
314
314
  file.puts ""
315
315
  file.puts "Ruby Path:\n #{$:.join("\n ")}\n\n"
@@ -81,7 +81,7 @@ module OpenC3
81
81
  ]
82
82
  }
83
83
  EOL
84
- @client.put_bucket_policy({ bucket: bucket, policy: policy })
84
+ @client.put_bucket_policy({ bucket: bucket, policy: policy, checksum_algorithm: "SHA256" })
85
85
  end
86
86
  end
87
87
 
@@ -193,7 +193,8 @@ module OpenC3
193
193
  # put_object fires off the request to store but does not confirm
194
194
  def put_object(bucket:, key:, body:, content_type: nil, cache_control: nil, metadata: nil)
195
195
  @client.put_object(bucket: bucket, key: key, body: body,
196
- content_type: content_type, cache_control: cache_control, metadata: metadata)
196
+ content_type: content_type, cache_control: cache_control, metadata: metadata,
197
+ checksum_algorithm: "SHA256")
197
198
  end
198
199
 
199
200
  # @returns [Boolean] Whether the file exists
@@ -87,7 +87,7 @@ class BucketFile
87
87
  # Try to retrieve the file three times
88
88
  retry_count += 1
89
89
  raise err if retry_count >= 3
90
- Logger.warn("Error retrieving log file from bucket - retry #{retry_count}: #{@bucket_path}\n#{err.formatted}")
90
+ OpenC3::Logger.warn("Error retrieving log file from bucket - retry #{retry_count}: #{@bucket_path}\n#{err.formatted}")
91
91
  sleep(1)
92
92
  retry
93
93
  end
@@ -40,20 +40,33 @@ module OpenC3
40
40
  if args[0] != 'plugin' and Dir.glob("*.gemspec").empty?
41
41
  abort("No gemspec file detected. #{args[0].to_s.downcase} generator should be run within an existing plugin.")
42
42
  end
43
+
44
+ if args[-1] == '--python'
45
+ @@language = 'py'
46
+ else
47
+ @@language = 'rb'
48
+ end
43
49
  end
44
50
 
45
51
  def self.process_template(template_dir, the_binding)
46
52
  Dir.glob("#{template_dir}/**/*", File::FNM_DOTMATCH).each do |file|
47
53
  next if File.basename(file) == '.'
54
+ if @@language == 'rb'
55
+ # Ignore python files if we're ruby
56
+ next if File.extname(file) == '.py'
57
+ elsif @@language == 'py'
58
+ # Ignore ruby files if we're python
59
+ next if File.extname(file) == '.rb'
60
+ end
48
61
  base_name = file.sub("#{template_dir}/", '')
49
62
  next if yield base_name
50
63
  if File.directory?(file)
51
- FileUtils.mkdir(base_name) unless File.exist?(base_name)
64
+ FileUtils.mkdir_p(base_name)
52
65
  next
53
66
  end
54
- output = ERB.new(File.read(file).comment_erb(), trim_mode: "-").result(the_binding)
55
- File.open(base_name, 'w') do |file|
56
- file.write output
67
+ output = ERB.new(File.read(file), trim_mode: "-").result(the_binding)
68
+ File.open(base_name, 'w') do |base_file|
69
+ base_file.write output
57
70
  end
58
71
  end
59
72
  end
@@ -82,8 +95,8 @@ module OpenC3
82
95
  end
83
96
 
84
97
  def self.generate_target(args)
85
- if args.length != 2
86
- abort("Usage: cli generate #{args[0]} <NAME>")
98
+ if args.length < 2 or args.length > 3
99
+ abort("Usage: cli generate #{args[0]} <NAME> (--ruby or --python)")
87
100
  end
88
101
 
89
102
  # Create the local variables
@@ -92,14 +105,14 @@ module OpenC3
92
105
  if File.exist?(target_path)
93
106
  abort("Target #{target_path} already exists!")
94
107
  end
95
- target_lib_filename = "#{target_name.downcase}.rb"
108
+ target_lib_filename = "#{target_name.downcase}.#{@@language}"
96
109
  target_class = target_lib_filename.filename_to_class_name
97
110
  target_object = target_name.downcase
98
111
 
99
112
  process_template("#{TEMPLATES_DIR}/target", binding) do |filename|
100
113
  # Rename the template TARGET to our actual target named after the plugin
101
114
  filename.sub!("targets/TARGET", "targets/#{target_name}")
102
- filename.sub!("target.rb", target_lib_filename)
115
+ filename.sub!("target.#{@@language}", target_lib_filename)
103
116
  false
104
117
  end
105
118
 
@@ -120,8 +133,8 @@ module OpenC3
120
133
  end
121
134
 
122
135
  def self.generate_microservice(args)
123
- if args.length != 2
124
- abort("Usage: cli generate #{args[0]} <NAME>")
136
+ if args.length < 2 or args.length > 3
137
+ abort("Usage: cli generate #{args[0]} <NAME> (--ruby or --python)")
125
138
  end
126
139
 
127
140
  # Create the local variables
@@ -130,13 +143,13 @@ module OpenC3
130
143
  if File.exist?(microservice_path)
131
144
  abort("Microservice #{microservice_path} already exists!")
132
145
  end
133
- microservice_filename = "#{microservice_name.downcase}.rb"
146
+ microservice_filename = "#{microservice_name.downcase}.#{@@language}"
134
147
  microservice_class = microservice_filename.filename_to_class_name
135
148
 
136
149
  process_template("#{TEMPLATES_DIR}/microservice", binding) do |filename|
137
150
  # Rename the template MICROSERVICE to our actual microservice name
138
151
  filename.sub!("microservices/TEMPLATE", "microservices/#{microservice_name}")
139
- filename.sub!("microservice.rb", microservice_filename)
152
+ filename.sub!("microservice.#{@@language}", microservice_filename)
140
153
  false
141
154
  end
142
155
 
@@ -252,8 +265,8 @@ module OpenC3
252
265
  self.singleton_class.send(:alias_method, :generate_tool_svelte, :generate_tool)
253
266
 
254
267
  def self.generate_conversion(args)
255
- if args.length != 3
256
- abort("Usage: cli generate conversion <TARGET> <NAME>")
268
+ if args.length < 3 or args.length > 4
269
+ abort("Usage: cli generate conversion <TARGET> <NAME> (--ruby or --python)")
257
270
  end
258
271
 
259
272
  # Create the local variables
@@ -263,7 +276,7 @@ module OpenC3
263
276
  end
264
277
  conversion_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_CONVERSION"
265
278
  conversion_path = "targets/#{target_name}/lib/"
266
- conversion_basename = "#{conversion_name.downcase}.rb"
279
+ conversion_basename = "#{conversion_name.downcase}.#{@@language}"
267
280
  conversion_class = conversion_basename.filename_to_class_name
268
281
  conversion_filename = "targets/#{target_name}/lib/#{conversion_basename}"
269
282
  if File.exist?(conversion_filename)
@@ -271,7 +284,7 @@ module OpenC3
271
284
  end
272
285
 
273
286
  process_template("#{TEMPLATES_DIR}/conversion", binding) do |filename|
274
- filename.sub!("conversion.rb", conversion_filename)
287
+ filename.sub!("conversion.#{@@language}", conversion_filename)
275
288
  false
276
289
  end
277
290
 
@@ -282,8 +295,8 @@ module OpenC3
282
295
  end
283
296
 
284
297
  def self.generate_limits_response(args)
285
- if args.length != 3
286
- abort("Usage: cli generate limits_response <TARGET> <NAME>")
298
+ if args.length < 3 or args.length > 4
299
+ abort("Usage: cli generate limits_response <TARGET> <NAME> (--ruby or --python)")
287
300
  end
288
301
 
289
302
  # Create the local variables
@@ -293,7 +306,7 @@ module OpenC3
293
306
  end
294
307
  response_name = "#{args[2].upcase.gsub(/_+|-+/, '_')}_LIMITS_RESPONSE"
295
308
  response_path = "targets/#{target_name}/lib/"
296
- response_basename = "#{response_name.downcase}.rb"
309
+ response_basename = "#{response_name.downcase}.#{@@language}"
297
310
  response_class = response_basename.filename_to_class_name
298
311
  response_filename = "targets/#{target_name}/lib/#{response_basename}"
299
312
  if File.exist?(response_filename)
@@ -301,7 +314,7 @@ module OpenC3
301
314
  end
302
315
 
303
316
  process_template("#{TEMPLATES_DIR}/limits_response", binding) do |filename|
304
- filename.sub!("response.rb", response_filename)
317
+ filename.sub!("response.#{@@language}", response_filename)
305
318
  false
306
319
  end
307
320