openc3 5.5.2 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openc3cli +167 -69
  3. data/data/config/_interfaces.yaml +1 -6
  4. data/data/config/interface_modifiers.yaml +55 -4
  5. data/data/config/microservice.yaml +30 -3
  6. data/ext/openc3/ext/crc/crc.c +82 -1
  7. data/lib/openc3/api/cmd_api.rb +19 -7
  8. data/lib/openc3/api/tlm_api.rb +13 -12
  9. data/lib/openc3/bridge/bridge_config.rb +4 -4
  10. data/lib/openc3/config/config_parser.rb +1 -0
  11. data/lib/openc3/conversions/unix_time_conversion.rb +3 -1
  12. data/lib/openc3/ext/.keep +0 -0
  13. data/lib/openc3/interfaces/interface.rb +54 -26
  14. data/lib/openc3/interfaces/serial_interface.rb +4 -5
  15. data/lib/openc3/interfaces/simulated_target_interface.rb +4 -4
  16. data/lib/openc3/interfaces/stream_interface.rb +2 -2
  17. data/lib/openc3/interfaces/tcpip_client_interface.rb +4 -3
  18. data/lib/openc3/interfaces/tcpip_server_interface.rb +18 -19
  19. data/lib/openc3/interfaces/udp_interface.rb +10 -4
  20. data/lib/openc3/io/json_api.rb +72 -0
  21. data/lib/openc3/io/serial_driver.rb +4 -5
  22. data/lib/openc3/logs/buffered_packet_log_writer.rb +2 -4
  23. data/lib/openc3/logs/log_writer.rb +9 -8
  24. data/lib/openc3/logs/packet_log_reader.rb +8 -1
  25. data/lib/openc3/logs/packet_log_writer.rb +3 -4
  26. data/lib/openc3/logs/stream_log.rb +116 -0
  27. data/lib/openc3/logs/stream_log_pair.rb +70 -0
  28. data/lib/openc3/microservices/cleanup_microservice.rb +1 -1
  29. data/lib/openc3/microservices/decom_microservice.rb +17 -2
  30. data/lib/openc3/microservices/interface_decom_common.rb +42 -0
  31. data/lib/openc3/microservices/interface_microservice.rb +24 -17
  32. data/lib/openc3/microservices/router_microservice.rb +46 -4
  33. data/lib/openc3/migrations/20221202214600_add_target_names.rb +1 -1
  34. data/lib/openc3/migrations/20230319154100_log_stream.rb +40 -0
  35. data/lib/openc3/migrations/20230413101100_remove_log.rb +30 -0
  36. data/lib/openc3/models/gem_model.rb +2 -2
  37. data/lib/openc3/models/interface_model.rb +13 -14
  38. data/lib/openc3/models/metadata_model.rb +1 -1
  39. data/lib/openc3/models/note_model.rb +1 -1
  40. data/lib/openc3/models/plugin_model.rb +3 -2
  41. data/lib/openc3/operators/operator.rb +2 -0
  42. data/lib/openc3/packets/commands.rb +2 -0
  43. data/lib/openc3/packets/packet_config.rb +3 -2
  44. data/lib/openc3/packets/parsers/xtce_converter.rb +2 -1
  45. data/lib/openc3/script/gems.rb +125 -0
  46. data/lib/openc3/script/plugins.rb +186 -0
  47. data/lib/openc3/script/screen.rb +119 -0
  48. data/lib/openc3/script/script.rb +3 -0
  49. data/lib/openc3/script/script_runner.rb +19 -8
  50. data/lib/openc3/script/suite_results.rb +2 -2
  51. data/lib/openc3/script/web_socket_api.rb +5 -1
  52. data/lib/openc3/streams/serial_stream.rb +14 -11
  53. data/lib/openc3/streams/tcpip_client_stream.rb +5 -2
  54. data/lib/openc3/streams/tcpip_socket_stream.rb +37 -71
  55. data/lib/openc3/streams/web_socket_client_stream.rb +5 -3
  56. data/lib/openc3/system/system.rb +2 -0
  57. data/lib/openc3/topics/interface_topic.rb +13 -4
  58. data/lib/openc3/topics/router_topic.rb +6 -6
  59. data/lib/openc3/topics/telemetry_decom_topic.rb +10 -1
  60. data/lib/openc3/utilities/bucket_utilities.rb +12 -5
  61. data/lib/openc3/utilities/cli_generator.rb +56 -4
  62. data/lib/openc3/utilities/crc.rb +42 -7
  63. data/lib/openc3/utilities/process_manager.rb +3 -1
  64. data/lib/openc3/utilities/ruby_lex_utils.rb +265 -504
  65. data/lib/openc3/version.rb +6 -6
  66. data/templates/conversion/conversion.rb +10 -2
  67. data/templates/microservice/microservices/TEMPLATE/microservice.rb +1 -1
  68. data/templates/plugin/Rakefile +8 -1
  69. data/templates/widget/.browserslistrc +16 -0
  70. data/templates/widget/.eslintrc.js +43 -0
  71. data/templates/widget/.nycrc +3 -0
  72. data/templates/widget/.prettierrc.js +5 -0
  73. data/templates/widget/LICENSE.txt +20 -0
  74. data/templates/widget/Rakefile +24 -0
  75. data/templates/widget/babel.config.json +11 -0
  76. data/templates/widget/package.json +35 -0
  77. data/templates/widget/src/Widget.vue +46 -0
  78. data/templates/widget/vue.config.js +25 -0
  79. data/templates/widget/yarn.lock +8938 -0
  80. metadata +23 -4
  81. data/lib/openc3/io/raw_logger.rb +0 -170
  82. data/lib/openc3/io/raw_logger_pair.rb +0 -80
@@ -28,7 +28,7 @@ require 'rubygems'
28
28
  require 'rubygems/uninstaller'
29
29
  require 'tempfile'
30
30
  require 'openc3/utilities/process_manager'
31
- require "pathname"
31
+ require 'pathname'
32
32
 
33
33
  module OpenC3
34
34
  # This class acts like a Model but doesn't inherit from Model because it doesn't
@@ -55,7 +55,7 @@ module OpenC3
55
55
  if gem_install
56
56
  Logger.info "Installing gem: #{gem_filename}"
57
57
  result = OpenC3::ProcessManager.instance.spawn(["ruby", "/openc3/bin/openc3cli", "geminstall", gem_filename, scope], "gem_install", gem_filename, Time.now + 3600.0, scope: scope)
58
- return result
58
+ return result.name
59
59
  end
60
60
  else
61
61
  message = "Gem file #{gem_file_path} does not exist!"
@@ -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
@@ -41,8 +41,7 @@ module OpenC3
41
41
  attr_accessor :secret_options
42
42
  attr_accessor :protocols
43
43
  attr_accessor :interfaces
44
- attr_accessor :log
45
- attr_accessor :log_raw
44
+ attr_accessor :log_stream
46
45
  attr_accessor :needs_dependencies
47
46
  attr_accessor :secrets
48
47
 
@@ -105,8 +104,7 @@ module OpenC3
105
104
  options: [],
106
105
  secret_options: [],
107
106
  protocols: [],
108
- log: true,
109
- log_raw: false,
107
+ log_stream: nil,
110
108
  updated_at: nil,
111
109
  plugin: nil,
112
110
  needs_dependencies: false,
@@ -129,8 +127,7 @@ module OpenC3
129
127
  @options = options
130
128
  @secret_options = secret_options
131
129
  @protocols = protocols
132
- @log = log
133
- @log_raw = log_raw
130
+ @log_stream = log_stream
134
131
  @needs_dependencies = needs_dependencies
135
132
  @secrets = secrets
136
133
  end
@@ -165,6 +162,10 @@ module OpenC3
165
162
  klass = OpenC3.require_class(protocol[1])
166
163
  interface_or_router.add_protocol(klass, protocol[2..-1], protocol[0].upcase.intern)
167
164
  end
165
+ if @log_stream
166
+ interface_or_router.stream_log_pair = StreamLogPair.new(interface_or_router.name, @log_stream)
167
+ interface_or_router.start_raw_logging
168
+ end
168
169
  interface_or_router
169
170
  end
170
171
 
@@ -182,8 +183,7 @@ module OpenC3
182
183
  'options' => @options,
183
184
  'secret_options' => @secret_options,
184
185
  'protocols' => @protocols,
185
- 'log' => @log,
186
- 'log_raw' => @log_raw,
186
+ 'log_stream' => @log_stream,
187
187
  'plugin' => @plugin,
188
188
  'needs_dependencies' => @needs_dependencies,
189
189
  'secrets' => @secrets.as_json(*a),
@@ -249,12 +249,11 @@ module OpenC3
249
249
  @protocols << parameters.dup
250
250
 
251
251
  when 'DONT_LOG'
252
- parser.verify_num_parameters(0, 0, "#{keyword}")
253
- @log = false
252
+ Logger.warn "DONT_LOG is deprecated and does nothing."
254
253
 
255
- when 'LOG_RAW'
256
- parser.verify_num_parameters(0, 0, "#{keyword}")
257
- @log_raw = true
254
+ when 'LOG_STREAM', 'LOG_RAW'
255
+ parser.verify_num_parameters(0, nil, "#{keyword} <Log Stream Class File (optional)> <Log Stream Parameters (optional)>")
256
+ @log_stream = parameters.dup # Even if it is empty we copy it to set it as not nil
258
257
 
259
258
  when 'SECRET'
260
259
  parser.verify_num_parameters(3, 5, "#{keyword} <Secret Type: ENV or FILE> <Secret Name> <Environment Variable Name or File Path> <Option Name (Optional)> <Secret Store Name (Optional)>")
@@ -69,7 +69,7 @@ module OpenC3
69
69
  if @color.nil?
70
70
  @color = '#%06x' % (rand * 0xffffff)
71
71
  end
72
- unless @color =~ /(#*)([0-9a-fA-F]{6})/
72
+ unless @color =~ /#?([0-9a-fA-F]{6})/
73
73
  raise SortedInputError.new "invalid color, must be in hex format, e.g. #FF0000"
74
74
  end
75
75
  @color = "##{@color}" unless @color.start_with?('#')
@@ -78,7 +78,7 @@ module OpenC3
78
78
  if @color.nil?
79
79
  @color = '#%06x' % (rand * 0xffffff)
80
80
  end
81
- unless @color =~ /(#*)([0-9a-fA-F]{6})/
81
+ unless @color =~ /#?([0-9a-fA-F]{6})/
82
82
  raise SortedInputError.new "invalid color, must be in hex format, e.g. #FF0000"
83
83
  end
84
84
  @color = "##{@color}" unless @color.start_with?('#')
@@ -36,6 +36,7 @@ require 'openc3/models/widget_model'
36
36
  require 'openc3/models/microservice_model'
37
37
  require 'tmpdir'
38
38
  require 'tempfile'
39
+ require 'fileutils'
39
40
 
40
41
  module OpenC3
41
42
  # Represents a OpenC3 plugin that can consist of targets, interfaces, routers
@@ -155,7 +156,7 @@ module OpenC3
155
156
  end
156
157
 
157
158
  # Actually install the gem now (slow)
158
- OpenC3::GemModel.install(gem_file_path, scope: scope)
159
+ OpenC3::GemModel.install(gem_file_path, scope: scope) unless validate_only
159
160
 
160
161
  # Extract gem contents
161
162
  gem_path = File.join(temp_dir, "gem")
@@ -284,7 +285,7 @@ module OpenC3
284
285
  microservice_count += 1
285
286
  end
286
287
  # Wait for the operator to wake up and remove the microservice processes
287
- sleep 12 if microservice_count > 0 # Cycle time 5s times 2 plus 2s wait for soft stop and then hard stop
288
+ sleep 15 if microservice_count > 0 # Cycle time 5s times 2 plus 5s wait for soft stop and then hard stop
288
289
  # Remove all the other models now that the processes have stopped
289
290
  # Save TargetModel for last as it has the most to cleanup
290
291
  [InterfaceModel, RouterModel, ToolModel, WidgetModel, TargetModel].each do |model|
@@ -83,6 +83,7 @@ module OpenC3
83
83
  attr_accessor :new_temp_dir
84
84
  attr_reader :temp_dir
85
85
  attr_reader :scope
86
+ attr_reader :name
86
87
 
87
88
  def self.setup
88
89
  # Perform any setup steps necessary
@@ -139,6 +140,7 @@ module OpenC3
139
140
  @process.io.stdout = OperatorProcessIO.new('microservice-stdout')
140
141
  @process.io.stderr = OperatorProcessIO.new('microservice-stderr')
141
142
  @process.start
143
+ @name = "#{Socket.gethostname}__#{@process.pid}"
142
144
  end
143
145
 
144
146
  def alive?
@@ -205,6 +205,8 @@ module OpenC3
205
205
  else
206
206
  output_string = 'cmd("'
207
207
  end
208
+ target_name = 'UNKNOWN' unless target_name
209
+ cmd_name = 'UNKNOWN' unless cmd_name
208
210
  output_string << target_name + ' ' + cmd_name
209
211
  if cmd_params.nil? or cmd_params.empty?
210
212
  output_string << '")'
@@ -17,7 +17,7 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/config/config_parser'
@@ -35,6 +35,7 @@ require 'openc3/conversions'
35
35
  require 'openc3/processors'
36
36
  require 'nokogiri'
37
37
  require 'ostruct'
38
+ require 'fileutils'
38
39
 
39
40
  module OpenC3
40
41
  # Reads a command or telemetry configuration file and builds a hash of packets.
@@ -523,7 +524,7 @@ module OpenC3
523
524
  @converted_bit_size = nil
524
525
  if params[0]
525
526
  @converted_type = params[0].upcase.intern
526
- raise parser.error("Invalid converted_type: #{@converted_type}.") unless [:INT, :UINT, :FLOAT, :STRING, :BLOCK].include? @converted_type
527
+ raise parser.error("Invalid converted_type: #{@converted_type}.") unless [:INT, :UINT, :FLOAT, :STRING, :BLOCK, :RUBY_TIME].include? @converted_type
527
528
  end
528
529
  @converted_bit_size = Integer(params[1]) if params[1]
529
530
  if @converted_type.nil? or @converted_bit_size.nil?
@@ -17,11 +17,12 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'nokogiri'
24
24
  require 'openc3/packets/parsers/xtce_parser'
25
+ require 'fileutils'
25
26
 
26
27
  module OpenC3
27
28
  class XtceConverter
@@ -0,0 +1,125 @@
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/script/plugins'
20
+
21
+ module OpenC3
22
+ module Script
23
+ private
24
+
25
+ def gem_list(scope: $openc3_scope)
26
+ response_body = nil
27
+ begin
28
+ endpoint = "/openc3-api/gems?scope=#{scope}"
29
+ uri = URI.parse($api_server.generate_url + endpoint)
30
+ auth = $api_server.generate_auth
31
+
32
+ request = Net::HTTP::Get.new(uri)
33
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
34
+ request['Content-Type'] = 'application/json'
35
+ request['Authorization'] = auth.token
36
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
37
+ http.request(request) do |response|
38
+ response_body = response.body
39
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
40
+ return JSON.parse(response.body, allow_nan: true, create_additions: true)
41
+ end
42
+ end
43
+ rescue => error
44
+ raise "gem_list failed due to #{error.formatted}\nResponse:\n#{response_body}"
45
+ end
46
+ end
47
+
48
+ def gem_install(file_path, scope: $openc3_scope)
49
+ response_body = nil
50
+ begin
51
+ endpoint = "/openc3-api/gems?scope=#{scope}"
52
+ uri = URI.parse($api_server.generate_url + endpoint)
53
+ auth = $api_server.generate_auth
54
+
55
+ File.open(file_path, 'rb') do |file|
56
+ request = Net::HTTP::Post.new(uri)
57
+ form_data = [["gem", file]]
58
+ request.set_form(form_data, "multipart/form-data")
59
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
60
+ request['Authorization'] = auth.token
61
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
62
+ http.request(request) do |response|
63
+ response_body = response.body
64
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
65
+ return response_body.remove_quotes
66
+ end
67
+ end
68
+ end
69
+ rescue => error
70
+ raise "gem_install failed due to #{error.formatted}\nResponse:\n#{response_body}"
71
+ end
72
+ end
73
+
74
+ def gem_uninstall(gem_name, scope: $openc3_scope)
75
+ response_body = nil
76
+ begin
77
+ endpoint = "/openc3-api/gems/#{gem_name}?scope=#{scope}"
78
+ uri = URI.parse($api_server.generate_url + endpoint)
79
+ auth = $api_server.generate_auth
80
+ request = Net::HTTP::Delete.new(uri)
81
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
82
+ request['Authorization'] = auth.token
83
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
84
+ http.request(request) do |response|
85
+ response_body = response.body
86
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
87
+ return true
88
+ end
89
+ end
90
+ rescue => error
91
+ raise "gem_uninstall failed due to #{error.formatted}\nResponse:\n#{response_body}"
92
+ end
93
+ end
94
+
95
+ def gem_status(process_name, scope: $openc3_scope)
96
+ return plugin_status(process_name, scope: scope)
97
+ end
98
+
99
+ def gem_download(gem_name, local_file_path, scope: $openc3_scope)
100
+ response_body = nil
101
+ begin
102
+ endpoint = "/openc3-api/gems/#{gem_name}/download?scope=#{scope}"
103
+ uri = URI.parse($api_server.generate_url + endpoint)
104
+ auth = $api_server.generate_auth
105
+ request = Net::HTTP::Post.new(uri)
106
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
107
+ request['Authorization'] = auth.token
108
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
109
+ http.request(request) do |response|
110
+ response_body = response.body
111
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
112
+ parsed = JSON.parse(response.body, allow_nan: true, create_additions: true)
113
+ File.open(local_file_path, 'wb') do |file|
114
+ file.write(Base64.decode64(parsed['contents']))
115
+ end
116
+ return local_file_path
117
+ end
118
+ end
119
+ rescue => error
120
+ raise "gem_uninstall failed due to #{error.formatted}\nResponse:\n#{response_body}"
121
+ end
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,186 @@
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
+ module OpenC3
20
+ module Script
21
+ private
22
+
23
+ def plugin_list(scope: $openc3_scope)
24
+ response_body = nil
25
+ begin
26
+ endpoint = "/openc3-api/plugins?scope=#{scope}"
27
+ uri = URI.parse($api_server.generate_url + endpoint)
28
+ auth = $api_server.generate_auth
29
+
30
+ request = Net::HTTP::Get.new(uri)
31
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
32
+ request['Content-Type'] = 'application/json'
33
+ request['Authorization'] = auth.token
34
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
35
+ http.request(request) do |response|
36
+ response_body = response.body
37
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
38
+ return JSON.parse(response.body, allow_nan: true, create_additions: true)
39
+ end
40
+ end
41
+ rescue => error
42
+ raise "get_plugin_list failed due to #{error.formatted}\nResponse:\n#{response_body}"
43
+ end
44
+ end
45
+
46
+ def plugin_get(plugin_name, scope: $openc3_scope)
47
+ response_body = nil
48
+ begin
49
+ endpoint = "/openc3-api/plugins/#{plugin_name}?scope=#{scope}"
50
+ uri = URI.parse($api_server.generate_url + endpoint)
51
+ auth = $api_server.generate_auth
52
+
53
+ request = Net::HTTP::Get.new(uri)
54
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
55
+ request['Content-Type'] = 'application/json'
56
+ request['Authorization'] = auth.token
57
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
58
+ http.request(request) do |response|
59
+ response_body = response.body
60
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
61
+ return JSON.parse(response.body, allow_nan: true, create_additions: true)
62
+ end
63
+ end
64
+ rescue => error
65
+ raise "get_plugin failed due to #{error.formatted}\nResponse:\n#{response_body}"
66
+ end
67
+ end
68
+
69
+ def plugin_install_phase1(file_path, update: false, existing_plugin_name: nil, scope: $openc3_scope)
70
+ response_body = nil
71
+ begin
72
+ if update
73
+ endpoint = "/openc3-api/plugins/#{existing_plugin_name}?scope=#{scope}"
74
+ else
75
+ endpoint = "/openc3-api/plugins?scope=#{scope}"
76
+ end
77
+ uri = URI.parse($api_server.generate_url + endpoint)
78
+ auth = $api_server.generate_auth
79
+
80
+ File.open(file_path, 'rb') do |file|
81
+ if update
82
+ request = Net::HTTP::Put.new(uri)
83
+ else
84
+ request = Net::HTTP::Post.new(uri)
85
+ end
86
+ form_data = [["plugin", file]]
87
+ request.set_form(form_data, "multipart/form-data")
88
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
89
+ request['Authorization'] = auth.token
90
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
91
+ http.request(request) do |response|
92
+ response_body = response.body
93
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
94
+ return JSON.parse(response.body, allow_nan: true, create_additions: true)
95
+ end
96
+ end
97
+ end
98
+ rescue => error
99
+ raise "plugin_install_phase1 failed due to #{error.formatted}\nResponse:\n#{response_body}"
100
+ end
101
+ end
102
+
103
+ def plugin_install_phase2(plugin_hash, update: false, scope: $openc3_scope)
104
+ response_body = nil
105
+ begin
106
+ plugin_name = plugin_hash['name']
107
+ if update
108
+ endpoint = "/openc3-api/plugins/#{plugin_name}?scope=#{scope}"
109
+ else
110
+ endpoint = "/openc3-api/plugins/install/#{plugin_name}?scope=#{scope}"
111
+ end
112
+ uri = URI.parse($api_server.generate_url + endpoint)
113
+ auth = $api_server.generate_auth
114
+
115
+ if update
116
+ request = Net::HTTP::Put.new(uri)
117
+ else
118
+ request = Net::HTTP::Post.new(uri)
119
+ end
120
+ form_data = [["plugin_hash", JSON.generate(plugin_hash, allow_nan: true)]]
121
+ request.set_form(form_data)
122
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
123
+ request['Content-Type'] = 'application/json'
124
+ request['Authorization'] = auth.token
125
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
126
+ http.request(request) do |response|
127
+ response_body = response.body
128
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
129
+ return response_body.remove_quotes
130
+ end
131
+ end
132
+ rescue => error
133
+ raise "plugin_install_phase2 failed due to #{error.formatted}\nResponse:\n#{response_body}"
134
+ end
135
+ end
136
+
137
+ def plugin_update_phase1(file_path, existing_plugin_name, scope: $openc3_scope)
138
+ return plugin_install_phase1(file_path, existing_plugin_name: existing_plugin_name, update: true, scope: scope)
139
+ end
140
+
141
+ def plugin_uninstall(plugin_name, scope: $openc3_scope)
142
+ response_body = nil
143
+ begin
144
+ endpoint = "/openc3-api/plugins/#{plugin_name}?scope=#{scope}"
145
+ uri = URI.parse($api_server.generate_url + endpoint)
146
+ auth = $api_server.generate_auth
147
+ request = Net::HTTP::Delete.new(uri)
148
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
149
+ request['Authorization'] = auth.token
150
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
151
+ http.request(request) do |response|
152
+ response_body = response.body
153
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
154
+ return response_body.remove_quotes
155
+ end
156
+ end
157
+ rescue => error
158
+ raise "plugin_uninstall failed due to #{error.formatted}\nResponse:\n#{response_body}"
159
+ end
160
+ end
161
+
162
+ def plugin_status(process_name, scope: $openc3_scope)
163
+ response_body = nil
164
+ begin
165
+ endpoint = "/openc3-api/process_status/#{process_name}?scope=#{scope}"
166
+ uri = URI.parse($api_server.generate_url + endpoint)
167
+ auth = $api_server.generate_auth
168
+
169
+ request = Net::HTTP::Get.new(uri)
170
+ request['User-Agent'] = JsonDRbObject::USER_AGENT
171
+ request['Content-Type'] = 'application/json'
172
+ request['Authorization'] = auth.token
173
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
174
+ http.request(request) do |response|
175
+ response_body = response.body
176
+ response.value() # Raises an HTTP error if the response is not 2xx (success)
177
+ return JSON.parse(response.body, allow_nan: true, create_additions: true)
178
+ end
179
+ end
180
+ rescue => error
181
+ raise "plugin_status failed due to #{error.formatted}\nResponse:\n#{response_body}"
182
+ end
183
+ end
184
+
185
+ end
186
+ end
@@ -0,0 +1,119 @@
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
+ module OpenC3
20
+ module Script
21
+ private
22
+
23
+ def get_screen_list(scope: $openc3_scope)
24
+ begin
25
+ endpoint = "/openc3-api/screens"
26
+ # Pass the name of the ENV variable name where we pull the actual bucket name
27
+ response = $api_server.request('get', endpoint, scope: scope)
28
+ if response.nil? || response.code != 200
29
+ raise "Unexpected response to get_screen_list: #{response.inspect}"
30
+ end
31
+ screen_list = {}
32
+ filenames = JSON.parse(response.body)
33
+ filenames.each do |filename|
34
+ # TARGET/screens/filename.txt
35
+ split_filename = filename.split('/')
36
+ target_name = split_filename[0]
37
+ screen_name = File.basename(filename, '.txt').to_s.upcase
38
+ screen_list[target_name] ||= []
39
+ screen_list[target_name] << screen_name
40
+ end
41
+ return screen_list
42
+ rescue => error
43
+ raise "get_screen_list failed due to #{error.formatted}"
44
+ end
45
+ end
46
+
47
+ def get_screen_definition(target_name, screen_name, scope: $openc3_scope)
48
+ begin
49
+ endpoint = "/openc3-api/screen/#{target_name.upcase}/#{screen_name.upcase}"
50
+ response = $api_server.request('get', endpoint, headers: {
51
+ Accept: 'text/plain',
52
+ }, scope: scope)
53
+ if response.nil? || response.code != 200
54
+ raise "Screen definition not found: #{target_name} #{screen_name}"
55
+ end
56
+ return response.body
57
+ rescue => error
58
+ raise "get_screen_definition failed due to #{error.formatted}"
59
+ end
60
+ end
61
+
62
+ def create_screen(target_name, screen_name, definition, scope: $openc3_scope)
63
+ begin
64
+ endpoint = "/openc3-api/screen"
65
+ data = {
66
+ "target" => target_name,
67
+ "screen" => screen_name,
68
+ "text" => definition
69
+ }
70
+ response = $api_server.request('post', endpoint, :data => data, scope: scope)
71
+ if response.nil? || response.code != 200
72
+ if response
73
+ parsed = JSON.parse(response)
74
+ raise "create_screen error: #{parsed['error']}"
75
+ else
76
+ raise "create_screen failed"
77
+ end
78
+ end
79
+ return response.body
80
+ rescue => error
81
+ raise "create_screen failed due to #{error.formatted}"
82
+ end
83
+ end
84
+
85
+ def delete_screen(target_name, screen_name, scope: $openc3_scope)
86
+ begin
87
+ endpoint = "/openc3-api/screen/#{target_name.upcase}/#{screen_name.upcase}"
88
+ response = $api_server.request('delete', endpoint, scope: scope)
89
+ if response.nil? || response.code != 200
90
+ if response
91
+ parsed = JSON.parse(response)
92
+ raise "delete_screen error: #{parsed['error']}"
93
+ else
94
+ raise "delete_screen failed"
95
+ end
96
+ end
97
+ return response.body
98
+ rescue => error
99
+ raise "delete_screen failed due to #{error.formatted}"
100
+ end
101
+ end
102
+
103
+ def display_screen(target_name, screen_name, x = nil, y = nil, scope: $openc3_scope)
104
+ # Noop outside of ScriptRunner
105
+ end
106
+
107
+ def clear_screen(target_name, screen_name)
108
+ # Noop outside of ScriptRunner
109
+ end
110
+
111
+ def clear_all_screens
112
+ # Noop outside of ScriptRunner
113
+ end
114
+
115
+ def local_screen(screen_name, definition, x = nil, y = nil)
116
+ # Noop outside of ScriptRunner
117
+ end
118
+ end
119
+ end
@@ -29,9 +29,12 @@ require 'openc3/script/commands'
29
29
  require 'openc3/script/telemetry'
30
30
  require 'openc3/script/limits'
31
31
  require 'openc3/script/exceptions'
32
+ require 'openc3/script/screen'
32
33
  require 'openc3/script/script_runner'
33
34
  require 'openc3/script/storage'
34
35
  require 'openc3/script/web_socket_api'
36
+ require 'openc3/script/gems'
37
+ require 'openc3/script/plugins'
35
38
  require 'openc3/utilities/authentication'
36
39
 
37
40
  $api_server = nil