openc3 5.7.0 → 5.8.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/data/config/widgets.yaml +6 -6
  4. data/lib/openc3/api/cmd_api.rb +29 -0
  5. data/lib/openc3/api/limits_api.rb +31 -1
  6. data/lib/openc3/api/tlm_api.rb +5 -7
  7. data/lib/openc3/core_ext/faraday.rb +8 -0
  8. data/lib/openc3/core_ext.rb +1 -1
  9. data/lib/openc3/io/json_api_object.rb +24 -12
  10. data/lib/openc3/io/json_drb_object.rb +3 -7
  11. data/lib/openc3/logs/buffered_packet_log_writer.rb +20 -12
  12. data/lib/openc3/logs/log_writer.rb +12 -7
  13. data/lib/openc3/logs/packet_log_writer.rb +9 -6
  14. data/lib/openc3/microservices/decom_microservice.rb +4 -0
  15. data/lib/openc3/microservices/interface_decom_common.rb +32 -0
  16. data/lib/openc3/microservices/reducer_microservice.rb +15 -11
  17. data/lib/openc3/models/cvt_model.rb +10 -5
  18. data/lib/openc3/models/gem_model.rb +0 -1
  19. data/lib/openc3/models/scope_model.rb +0 -3
  20. data/lib/openc3/models/target_model.rb +7 -7
  21. data/lib/openc3/models/timeline_model.rb +0 -1
  22. data/lib/openc3/models/trigger_group_model.rb +0 -1
  23. data/lib/openc3/script/metadata.rb +7 -7
  24. data/lib/openc3/script/screen.rb +5 -5
  25. data/lib/openc3/script/script_runner.rb +17 -17
  26. data/lib/openc3/script/storage.rb +2 -2
  27. data/lib/openc3/topics/config_topic.rb +1 -6
  28. data/lib/openc3/topics/decom_interface_topic.rb +62 -0
  29. data/lib/openc3/topics/telemetry_decom_topic.rb +0 -9
  30. data/lib/openc3/topics/topic.rb +4 -11
  31. data/lib/openc3/utilities/authentication.rb +4 -4
  32. data/lib/openc3/utilities/bucket_require.rb +65 -0
  33. data/lib/openc3/utilities/bucket_utilities.rb +38 -5
  34. data/lib/openc3/utilities/open_telemetry.rb +4 -4
  35. data/lib/openc3/utilities/process_manager.rb +4 -2
  36. data/lib/openc3/utilities/ruby_lex_utils.rb +62 -36
  37. data/lib/openc3/utilities/store_autoload.rb +7 -28
  38. data/lib/openc3/version.rb +5 -5
  39. data/lib/openc3.rb +1 -1
  40. data/templates/widget/package.json +7 -7
  41. data/templates/widget/yarn.lock +46 -47
  42. metadata +55 -38
@@ -23,7 +23,6 @@
23
23
  require 'fileutils'
24
24
  require 'open-uri'
25
25
  require 'nokogiri'
26
- require 'httpclient'
27
26
  require 'rubygems'
28
27
  require 'rubygems/uninstaller'
29
28
  require 'tempfile'
@@ -135,7 +135,6 @@ module OpenC3
135
135
  end
136
136
 
137
137
  def deploy_unknown_commandlog_microservice(gem_path, variables, parent)
138
- Topic.initialize_streams(["#{@scope}__COMMAND__{UNKNOWN}__UNKNOWN"])
139
138
  microservice_name = "#{@scope}__COMMANDLOG__UNKNOWN"
140
139
  microservice = MicroserviceModel.new(
141
140
  name: microservice_name,
@@ -158,7 +157,6 @@ module OpenC3
158
157
  end
159
158
 
160
159
  def deploy_unknown_packetlog_microservice(gem_path, variables, parent)
161
- Topic.initialize_streams(["#{@scope}__TELEMETRY__{UNKNOWN}__UNKNOWN"])
162
160
  microservice_name = "#{@scope}__PACKETLOG__UNKNOWN"
163
161
  microservice = MicroserviceModel.new(
164
162
  name: microservice_name,
@@ -211,7 +209,6 @@ module OpenC3
211
209
 
212
210
  def deploy(gem_path, variables)
213
211
  seed_database()
214
- ConfigTopic.initialize_stream(@scope)
215
212
 
216
213
  # Create UNKNOWN target for display of unknown data
217
214
  model = TargetModel.new(name: "UNKNOWN", scope: @scope)
@@ -527,7 +527,13 @@ module OpenC3
527
527
  data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
528
528
  end
529
529
  rescue => error
530
- raise "ERB error parsing: #{filename}: #{error.formatted}"
530
+ # ERB error parsing a screen is just a logger error because life can go on
531
+ # With cmd/tlm or scripts this is a serious error and we raise
532
+ if (filename.include?('/screens/'))
533
+ Logger.error("ERB error parsing #{key} due to #{error.message}")
534
+ else
535
+ raise "ERB error parsing #{key} due to #{error.message}"
536
+ end
531
537
  end
532
538
  local_path = File.join(temp_dir, @name, target_folder_path)
533
539
  FileUtils.mkdir_p(File.dirname(local_path))
@@ -965,12 +971,6 @@ module OpenC3
965
971
  rescue
966
972
  # No telemetry packets for this target
967
973
  end
968
- # It's ok to call initialize_streams with an empty array
969
- Topic.initialize_streams(command_topic_list)
970
- Topic.initialize_streams(decom_command_topic_list)
971
- Topic.initialize_streams(packet_topic_list)
972
- Topic.initialize_streams(decom_topic_list)
973
- Topic.initialize_streams(reduced_topic_list)
974
974
 
975
975
  @parent = nil
976
976
  %w(DECOM COMMANDLOG DECOMCMDLOG PACKETLOG DECOMLOG REDUCER CLEANUP).each do |type|
@@ -128,7 +128,6 @@ module OpenC3
128
128
 
129
129
  def deploy
130
130
  topics = ["#{@scope}__#{PRIMARY_KEY}"]
131
- TimelineTopic.initialize_streams(topics)
132
131
  # Timeline Microservice
133
132
  microservice = MicroserviceModel.new(
134
133
  name: @name,
@@ -172,7 +172,6 @@ module OpenC3
172
172
  def deploy
173
173
  topics = ["#{@scope}__openc3_autonomic"]
174
174
  if MicroserviceModel.get_model(name: @microservice_name, scope: @scope).nil?
175
- AutonomicTopic.initialize_streams(topics)
176
175
  create_microservice(topics: topics)
177
176
  end
178
177
  end
@@ -35,7 +35,7 @@ module OpenC3
35
35
  def metadata_all(limit: 100, scope: $openc3_scope)
36
36
  response = $api_server.request('get', "/openc3-api/metadata", query: { limit: limit }, scope: scope)
37
37
  # Non-existant just returns nil
38
- return nil if response.nil? || response.code != 200
38
+ return nil if response.nil? || response.status != 200
39
39
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
40
40
  end
41
41
  alias all_metadata metadata_all
@@ -50,7 +50,7 @@ module OpenC3
50
50
  response = $api_server.request('get', "/openc3-api/metadata/latest", scope: scope)
51
51
  end
52
52
  # Non-existant just returns nil
53
- return nil if response.nil? || response.code != 200
53
+ return nil if response.nil? || response.status != 200
54
54
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
55
55
  end
56
56
  alias get_metadata metadata_get
@@ -70,11 +70,11 @@ module OpenC3
70
70
  data[:start] = start.iso8601 unless start.nil?
71
71
  response = $api_server.request('post', '/openc3-api/metadata', data: data, json: true, scope: scope)
72
72
  if response.nil?
73
- raise "Failed to set metadata due to #{response.code}"
74
- elsif response.code == 409
73
+ raise "Failed to set metadata due to #{response.status}"
74
+ elsif response.status == 409
75
75
  raise "Metadata overlaps existing metadata. Did you metadata_set within 1s of another?"
76
- elsif response.code != 201
77
- raise "Failed to set metadata due to #{response.code}"
76
+ elsif response.status != 201
77
+ raise "Failed to set metadata due to #{response.status}"
78
78
  end
79
79
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
80
80
  end
@@ -101,7 +101,7 @@ module OpenC3
101
101
  data = { :color => color, :metadata => metadata }
102
102
  data[:start] = Time.at(start).iso8601
103
103
  response = $api_server.request('put', "/openc3-api/metadata/#{start}", data: data, json: true, scope: scope)
104
- if response.nil? || response.code != 200
104
+ if response.nil? || response.status != 200
105
105
  raise "Failed to update metadata"
106
106
  end
107
107
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -25,7 +25,7 @@ module OpenC3
25
25
  endpoint = "/openc3-api/screens"
26
26
  # Pass the name of the ENV variable name where we pull the actual bucket name
27
27
  response = $api_server.request('get', endpoint, scope: scope)
28
- if response.nil? || response.code != 200
28
+ if response.nil? || response.status != 200
29
29
  raise "Unexpected response to get_screen_list: #{response.inspect}"
30
30
  end
31
31
  screen_list = {}
@@ -50,7 +50,7 @@ module OpenC3
50
50
  response = $api_server.request('get', endpoint, headers: {
51
51
  Accept: 'text/plain',
52
52
  }, scope: scope)
53
- if response.nil? || response.code != 200
53
+ if response.nil? || response.status != 200
54
54
  raise "Screen definition not found: #{target_name} #{screen_name}"
55
55
  end
56
56
  return response.body
@@ -67,8 +67,8 @@ module OpenC3
67
67
  "screen" => screen_name,
68
68
  "text" => definition
69
69
  }
70
- response = $api_server.request('post', endpoint, :data => data, scope: scope)
71
- if response.nil? || response.code != 200
70
+ response = $api_server.request('post', endpoint, :data => data, :json => true, scope: scope)
71
+ if response.nil? || response.status != 200
72
72
  if response
73
73
  parsed = JSON.parse(response)
74
74
  raise "create_screen error: #{parsed['error']}"
@@ -86,7 +86,7 @@ module OpenC3
86
86
  begin
87
87
  endpoint = "/openc3-api/screen/#{target_name.upcase}/#{screen_name.upcase}"
88
88
  response = $api_server.request('delete', endpoint, scope: scope)
89
- if response.nil? || response.code != 200
89
+ if response.nil? || response.status != 200
90
90
  if response
91
91
  parsed = JSON.parse(response)
92
92
  raise "delete_screen error: #{parsed['error']}"
@@ -22,7 +22,7 @@ module OpenC3
22
22
 
23
23
  def _script_response_error(response, message, scope: $openc3_scope)
24
24
  if response
25
- raise "#{message} (#{response.code}): #{response.body}"
25
+ raise "#{message} (#{response.status}): #{response.body}"
26
26
  else
27
27
  raise "#{message}: No Response"
28
28
  end
@@ -31,7 +31,7 @@ module OpenC3
31
31
  def script_list(scope: $openc3_scope)
32
32
  endpoint = "/script-api/scripts"
33
33
  response = $script_runner_api_server.request('get', endpoint, scope: scope)
34
- if response.nil? || response.code != 200
34
+ if response.nil? || response.status != 200
35
35
  _script_response_error(response, "Script list request failed", scope: scope)
36
36
  else
37
37
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -41,7 +41,7 @@ module OpenC3
41
41
  def script_syntax_check(script, scope: $openc3_scope)
42
42
  endpoint = "/script-api/scripts/syntax"
43
43
  response = $script_runner_api_server.request('post', endpoint, json: true, data: script, scope: scope)
44
- if response.nil? || response.code != 200
44
+ if response.nil? || response.status != 200
45
45
  _script_response_error(response, "Script syntax check request failed", scope: scope)
46
46
  else
47
47
  result = JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -56,7 +56,7 @@ module OpenC3
56
56
  def script_body(filename, scope: $openc3_scope)
57
57
  endpoint = "/script-api/scripts/#{filename}"
58
58
  response = $script_runner_api_server.request('get', endpoint, scope: scope)
59
- if response.nil? || response.code != 200
59
+ if response.nil? || response.status != 200
60
60
  _script_response_error(response, "Failed to get #{filename}", scope: scope)
61
61
  else
62
62
  script = response.body
@@ -82,7 +82,7 @@ module OpenC3
82
82
  end
83
83
  # NOTE: json: true causes json_api_object to JSON generate and set the Content-Type to json
84
84
  response = $script_runner_api_server.request('post', endpoint, json: true, data: { environment: env_data }, scope: scope)
85
- if response.nil? || response.code != 200
85
+ if response.nil? || response.status != 200
86
86
  _script_response_error(response, "Failed to run #{filename}", scope: scope)
87
87
  else
88
88
  script_id = Integer(response.body)
@@ -93,7 +93,7 @@ module OpenC3
93
93
  def script_delete(filename, scope: $openc3_scope)
94
94
  endpoint = "/script-api/scripts/#{filename}/delete"
95
95
  response = $script_runner_api_server.request('post', endpoint, scope: scope)
96
- if response.nil? || response.code != 200
96
+ if response.nil? || response.status != 200
97
97
  _script_response_error(response, "Failed to delete #{filename}", scope: scope)
98
98
  else
99
99
  return true
@@ -103,7 +103,7 @@ module OpenC3
103
103
  def script_lock(filename, scope: $openc3_scope)
104
104
  endpoint = "/script-api/scripts/#{filename}/lock"
105
105
  response = $script_runner_api_server.request('post', endpoint, scope: scope)
106
- if response.nil? || response.code != 200
106
+ if response.nil? || response.status != 200
107
107
  _script_response_error(response, "Failed to lock #{filename}", scope: scope)
108
108
  else
109
109
  return true
@@ -113,7 +113,7 @@ module OpenC3
113
113
  def script_unlock(filename, scope: $openc3_scope)
114
114
  endpoint = "/script-api/scripts/#{filename}/unlock"
115
115
  response = $script_runner_api_server.request('post', endpoint, scope: scope)
116
- if response.nil? || response.code != 200
116
+ if response.nil? || response.status != 200
117
117
  _script_response_error(response, "Failed to unlock #{filename}", scope: scope)
118
118
  else
119
119
  return true
@@ -123,7 +123,7 @@ module OpenC3
123
123
  def script_instrumented(filename, script, scope: $openc3_scope)
124
124
  endpoint = "/script-api/scripts/#{filename}/instrumented"
125
125
  response = $script_runner_api_server.request('post', endpoint, json: true, data: script, scope: scope)
126
- if response.nil? || response.code != 200
126
+ if response.nil? || response.status != 200
127
127
  _script_response_error(response, "Script instrumented request failed", scope: scope)
128
128
  else
129
129
  result = JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -139,7 +139,7 @@ module OpenC3
139
139
  def script_create(filename, script, breakpoints = [], scope: $openc3_scope)
140
140
  endpoint = "/script-api/scripts/#{filename}"
141
141
  response = $script_runner_api_server.request('post', endpoint, json: true, data: { text: script, breakpoints: breakpoints }, scope: scope)
142
- if response.nil? || response.code != 200
142
+ if response.nil? || response.status != 200
143
143
  _script_response_error(response, "Script create request failed", scope: scope)
144
144
  else
145
145
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -149,7 +149,7 @@ module OpenC3
149
149
  def script_delete_all_breakpoints(scope: $openc3_scope)
150
150
  endpoint = "/script-api/breakpoints/delete/all"
151
151
  response = $script_runner_api_server.request('delete', endpoint, scope: scope)
152
- if response.nil? || response.code != 200
152
+ if response.nil? || response.status != 200
153
153
  _script_response_error(response, "Script delete all breakpoints failed", scope: scope)
154
154
  else
155
155
  return true
@@ -159,7 +159,7 @@ module OpenC3
159
159
  def running_script_list(scope: $openc3_scope)
160
160
  endpoint = "/script-api/running-script"
161
161
  response = $script_runner_api_server.request('get', endpoint, scope: scope)
162
- if response.nil? || response.code != 200
162
+ if response.nil? || response.status != 200
163
163
  _script_response_error(response, "Running script list request failed", scope: scope)
164
164
  else
165
165
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -169,7 +169,7 @@ module OpenC3
169
169
  def running_script_get(id, scope: $openc3_scope)
170
170
  endpoint = "/script-api/running-script/#{id}"
171
171
  response = $script_runner_api_server.request('get', endpoint, scope: scope)
172
- if response.nil? || response.code != 200
172
+ if response.nil? || response.status != 200
173
173
  _script_response_error(response, "Running script show request failed", scope: scope)
174
174
  else
175
175
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -179,7 +179,7 @@ module OpenC3
179
179
  def _running_script_action(id, action_name, scope: $openc3_scope)
180
180
  endpoint = "/script-api/running-script/#{id}/#{action_name}"
181
181
  response = $script_runner_api_server.request('post', endpoint, scope: scope)
182
- if response.nil? || response.code != 200
182
+ if response.nil? || response.status != 200
183
183
  _script_response_error(response, "Running script #{action_name} request failed", scope: scope)
184
184
  else
185
185
  return true
@@ -217,7 +217,7 @@ module OpenC3
217
217
  def running_script_debug(id, debug_code, scope: $openc3_scope)
218
218
  endpoint = "/script-api/running-script/#{id}/debug"
219
219
  response = $script_runner_api_server.request('post', endpoint, json: true, data: {'args' => debug_code}, scope: scope)
220
- if response.nil? || response.code != 200
220
+ if response.nil? || response.status != 200
221
221
  _script_response_error(response, "Running script debug request failed", scope: scope)
222
222
  else
223
223
  return true
@@ -231,7 +231,7 @@ module OpenC3
231
231
  else
232
232
  response = $script_runner_api_server.request('post', endpoint, json: true, data: {'method' => method_name, 'answer' => answer, 'prompt_id' => prompt_id}, scope: scope)
233
233
  end
234
- if response.nil? || response.code != 200
234
+ if response.nil? || response.status != 200
235
235
  _script_response_error(response, "Running script prompt request failed", scope: scope)
236
236
  else
237
237
  return true
@@ -241,7 +241,7 @@ module OpenC3
241
241
  def completed_script_list(scope: $openc3_scope)
242
242
  endpoint = "/script-api/completed-scripts"
243
243
  response = $script_runner_api_server.request('get', endpoint, scope: scope)
244
- if response.nil? || response.code != 200
244
+ if response.nil? || response.status != 200
245
245
  _script_response_error(response, "Completed script list request failed", scope: scope)
246
246
  else
247
247
  return JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -40,7 +40,7 @@ module OpenC3
40
40
  OpenC3::Logger.info "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
- if response.nil? || response.code != 200
43
+ if response.nil? || response.status != 200
44
44
  raise "Failed to delete #{delete_path}"
45
45
  end
46
46
  rescue => error
@@ -181,7 +181,7 @@ module OpenC3
181
181
  else
182
182
  response = $api_server.request('get', endpoint, query: { bucket: 'OPENC3_CONFIG_BUCKET' }, scope: scope)
183
183
  end
184
- if response.nil? || response.code != 201
184
+ if response.nil? || response.status != 201
185
185
  raise "Failed to get presigned URL for #{endpoint}"
186
186
  end
187
187
  JSON.parse(response.body, :allow_nan => true, :create_additions => true)
@@ -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/topics/topic'
@@ -26,11 +26,6 @@ module OpenC3
26
26
  class ConfigTopic < Topic
27
27
  PRIMARY_KEY = "__CONFIG"
28
28
 
29
- # Helper method to initialize the stream and ensure a consistent key
30
- def self.initialize_stream(scope)
31
- self.initialize_streams(["#{scope}#{PRIMARY_KEY}"])
32
- end
33
-
34
29
  # Write a configuration change to the topic
35
30
  # @param config [Hash] Hash with required keys 'kind', 'name', 'type'
36
31
  def self.write(config, scope:)
@@ -0,0 +1,62 @@
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/topics/topic'
20
+
21
+ module OpenC3
22
+ class DecomInterfaceTopic < Topic
23
+ def self.build_cmd(target_name, cmd_name, cmd_params, range_check, raw, scope:)
24
+ data = {}
25
+ data['target_name'] = target_name.to_s.upcase
26
+ data['cmd_name'] = cmd_name.to_s.upcase
27
+ data['cmd_params'] = cmd_params
28
+ data['range_check'] = range_check
29
+ data['raw'] = raw
30
+ # DecomMicroservice is listening to the DECOMINTERFACE topic and is responsible
31
+ # for actually building the command. This was deliberate to allow this to work
32
+ # with or without an interface.
33
+ decom_id = Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",
34
+ { 'build_cmd' => JSON.generate(data, allow_nan: true) }, '*', 100)
35
+ timeout = 5 # Arbitrary 5s timeout
36
+ ack_topic = "{#{scope}__ACKCMD}TARGET__#{target_name}"
37
+ time = Time.now
38
+ while (Time.now - time) < timeout
39
+ Topic.read_topics([ack_topic]) do |topic, msg_id, msg_hash, redis|
40
+ if msg_hash["id"] == decom_id
41
+ if msg_hash["result"] == "SUCCESS"
42
+ return msg_hash
43
+ else
44
+ raise msg_hash["message"]
45
+ end
46
+ end
47
+ end
48
+ end
49
+ raise "Timeout of #{timeout}s waiting for cmd ack. Does target '#{target_name}' exist?"
50
+ end
51
+
52
+ def self.inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, scope:)
53
+ data = {}
54
+ data['target_name'] = target_name.to_s.upcase
55
+ data['packet_name'] = packet_name.to_s.upcase
56
+ data['item_hash'] = item_hash
57
+ data['type'] = type
58
+ Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}",
59
+ { 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
60
+ end
61
+ end
62
+ end
@@ -56,14 +56,5 @@ module OpenC3
56
56
  end
57
57
  end
58
58
  end
59
-
60
- def self.inject_tlm(target_name, packet_name, item_hash = nil, type: :CONVERTED, scope:)
61
- data = {}
62
- data['target_name'] = target_name.to_s.upcase
63
- data['packet_name'] = packet_name.to_s.upcase
64
- data['item_hash'] = item_hash
65
- data['type'] = type
66
- Topic.write_topic("#{scope}__DECOMINTERFACE__{#{target_name}}", { 'inject_tlm' => JSON.generate(data, allow_nan: true) }, '*', 100)
67
- end
68
59
  end
69
60
  end
@@ -17,23 +17,16 @@
17
17
  # All changes Copyright 2022, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
- # This file may also be used under the terms of a commercial license
20
+ # This file may also be used under the terms of a commercial license
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/utilities/store'
24
24
 
25
25
  module OpenC3
26
26
  class Topic
27
- if RUBY_VERSION < "3"
28
- # Delegate all unknown class methods to delegate to the EphemeralStore
29
- def self.method_missing(message, *args, &block)
30
- EphemeralStore.public_send(message, *args, &block)
31
- end
32
- else
33
- # Delegate all unknown class methods to delegate to the EphemeralStore
34
- def self.method_missing(message, *args, **kwargs, &block)
35
- EphemeralStore.public_send(message, *args, **kwargs, &block)
36
- end
27
+ # Delegate all unknown class methods to delegate to the EphemeralStore
28
+ def self.method_missing(message, *args, **kwargs, &block)
29
+ EphemeralStore.public_send(message, *args, **kwargs, &block)
37
30
  end
38
31
 
39
32
  def self.clear_topics(topics, maxlen = 0)
@@ -14,19 +14,18 @@
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
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/version'
24
+ require 'faraday'
24
25
 
25
26
  module OpenC3
26
-
27
27
  # Basic exception for known errors
28
28
  class OpenC3AuthenticationError < StandardError; end
29
-
30
29
  class OpenC3AuthenticationRetryableError < OpenC3AuthenticationError; end
31
30
 
32
31
  # OpenC3 base / open source authentication code
@@ -71,6 +70,7 @@ module OpenC3
71
70
  @refresh_expires_at = nil
72
71
  @token = nil
73
72
  @log = [nil, nil]
73
+ @http = Faraday.new
74
74
  end
75
75
 
76
76
  # Load the token from the environment
@@ -150,7 +150,7 @@ module OpenC3
150
150
  STDOUT.puts @log[0] if JsonDRb.debug?
151
151
  saved_verbose = $VERBOSE; $VERBOSE = nil
152
152
  begin
153
- resp = HTTPClient.new().post(uri, :body => data, :header => headers)
153
+ resp = @http.post(uri, data, headers)
154
154
  ensure
155
155
  $VERBOSE = saved_verbose
156
156
  end
@@ -0,0 +1,65 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2022 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'
20
+ require 'openc3/utilities/bucket_utilities'
21
+
22
+ OpenC3.disable_warnings do
23
+ def require(*args, **kw_args)
24
+ begin
25
+ return super(*args, **kw_args)
26
+ rescue LoadError
27
+ begin
28
+ @bucket_require_cache ||= {}
29
+ if @bucket_require_cache[args[0]]
30
+ return false
31
+ else
32
+ scope = nil
33
+ if kw_args[:scope]
34
+ scope = kw_args[:scope]
35
+ else
36
+ scope = $openc3_scope
37
+ end
38
+ OpenC3::BucketUtilities.bucket_load(*args, scope: scope)
39
+ @bucket_require_cache[args[0]] = true
40
+ return true
41
+ end
42
+ rescue Exception => err
43
+ raise LoadError, "#{err.class}:#{err.message}", err.backtrace
44
+ end
45
+ end
46
+ end
47
+
48
+ def load(*args, **kw_args)
49
+ begin
50
+ super(*args, **kw_args)
51
+ rescue LoadError
52
+ begin
53
+ scope = nil
54
+ if kw_args[:scope]
55
+ scope = kw_args[:scope]
56
+ else
57
+ scope = $openc3_scope
58
+ end
59
+ OpenC3::BucketUtilities.bucket_load(*args, scope: scope)
60
+ rescue Exception
61
+ raise LoadError, "#{err.class}:#{err.message}", err.backtrace
62
+ end
63
+ end
64
+ end
65
+ end
@@ -21,6 +21,7 @@
21
21
  # if purchased from OpenC3, Inc.
22
22
 
23
23
  require 'openc3/utilities/bucket'
24
+ require 'openc3/utilities/target_file'
24
25
  require 'openc3/models/reducer_model'
25
26
  require 'zlib'
26
27
 
@@ -29,6 +30,26 @@ module OpenC3
29
30
  FILE_TIMESTAMP_FORMAT = "%Y%m%d%H%M%S%N"
30
31
  DIRECTORY_TIMESTAMP_FORMAT = "%Y%m%d"
31
32
 
33
+ def self.bucket_load(*args, scope: $openc3_scope)
34
+ path = args[0]
35
+
36
+ # Only support TARGET files
37
+ if path[0] == '/' or path.split('/')[0].to_s.upcase != path.split('/')[0]
38
+ raise LoadError
39
+ end
40
+ extension = File.extname(path)
41
+ path = path + '.rb' if extension == ""
42
+
43
+ # Retrieve the text of the script from S3
44
+ text = TargetFile.body(scope, path)
45
+
46
+ # Execute the script directly without instrumentation because we are doing require/load
47
+ Object.class_eval(text, path, 1)
48
+
49
+ # Successful load/require returns true
50
+ true
51
+ end
52
+
32
53
  # @param bucket [String] Name of the bucket to list
33
54
  # @param prefix [String] Prefix to filter all files by
34
55
  # @param start_time [Time|nil] Ruby time to find files after. nil means no start (first file on).
@@ -66,12 +87,24 @@ module OpenC3
66
87
  filename = compress_file(filename)
67
88
  bucket_key += '.gz'
68
89
  end
69
- # We want to open this as a file and pass that to put_object to allow
70
- # this to work with really large files. Otherwise the entire file has
71
- # to be held in memory!
72
- File.open(filename, 'rb') do |file|
73
- client.put_object(bucket: ENV['OPENC3_LOGS_BUCKET'], key: bucket_key, body: file, metadata: metadata)
90
+
91
+ retry_count = 0
92
+ begin
93
+ # We want to open this as a file and pass that to put_object to allow
94
+ # this to work with really large files. Otherwise the entire file has
95
+ # to be held in memory!
96
+ File.open(filename, 'rb') do |file|
97
+ client.put_object(bucket: ENV['OPENC3_LOGS_BUCKET'], key: bucket_key, body: file, metadata: metadata)
98
+ end
99
+ rescue => err
100
+ # Try to upload file three times
101
+ retry_count += 1
102
+ raise err if retry_count >= 3
103
+ Logger.warn("Error saving log file to bucket - retry #{retry_count}: #{filename}\n#{err.formatted}")
104
+ sleep(1)
105
+ retry
74
106
  end
107
+
75
108
  Logger.debug "wrote #{ENV['OPENC3_LOGS_BUCKET']}/#{bucket_key}"
76
109
  ReducerModel.add_file(bucket_key) # Record the new file for data reduction
77
110
 
@@ -1,6 +1,6 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- # Copyright 2022 OpenC3, Inc.
3
+ # Copyright 2023 OpenC3, Inc.
4
4
  # All Rights Reserved.
5
5
  #
6
6
  # This program is free software; you can modify and/or redistribute it
@@ -13,7 +13,7 @@
13
13
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
14
  # GNU Affero General Public License for more details.
15
15
  #
16
- # This file may also be used under the terms of a commercial license
16
+ # This file may also be used under the terms of a commercial license
17
17
  # if purchased from OpenC3, Inc.
18
18
 
19
19
  require 'openc3/utilities/bucket'
@@ -60,7 +60,7 @@ module OpenC3
60
60
 
61
61
  if @otel_enabled
62
62
  require 'redis'
63
- require 'httpclient'
63
+ require 'faraday'
64
64
  require 'openc3/utilities/bucket'
65
65
  # Load the bucket client code so the instrumentation works later
66
66
  Bucket.getClient()
@@ -86,7 +86,7 @@ module OpenC3
86
86
  # To omit the attribute, set db_statement to :omit.
87
87
  db_statement: :include,
88
88
  }
89
- c.use 'OpenTelemetry::Instrumentation::HttpClient'
89
+ c.use 'OpenTelemetry::Instrumentation::Faraday'
90
90
  c.use 'OpenTelemetry::Instrumentation::AwsSdk'
91
91
  # TODO: Add in additional cloud SDKs
92
92
  end