openc3 5.7.2 → 5.8.0

Sign up to get free protection for your applications and to get access to all the features.
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 +6 -6
  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