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.
- checksums.yaml +4 -4
- data/Gemfile +2 -2
- data/bin/openc3cli +29 -15
- data/data/config/_id_items.yaml +6 -4
- data/data/config/_id_params.yaml +9 -6
- data/data/config/_items.yaml +6 -4
- data/data/config/_params.yaml +3 -2
- data/data/config/graph_settings.yaml +1 -1
- data/data/config/interface_modifiers.yaml +1 -1
- data/data/config/item_modifiers.yaml +1 -2
- data/data/config/microservice.yaml +10 -1
- data/data/config/parameter_modifiers.yaml +13 -14
- data/data/config/plugins.yaml +13 -3
- data/data/config/screen.yaml +1 -2
- data/data/config/target.yaml +9 -0
- data/data/config/target_config.yaml +14 -6
- data/data/config/tool.yaml +12 -3
- data/lib/openc3/api/api.rb +1 -1
- data/lib/openc3/api/cmd_api.rb +123 -59
- data/lib/openc3/api/config_api.rb +12 -12
- data/lib/openc3/api/limits_api.rb +4 -3
- data/lib/openc3/api/settings_api.rb +5 -2
- data/lib/openc3/api/tlm_api.rb +70 -34
- data/lib/openc3/conversions/unix_time_conversion.rb +8 -6
- data/lib/openc3/interfaces/mqtt_interface.rb +11 -9
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +78 -0
- data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -7
- data/lib/openc3/io/json_drb.rb +3 -2
- data/lib/openc3/io/json_rpc.rb +6 -6
- data/lib/openc3/logs/buffered_packet_log_writer.rb +4 -2
- data/lib/openc3/logs/packet_log_reader.rb +2 -2
- data/lib/openc3/logs/packet_log_writer.rb +22 -7
- data/lib/openc3/logs/text_log_writer.rb +3 -2
- data/lib/openc3/microservices/cleanup_microservice.rb +8 -1
- data/lib/openc3/microservices/decom_microservice.rb +1 -1
- data/lib/openc3/microservices/interface_microservice.rb +2 -2
- data/lib/openc3/microservices/microservice.rb +5 -2
- data/lib/openc3/microservices/reaction_microservice.rb +1 -0
- data/lib/openc3/microservices/timeline_microservice.rb +7 -5
- data/lib/openc3/microservices/trigger_group_microservice.rb +2 -1
- data/lib/openc3/migrations/20231022000000_tlm_viewer_config.rb +22 -0
- data/lib/openc3/models/activity_model.rb +21 -3
- data/lib/openc3/models/cvt_model.rb +2 -1
- data/lib/openc3/models/gem_model.rb +4 -1
- data/lib/openc3/models/interface_model.rb +11 -5
- data/lib/openc3/models/metadata_model.rb +11 -0
- data/lib/openc3/models/microservice_model.rb +16 -3
- data/lib/openc3/models/model.rb +18 -0
- data/lib/openc3/models/note_model.rb +11 -0
- data/lib/openc3/models/plugin_model.rb +56 -4
- data/lib/openc3/models/python_package_model.rb +104 -0
- data/lib/openc3/models/scope_model.rb +2 -0
- data/lib/openc3/models/sorted_model.rb +17 -8
- data/lib/openc3/models/target_model.rb +53 -18
- data/lib/openc3/models/tool_config_model.rb +9 -3
- data/lib/openc3/models/tool_model.rb +22 -7
- data/lib/openc3/models/widget_model.rb +19 -3
- data/lib/openc3/operators/microservice_operator.rb +2 -0
- data/lib/openc3/packets/json_packet.rb +46 -15
- data/lib/openc3/packets/limits.rb +6 -18
- data/lib/openc3/packets/packet.rb +1 -0
- data/lib/openc3/packets/packet_config.rb +2 -1
- data/lib/openc3/packets/parsers/format_string_parser.rb +4 -4
- data/lib/openc3/packets/parsers/limits_parser.rb +4 -4
- data/lib/openc3/packets/parsers/limits_response_parser.rb +5 -5
- data/lib/openc3/packets/parsers/processor_parser.rb +4 -4
- data/lib/openc3/packets/parsers/state_parser.rb +3 -3
- data/lib/openc3/packets/parsers/xtce_parser.rb +5 -1
- data/lib/openc3/script/api_shared.rb +81 -63
- data/lib/openc3/script/calendar.rb +109 -0
- data/lib/openc3/script/commands.rb +18 -19
- data/lib/openc3/script/limits.rb +1 -1
- data/lib/openc3/script/{gems.rb → packages.rb} +20 -16
- data/lib/openc3/script/script.rb +49 -38
- data/lib/openc3/script/storage.rb +4 -4
- data/lib/openc3/script/web_socket_api.rb +2 -2
- data/lib/openc3/streams/mqtt_stream.rb +109 -0
- data/lib/openc3/system/system.rb +2 -0
- data/lib/openc3/system/target.rb +10 -1
- data/lib/openc3/top_level.rb +2 -2
- data/lib/openc3/utilities/aws_bucket.rb +3 -2
- data/lib/openc3/utilities/bucket_file_cache.rb +1 -1
- data/lib/openc3/utilities/cli_generator.rb +33 -20
- data/lib/openc3/utilities/local_mode.rb +5 -3
- data/lib/openc3/utilities/logger.rb +18 -17
- data/lib/openc3/utilities/process_manager.rb +1 -1
- data/lib/openc3/utilities/ruby_lex_utils.rb +0 -8
- data/lib/openc3/version.rb +6 -6
- data/templates/conversion/conversion.py +28 -0
- data/templates/conversion/conversion.rb +1 -18
- data/templates/limits_response/response.py +37 -0
- data/templates/limits_response/response.rb +0 -17
- data/templates/microservice/microservices/TEMPLATE/microservice.py +54 -0
- data/templates/microservice/microservices/TEMPLATE/microservice.rb +0 -7
- data/templates/plugin/.gitignore +1 -0
- data/templates/target/targets/TARGET/lib/target.py +9 -0
- data/templates/target/targets/TARGET/procedures/procedure.py +3 -0
- data/templates/tool_angular/package.json +22 -21
- data/templates/tool_angular/yarn.lock +2319 -3156
- data/templates/tool_react/package.json +16 -16
- data/templates/tool_react/yarn.lock +763 -645
- data/templates/tool_svelte/package.json +15 -14
- data/templates/tool_svelte/src/services/openc3-api.js +33 -82
- data/templates/tool_svelte/yarn.lock +748 -538
- data/templates/tool_vue/package.json +15 -14
- data/templates/tool_vue/yarn.lock +150 -64
- data/templates/widget/package.json +14 -13
- data/templates/widget/yarn.lock +133 -58
- metadata +60 -7
@@ -22,10 +22,10 @@ module OpenC3
|
|
22
22
|
module Script
|
23
23
|
private
|
24
24
|
|
25
|
-
def
|
25
|
+
def package_list(scope: $openc3_scope)
|
26
26
|
response_body = nil
|
27
27
|
begin
|
28
|
-
endpoint = "/openc3-api/
|
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 "
|
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
|
49
|
+
def package_install(file_path, scope: $openc3_scope)
|
49
50
|
response_body = nil
|
50
51
|
begin
|
51
|
-
endpoint = "/openc3-api/
|
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 = [["
|
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 "
|
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
|
76
|
+
def package_uninstall(package_name, scope: $openc3_scope)
|
75
77
|
response_body = nil
|
76
78
|
begin
|
77
|
-
endpoint = "/openc3-api/
|
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
|
89
|
+
return response_body.remove_quotes
|
88
90
|
end
|
89
91
|
end
|
90
92
|
rescue => error
|
91
|
-
raise "
|
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
|
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
|
103
|
+
def package_download(package_name, local_file_path, scope: $openc3_scope)
|
100
104
|
response_body = nil
|
101
105
|
begin
|
102
|
-
endpoint = "/openc3-api/
|
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 "
|
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
|
data/lib/openc3/script/script.rb
CHANGED
@@ -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
|
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/
|
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
|
-
|
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
|
-
|
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
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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['
|
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
|
data/lib/openc3/system/system.rb
CHANGED
@@ -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()
|
data/lib/openc3/system/target.rb
CHANGED
@@ -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)
|
data/lib/openc3/top_level.rb
CHANGED
@@ -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
|
-
#
|
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.
|
64
|
+
FileUtils.mkdir_p(base_name)
|
52
65
|
next
|
53
66
|
end
|
54
|
-
output = ERB.new(File.read(file)
|
55
|
-
File.open(base_name, 'w') do |
|
56
|
-
|
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
|
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}
|
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
|
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
|
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}
|
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
|
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
|
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}
|
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
|
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
|
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}
|
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
|
317
|
+
filename.sub!("response.#{@@language}", response_filename)
|
305
318
|
false
|
306
319
|
end
|
307
320
|
|