openc3 5.10.1 → 5.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -2
  3. data/data/config/target.yaml +9 -0
  4. data/ext/openc3/ext/packet/packet.c +3 -0
  5. data/ext/openc3/ext/reducer_microservice/extconf.rb +13 -0
  6. data/ext/openc3/ext/reducer_microservice/reducer_microservice.c +165 -0
  7. data/ext/openc3/ext/structure/structure.c +7 -9
  8. data/lib/openc3/accessors/accessor.rb +53 -3
  9. data/lib/openc3/accessors/binary_accessor.rb +16 -0
  10. data/lib/openc3/accessors/cbor_accessor.rb +3 -3
  11. data/lib/openc3/accessors/form_accessor.rb +78 -0
  12. data/lib/openc3/accessors/http_accessor.rb +145 -0
  13. data/lib/openc3/accessors/json_accessor.rb +19 -3
  14. data/lib/openc3/accessors/xml_accessor.rb +18 -1
  15. data/lib/openc3/accessors.rb +3 -1
  16. data/lib/openc3/config/config_parser.rb +7 -5
  17. data/lib/openc3/config/meta_config_parser.rb +1 -1
  18. data/lib/openc3/core_ext/string.rb +16 -1
  19. data/lib/openc3/interfaces/http_client_interface.rb +202 -0
  20. data/lib/openc3/interfaces/http_server_interface.rb +183 -0
  21. data/lib/openc3/interfaces/interface.rb +86 -16
  22. data/lib/openc3/interfaces/mqtt_interface.rb +6 -5
  23. data/lib/openc3/interfaces/protocols/burst_protocol.rb +11 -11
  24. data/lib/openc3/interfaces/protocols/cobs_protocol.rb +7 -7
  25. data/lib/openc3/interfaces/protocols/crc_protocol.rb +7 -7
  26. data/lib/openc3/interfaces/protocols/length_protocol.rb +6 -6
  27. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +9 -5
  28. data/lib/openc3/interfaces/protocols/protocol.rb +8 -6
  29. data/lib/openc3/interfaces/protocols/slip_protocol.rb +8 -8
  30. data/lib/openc3/interfaces/protocols/template_protocol.rb +6 -7
  31. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +4 -4
  32. data/lib/openc3/interfaces/simulated_target_interface.rb +2 -0
  33. data/lib/openc3/interfaces/stream_interface.rb +6 -4
  34. data/lib/openc3/interfaces/tcpip_server_interface.rb +2 -0
  35. data/lib/openc3/interfaces/udp_interface.rb +8 -5
  36. data/lib/openc3/interfaces.rb +2 -0
  37. data/lib/openc3/logs/buffered_packet_log_writer.rb +6 -7
  38. data/lib/openc3/logs/log_writer.rb +2 -10
  39. data/lib/openc3/logs/packet_log_constants.rb +13 -3
  40. data/lib/openc3/logs/packet_log_reader.rb +35 -98
  41. data/lib/openc3/logs/packet_log_writer.rb +24 -62
  42. data/lib/openc3/logs/text_log_writer.rb +32 -6
  43. data/lib/openc3/microservices/cleanup_microservice.rb +23 -16
  44. data/lib/openc3/microservices/decom_microservice.rb +8 -20
  45. data/lib/openc3/microservices/log_microservice.rb +3 -1
  46. data/lib/openc3/microservices/reaction_microservice.rb +22 -11
  47. data/lib/openc3/microservices/reducer_microservice.rb +174 -130
  48. data/lib/openc3/{models/notification_model.rb → microservices/scope_cleanup_microservice.rb} +20 -21
  49. data/lib/openc3/microservices/text_log_microservice.rb +2 -5
  50. data/lib/openc3/microservices/timeline_microservice.rb +0 -1
  51. data/lib/openc3/microservices/trigger_group_microservice.rb +0 -1
  52. data/lib/openc3/migrations/20230915000002_no_scope_log_messages.rb +44 -0
  53. data/lib/openc3/models/microservice_model.rb +1 -1
  54. data/lib/openc3/models/scope_model.rb +65 -34
  55. data/lib/openc3/models/target_model.rb +25 -5
  56. data/lib/openc3/models/tool_model.rb +14 -2
  57. data/lib/openc3/models/widget_model.rb +1 -1
  58. data/lib/openc3/packets/json_packet.rb +10 -2
  59. data/lib/openc3/packets/packet.rb +30 -9
  60. data/lib/openc3/packets/packet_config.rb +6 -2
  61. data/lib/openc3/packets/parsers/packet_item_parser.rb +11 -6
  62. data/lib/openc3/packets/structure.rb +19 -12
  63. data/lib/openc3/script/storage.rb +1 -1
  64. data/lib/openc3/script/web_socket_api.rb +17 -14
  65. data/lib/openc3/topics/telemetry_topic.rb +2 -1
  66. data/lib/openc3/utilities/bucket_utilities.rb +2 -0
  67. data/lib/openc3/utilities/cli_generator.rb +1 -1
  68. data/lib/openc3/utilities/logger.rb +62 -47
  69. data/lib/openc3/utilities/metric.rb +19 -1
  70. data/lib/openc3/utilities/sleeper.rb +3 -1
  71. data/lib/openc3/utilities/throttle.rb +76 -0
  72. data/lib/openc3/version.rb +6 -6
  73. data/templates/tool_angular/package.json +20 -20
  74. data/templates/tool_angular/yarn.lock +112 -106
  75. data/templates/tool_react/package.json +16 -18
  76. data/templates/tool_react/yarn.lock +977 -664
  77. data/templates/tool_svelte/.prettierrc.js +5 -0
  78. data/templates/tool_svelte/package.json +18 -18
  79. data/templates/tool_svelte/src/services/cable.js +1 -1
  80. data/templates/tool_svelte/src/services/openc3-api.js +173 -173
  81. data/templates/tool_svelte/yarn.lock +767 -665
  82. data/templates/tool_vue/package.json +10 -10
  83. data/templates/tool_vue/yarn.lock +225 -43
  84. data/templates/widget/package.json +10 -10
  85. data/templates/widget/yarn.lock +223 -46
  86. metadata +41 -4
  87. data/lib/openc3/topics/notifications_topic.rb +0 -31
@@ -190,7 +190,7 @@ module OpenC3
190
190
 
191
191
  # Base class for script-runner-api websockets - Do not use directly
192
192
  class ScriptWebSocketApi < WebSocketApi
193
- def initialize(url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_token)
193
+ def initialize(url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
194
194
  url = generate_url() unless url
195
195
  super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
196
196
  end
@@ -217,23 +217,15 @@ module OpenC3
217
217
 
218
218
  # Log Messages WebSocket
219
219
  class MessagesWebSocketApi < CmdTlmWebSocketApi
220
- def initialize(history_count: 0, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
220
+ def initialize(history_count: 0, start_time: nil, end_time: nil, severity: 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
- super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
226
- end
227
- end
228
-
229
- # Notifications WebSocket
230
- class NotificationsWebSocketApi < CmdTlmWebSocketApi
231
- def initialize(history_count: 0, start_offset: nil, url: nil, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope)
232
- @identifier = {
233
- channel: "NotificationsChannel",
234
- history_count: history_count,
235
- start_offset: start_offset
236
- }
225
+ @identifier['start_time'] = start_time if start_time
226
+ @identifier['end_time'] = end_time if end_time
227
+ @identifier['severity'] = severity if severity
228
+ @identifier['types'] = types if types
237
229
  super(url: url, write_timeout: write_timeout, read_timeout: read_timeout, connect_timeout: connect_timeout, authentication: authentication, scope: scope)
238
230
  end
239
231
  end
@@ -425,3 +417,14 @@ end
425
417
  #
426
418
  # # Warning this saves all data to RAM. Do not use for large queries
427
419
  # data = OpenC3::StreamingWebSocketApi.read_all(items: ['DECOM__TLM__INST__HEALTH_STATUS__TEMP1__CONVERTED', 'DECOM__TLM__INST__HEALTH_STATUS__TEMP2__CONVERTED'], start_time: Time.now - 30, end_time: Time.now + 30)
420
+
421
+ # $openc3_scope = 'DEFAULT'
422
+ # OpenC3::MessagesWebSocketApi.new(history_count: 0, start_time: (Time.now - 86400).to_nsec_from_epoch, end_time: (Time.now - 60).to_nsec_from_epoch) do |api|
423
+ # 500.times do
424
+ # # Note returns batch array
425
+ # data = api.read
426
+ # return if not data or data.length == 0
427
+ # puts "\nReceived #{data.length} log messages:"
428
+ # puts data
429
+ # end
430
+ # end
@@ -32,8 +32,9 @@ module OpenC3
32
32
  :target_name => packet.target_name,
33
33
  :packet_name => packet.packet_name,
34
34
  :received_count => packet.received_count,
35
- :buffer => packet.buffer(false),
35
+ :buffer => packet.buffer(false)
36
36
  }
37
+ msg_hash[:extra] = JSON.generate(packet.extra.as_json, allow_nan: true) if packet.extra
37
38
  Topic.write_topic("#{scope}__TELEMETRY__{#{packet.target_name}}__#{packet.packet_name}", msg_hash)
38
39
  end
39
40
  end
@@ -58,6 +58,8 @@ module OpenC3
58
58
  # @param start_time [Time|nil] Ruby time to find files after. nil means no start (first file on).
59
59
  # @param end_time [Time|nil] Ruby time to find files before. nil means no end (up to last file).
60
60
  # @param overlap [Boolean] Whether to include files which overlap the start and end time
61
+ # if true, file can be partially in the time range
62
+ # if false, file must be completely in the time range
61
63
  # @param max_request [Integer] How many files to request in each API call
62
64
  # @param max_total [Integer] Total number of files before stopping API requests
63
65
  def self.files_between_time(bucket, prefix, start_time, end_time, file_suffix: nil,
@@ -51,7 +51,7 @@ module OpenC3
51
51
  FileUtils.mkdir(base_name) unless File.exist?(base_name)
52
52
  next
53
53
  end
54
- output = ERB.new(File.read(file), trim_mode: "-").result(the_binding)
54
+ output = ERB.new(File.read(file).comment_erb(), trim_mode: "-").result(the_binding)
55
55
  File.open(base_name, 'w') do |file|
56
56
  file.write output
57
57
  end
@@ -14,7 +14,7 @@
14
14
  # GNU Affero General Public License for more details.
15
15
 
16
16
  # Modified by OpenC3, Inc.
17
- # All changes Copyright 2022, OpenC3, Inc.
17
+ # All changes Copyright 2023, OpenC3, Inc.
18
18
  # All Rights Reserved
19
19
  #
20
20
  # This file may also be used under the terms of a commercial license
@@ -44,11 +44,9 @@ module OpenC3
44
44
  # @return [String] Microservice name
45
45
  attr_reader :microservice_name
46
46
 
47
- # @return [String] Scope
48
- instance_attr_accessor :scope
49
-
50
47
  @@mutex = Mutex.new
51
48
  @@instance = nil
49
+ @@scope = ENV['OPENC3_SCOPE']
52
50
 
53
51
  # DEBUG only prints DEBUG messages
54
52
  DEBUG = ::Logger::DEBUG
@@ -67,11 +65,15 @@ module OpenC3
67
65
  ERROR_SEVERITY_STRING = 'ERROR'
68
66
  FATAL_SEVERITY_STRING = 'FATAL'
69
67
 
68
+ # Types
69
+ LOG = 'log'
70
+ NOTIFICATION = 'notification'
71
+ ALERT = 'alert'
72
+
70
73
  # @param level [Integer] The initial logging level
71
74
  def initialize(level = Logger::INFO)
72
75
  @stdout = true
73
76
  @level = level
74
- @scope = nil
75
77
  @detail_string = nil
76
78
  @container_name = Socket.gethostname
77
79
  @microservice_name = nil
@@ -95,68 +97,53 @@ module OpenC3
95
97
  # below the method name log level.
96
98
  # @param block [Proc] Block to call which should return a string to append
97
99
  # to the log message
98
- def debug(message = nil, scope: @scope, user: nil, &block)
99
- log_message(DEBUG_SEVERITY_STRING, message, scope: scope, user: user, &block) if @level <= DEBUG
100
+ def debug(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
101
+ log_message(DEBUG_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= DEBUG
100
102
  end
101
103
 
102
104
  # (see #debug)
103
- def info(message = nil, scope: @scope, user: nil, &block)
104
- log_message(INFO_SEVERITY_STRING, message, scope: scope, user: user, &block) if @level <= INFO
105
+ def info(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
106
+ log_message(INFO_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= INFO
105
107
  end
106
108
 
107
109
  # (see #debug)
108
- def warn(message = nil, scope: @scope, user: nil, &block)
109
- log_message(WARN_SEVERITY_STRING, message, scope: scope, user: user, &block) if @level <= WARN
110
+ def warn(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
111
+ log_message(WARN_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= WARN
110
112
  end
111
113
 
112
114
  # (see #debug)
113
- def error(message = nil, scope: @scope, user: nil, &block)
114
- log_message(ERROR_SEVERITY_STRING, message, scope: scope, user: user, &block) if @level <= ERROR
115
+ def error(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
116
+ log_message(ERROR_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= ERROR
115
117
  end
116
118
 
117
119
  # (see #debug)
118
- def fatal(message = nil, scope: @scope, user: nil, &block)
119
- log_message(FATAL_SEVERITY_STRING, message, scope: scope, user: user, &block) if @level <= FATAL
120
+ def fatal(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
121
+ log_message(FATAL_SEVERITY_STRING, message, scope: scope, user: user, type: type, url: url, &block) if @level <= FATAL
120
122
  end
121
123
 
122
124
  # (see #debug)
123
- def self.debug(message = nil, scope: nil, user: nil, &block)
124
- args = {}
125
- args[:scope] = scope if scope
126
- args[:user] = user if user
127
- self.instance.debug(message, **args, &block)
125
+ def self.debug(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
126
+ self.instance.debug(message, scope: scope, user: user, type: type, url: url, &block)
128
127
  end
129
128
 
130
129
  # (see #debug)
131
- def self.info(message = nil, scope: nil, user: nil, &block)
132
- args = {}
133
- args[:scope] = scope if scope
134
- args[:user] = user if user
135
- self.instance.info(message, **args, &block)
130
+ def self.info(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
131
+ self.instance.info(message, scope: scope, user: user, type: type, url: url, &block)
136
132
  end
137
133
 
138
134
  # (see #debug)
139
- def self.warn(message = nil, scope: nil, user: nil, &block)
140
- args = {}
141
- args[:scope] = scope if scope
142
- args[:user] = user if user
143
- self.instance.warn(message, **args, &block)
135
+ def self.warn(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
136
+ self.instance.warn(message, scope: scope, user: user, type: type, url: url, &block)
144
137
  end
145
138
 
146
139
  # (see #debug)
147
- def self.error(message = nil, scope: nil, user: nil, &block)
148
- args = {}
149
- args[:scope] = scope if scope
150
- args[:user] = user if user
151
- self.instance.error(message, **args, &block)
140
+ def self.error(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
141
+ self.instance.error(message, scope: scope, user: user, type: type, url: url, &block)
152
142
  end
153
143
 
154
144
  # (see #debug)
155
- def self.fatal(message = nil, scope: nil, user: nil, &block)
156
- args = {}
157
- args[:scope] = scope if scope
158
- args[:user] = user if user
159
- self.instance.fatal(message, **args, &block)
145
+ def self.fatal(message = nil, scope: @@scope, user: nil, type: LOG, url: nil, &block)
146
+ self.instance.fatal(message, scope: scope, user: user, type: type, url: url, &block)
160
147
  end
161
148
 
162
149
  # @return [Logger] The logger instance
@@ -169,11 +156,28 @@ module OpenC3
169
156
  @@instance
170
157
  end
171
158
 
159
+ def self.scope
160
+ return @@scope
161
+ end
162
+
163
+ def self.scope=(scope)
164
+ @@scope = scope
165
+ end
166
+
167
+ def scope
168
+ return @@scope
169
+ end
170
+
171
+ def scope=(scope)
172
+ @@scope = scope
173
+ end
174
+
172
175
  protected
173
176
 
174
- def log_message(severity_string, message, scope:, user:)
177
+ def log_message(severity_string, message, scope:, user:, type:, url:)
175
178
  @@mutex.synchronize do
176
- data = { time: Time.now.to_nsec_from_epoch, '@timestamp' => Time.now.xmlschema(3), severity: severity_string }
179
+ time = Time.now
180
+ data = { time: time.to_nsec_from_epoch, '@timestamp' => time.xmlschema(3), severity: severity_string }
177
181
  data[:microservice_name] = @microservice_name if @microservice_name
178
182
  data[:detail] = @detail_string if @detail_string
179
183
  data[:user] = user['username'] || 'Unknown' if user # EE: If a user is passed, put its name ('Unknown' if it doesn't have a name). Don't include user data if no user was passed
@@ -182,17 +186,28 @@ module OpenC3
182
186
  end
183
187
  data[:container_name] = @container_name
184
188
  data[:log] = message
189
+ data[:type] = type
190
+ data[:url] = url if url
185
191
  if @stdout
186
- puts data.as_json(:allow_nan => true).to_json(:allow_nan => true)
187
- $stdout.flush
192
+ case severity_string
193
+ when WARN_SEVERITY_STRING, ERROR_SEVERITY_STRING, FATAL_SEVERITY_STRING
194
+ if ENV['OPENC3_LOG_STDERR']
195
+ $stderr.puts data.as_json(:allow_nan => true).to_json(:allow_nan => true)
196
+ $stderr.flush
197
+ else
198
+ $stdout.puts data.as_json(:allow_nan => true).to_json(:allow_nan => true)
199
+ $stdout.flush
200
+ end
201
+ else
202
+ $stdout.puts data.as_json(:allow_nan => true).to_json(:allow_nan => true)
203
+ $stdout.flush
204
+ end
188
205
  end
189
206
  unless @no_store
190
207
  if scope
191
208
  Topic.write_topic("#{scope}__openc3_log_messages", data)
192
209
  else
193
- # The base openc3_log_messages doesn't have an associated logger
194
- # so it must be limited to prevent unbounded stream growth
195
- Topic.write_topic("openc3_log_messages", data, '*', 1000)
210
+ Topic.write_topic("NOSCOPE__openc3_log_messages", data)
196
211
  end
197
212
  end
198
213
  end
@@ -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
@@ -38,6 +38,9 @@ module OpenC3
38
38
  # Sleeper used to delay update thread
39
39
  @@update_sleeper = nil
40
40
 
41
+ # Objects with a generate method to be called on each metric cycle (to generate metrics)
42
+ @@update_generators = []
43
+
41
44
  attr_reader :microservice
42
45
  attr_reader :scope
43
46
  attr_reader :data
@@ -83,7 +86,12 @@ module OpenC3
83
86
  @@update_sleeper = Sleeper.new
84
87
  while true
85
88
  start_time = Time.now
89
+
86
90
  @@mutex.synchronize do
91
+ @@update_generators.each do |generator|
92
+ generator.generate(@@instances[0])
93
+ end
94
+
87
95
  @@instances.each do |instance|
88
96
  instance.mutex.synchronize do
89
97
  json = {}
@@ -116,5 +124,15 @@ module OpenC3
116
124
 
117
125
  def graceful_kill
118
126
  end
127
+
128
+ def self.add_update_generator(object)
129
+ @@update_generators << object
130
+ end
119
131
  end
120
132
  end
133
+
134
+ begin
135
+ require 'openc3-enterprise/utilities/metric'
136
+ rescue LoadError
137
+ # Open Source Edition - Do nothing here
138
+ end
@@ -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
  module OpenC3
@@ -37,6 +37,7 @@ module OpenC3
37
37
  def sleep(seconds)
38
38
  read_ready, _ = IO.select(@readers, nil, nil, seconds)
39
39
  if read_ready && read_ready.include?(@pipe_reader)
40
+ @pipe_reader.close unless @pipe_reader.closed?
40
41
  return true
41
42
  else
42
43
  return false
@@ -48,6 +49,7 @@ module OpenC3
48
49
  if !@canceled
49
50
  @canceled = true
50
51
  @pipe_writer.write('.')
52
+ @pipe_writer.close
51
53
  end
52
54
  end
53
55
  end
@@ -0,0 +1,76 @@
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
+ # Usage:
20
+ # throttle = OpenC3::Throttle.new(50.0) # Use max 50% cpu for work
21
+ #
22
+ # throttle.reset # Necessary if there are large periods of idle between hard work
23
+ # 1000.times do
24
+ # throttle.start
25
+ # # Do one iteration of cpu itensive work here
26
+ # # complete will sleep if necessary to not use too much CPU
27
+ # throttle.complete
28
+ # end
29
+
30
+ module OpenC3
31
+ class Throttle
32
+ MIN_SLEEP_SECONDS = 0.001
33
+ MAX_SLEEP_SECONDS = 0.100
34
+
35
+ attr_reader :reset_time
36
+ attr_reader :total_sleep_time
37
+
38
+ # @param max_cpu_utilization [Float] 0.0-100.0
39
+ def initialize(max_cpu_utilization)
40
+ @max_cpu_utilization = Float(max_cpu_utilization)
41
+ raise ArgumentError "max_cpu_utilization must be between 0.0 and 100.0" if @max_cpu_utilization > 100.0 or @max_cpu_utilization < 0.0
42
+ @max_cpu_utilization /= 100.0 # Normalize
43
+ reset()
44
+ end
45
+
46
+ def reset
47
+ @reset_time = Time.now
48
+ @total_sleep_time = 0
49
+ end
50
+
51
+ def throttle_sleep
52
+ return if @max_cpu_utilization >= 1.0
53
+ total_time = Time.now - @reset_time
54
+ if total_time > 0
55
+ cpu_utilization = 1.0 - (@total_sleep_time / total_time)
56
+ if cpu_utilization > @max_cpu_utilization
57
+ # Need to throttle
58
+ # max_cpu_utilization = sleep_time + total_sleep_time
59
+ # ----------------------------
60
+ # total_time
61
+ #
62
+ # (max_cpu_utilization * total_time) = sleep_time + total_sleep_time
63
+ #
64
+ # sleep_time = (max_cpu_utilization * total_time) - total_sleep_time
65
+ #
66
+ sleep_time = (@max_cpu_utilization * total_time) - @total_sleep_time
67
+ if sleep_time > MIN_SLEEP_SECONDS
68
+ sleep_time = MAX_SLEEP_SECONDS if sleep_time > MAX_SLEEP_SECONDS
69
+ sleep(sleep_time)
70
+ @total_sleep_time += sleep_time
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,14 +1,14 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- OPENC3_VERSION = '5.10.1'
3
+ OPENC3_VERSION = '5.11.0'
4
4
  module OpenC3
5
5
  module Version
6
6
  MAJOR = '5'
7
- MINOR = '10'
8
- PATCH = '1'
7
+ MINOR = '11'
8
+ PATCH = '0'
9
9
  OTHER = ''
10
- BUILD = 'b248056bc6fa7af79757e21f3b79601118eec0e5'
10
+ BUILD = 'f994eee0c2fadfc67ffbf0865ba798ed11ec1f5c'
11
11
  end
12
- VERSION = '5.10.1'
13
- GEM_VERSION = '5.10.1'
12
+ VERSION = '5.11.0'
13
+ GEM_VERSION = '5.11.0'
14
14
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "<%= tool_name %>",
3
- "version": "5.10.1",
3
+ "version": "5.11.0",
4
4
  "scripts": {
5
5
  "ng": "ng",
6
6
  "start": "ng serve",
@@ -12,36 +12,36 @@
12
12
  },
13
13
  "private": true,
14
14
  "dependencies": {
15
- "@openc3/tool-common": "5.10.1",
16
- "@angular/animations": "^16.2.0",
17
- "@angular/cdk": "^16.2.0",
18
- "@angular/common": "^16.2.0",
19
- "@angular/compiler": "^16.2.0",
20
- "@angular/core": "^16.2.0",
21
- "@angular/forms": "^16.2.0",
22
- "@angular/material": "16.2.0",
23
- "@angular/platform-browser": "^16.2.0",
24
- "@angular/platform-browser-dynamic": "^16.2.0",
25
- "@angular/router": "^16.2.0",
15
+ "@openc3/tool-common": "5.11.0",
16
+ "@angular/animations": "^16.2.4",
17
+ "@angular/cdk": "^16.2.3",
18
+ "@angular/common": "^16.2.4",
19
+ "@angular/compiler": "^16.2.4",
20
+ "@angular/core": "^16.2.4",
21
+ "@angular/forms": "^16.2.4",
22
+ "@angular/material": "16.2.3",
23
+ "@angular/platform-browser": "^16.2.4",
24
+ "@angular/platform-browser-dynamic": "^16.2.4",
25
+ "@angular/router": "^16.2.4",
26
26
  "rxjs": "~7.8.0",
27
27
  "single-spa": ">=5.9.5",
28
28
  "single-spa-angular": "^8.1.0",
29
- "tslib": "^2.6.1",
30
- "zone.js": "~0.13.1"
29
+ "tslib": "^2.6.2",
30
+ "zone.js": "~0.13.3"
31
31
  },
32
32
  "devDependencies": {
33
- "@angular-builders/custom-webpack": "16.0.0",
34
- "@angular-devkit/build-angular": "^16.2.0",
35
- "@angular/cli": "~16.2.0",
36
- "@angular/compiler-cli": "^16.2.0",
33
+ "@angular-builders/custom-webpack": "16.0.1",
34
+ "@angular-devkit/build-angular": "^16.2.1",
35
+ "@angular/cli": "~16.2.1",
36
+ "@angular/compiler-cli": "^16.2.4",
37
37
  "@types/jasmine": "~4.3.0",
38
- "jasmine-core": "~5.1.0",
38
+ "jasmine-core": "~5.1.1",
39
39
  "karma": "~6.4.0",
40
40
  "karma-chrome-launcher": "~3.2.0",
41
41
  "karma-coverage": "~2.2.0",
42
42
  "karma-jasmine": "~5.1.0",
43
43
  "karma-jasmine-html-reporter": "~2.1.0",
44
44
  "style-loader": "^3.3.1",
45
- "typescript": "~5.1.6"
45
+ "typescript": "~5.2.2"
46
46
  }
47
47
  }