openc3 5.10.1 → 5.11.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.
- checksums.yaml +4 -4
- data/Rakefile +3 -2
- data/data/config/target.yaml +9 -0
- data/ext/openc3/ext/packet/packet.c +3 -0
- data/ext/openc3/ext/reducer_microservice/extconf.rb +13 -0
- data/ext/openc3/ext/reducer_microservice/reducer_microservice.c +165 -0
- data/ext/openc3/ext/structure/structure.c +7 -9
- data/lib/openc3/accessors/accessor.rb +53 -3
- data/lib/openc3/accessors/binary_accessor.rb +16 -0
- data/lib/openc3/accessors/cbor_accessor.rb +3 -3
- data/lib/openc3/accessors/form_accessor.rb +78 -0
- data/lib/openc3/accessors/http_accessor.rb +145 -0
- data/lib/openc3/accessors/json_accessor.rb +19 -3
- data/lib/openc3/accessors/xml_accessor.rb +18 -1
- data/lib/openc3/accessors.rb +3 -1
- data/lib/openc3/config/config_parser.rb +7 -5
- data/lib/openc3/config/meta_config_parser.rb +1 -1
- data/lib/openc3/core_ext/string.rb +16 -1
- data/lib/openc3/interfaces/http_client_interface.rb +202 -0
- data/lib/openc3/interfaces/http_server_interface.rb +183 -0
- data/lib/openc3/interfaces/interface.rb +86 -16
- data/lib/openc3/interfaces/mqtt_interface.rb +6 -5
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +11 -11
- data/lib/openc3/interfaces/protocols/cobs_protocol.rb +7 -7
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +7 -7
- data/lib/openc3/interfaces/protocols/length_protocol.rb +6 -6
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +9 -5
- data/lib/openc3/interfaces/protocols/protocol.rb +8 -6
- data/lib/openc3/interfaces/protocols/slip_protocol.rb +8 -8
- data/lib/openc3/interfaces/protocols/template_protocol.rb +6 -7
- data/lib/openc3/interfaces/protocols/terminated_protocol.rb +4 -4
- data/lib/openc3/interfaces/simulated_target_interface.rb +2 -0
- data/lib/openc3/interfaces/stream_interface.rb +6 -4
- data/lib/openc3/interfaces/tcpip_server_interface.rb +2 -0
- data/lib/openc3/interfaces/udp_interface.rb +8 -5
- data/lib/openc3/interfaces.rb +2 -0
- data/lib/openc3/logs/buffered_packet_log_writer.rb +6 -7
- data/lib/openc3/logs/log_writer.rb +2 -10
- data/lib/openc3/logs/packet_log_constants.rb +13 -3
- data/lib/openc3/logs/packet_log_reader.rb +35 -98
- data/lib/openc3/logs/packet_log_writer.rb +24 -62
- data/lib/openc3/logs/text_log_writer.rb +32 -6
- data/lib/openc3/microservices/cleanup_microservice.rb +23 -16
- data/lib/openc3/microservices/decom_microservice.rb +8 -20
- data/lib/openc3/microservices/log_microservice.rb +3 -1
- data/lib/openc3/microservices/reaction_microservice.rb +22 -11
- data/lib/openc3/microservices/reducer_microservice.rb +174 -130
- data/lib/openc3/{models/notification_model.rb → microservices/scope_cleanup_microservice.rb} +20 -21
- data/lib/openc3/microservices/text_log_microservice.rb +2 -5
- data/lib/openc3/microservices/timeline_microservice.rb +0 -1
- data/lib/openc3/microservices/trigger_group_microservice.rb +0 -1
- data/lib/openc3/migrations/20230915000002_no_scope_log_messages.rb +44 -0
- data/lib/openc3/models/microservice_model.rb +1 -1
- data/lib/openc3/models/scope_model.rb +65 -34
- data/lib/openc3/models/target_model.rb +25 -5
- data/lib/openc3/models/tool_model.rb +14 -2
- data/lib/openc3/models/widget_model.rb +1 -1
- data/lib/openc3/packets/json_packet.rb +10 -2
- data/lib/openc3/packets/packet.rb +30 -9
- data/lib/openc3/packets/packet_config.rb +6 -2
- data/lib/openc3/packets/parsers/packet_item_parser.rb +11 -6
- data/lib/openc3/packets/structure.rb +19 -12
- data/lib/openc3/script/storage.rb +1 -1
- data/lib/openc3/script/web_socket_api.rb +17 -14
- data/lib/openc3/topics/telemetry_topic.rb +2 -1
- data/lib/openc3/utilities/bucket_utilities.rb +2 -0
- data/lib/openc3/utilities/cli_generator.rb +1 -1
- data/lib/openc3/utilities/logger.rb +62 -47
- data/lib/openc3/utilities/metric.rb +19 -1
- data/lib/openc3/utilities/sleeper.rb +3 -1
- data/lib/openc3/utilities/throttle.rb +76 -0
- data/lib/openc3/version.rb +6 -6
- data/templates/tool_angular/package.json +20 -20
- data/templates/tool_angular/yarn.lock +112 -106
- data/templates/tool_react/package.json +16 -18
- data/templates/tool_react/yarn.lock +977 -664
- data/templates/tool_svelte/.prettierrc.js +5 -0
- data/templates/tool_svelte/package.json +18 -18
- data/templates/tool_svelte/src/services/cable.js +1 -1
- data/templates/tool_svelte/src/services/openc3-api.js +173 -173
- data/templates/tool_svelte/yarn.lock +767 -665
- data/templates/tool_vue/package.json +10 -10
- data/templates/tool_vue/yarn.lock +225 -43
- data/templates/widget/package.json +10 -10
- data/templates/widget/yarn.lock +223 -46
- metadata +41 -4
- data/lib/openc3/topics/notifications_topic.rb +0 -31
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'openc3/utilities/migration'
|
|
2
|
+
require 'openc3/models/microservice_model'
|
|
3
|
+
|
|
4
|
+
module OpenC3
|
|
5
|
+
class NoScopeLogMessages < Migration
|
|
6
|
+
def self.run
|
|
7
|
+
# Add NOSCOPE topic to log message microservice for DEFAULT scope
|
|
8
|
+
model = MicroserviceModel.get_model(name: "DEFAULT__OPENC3__LOG", scope: 'DEFAULT')
|
|
9
|
+
if model
|
|
10
|
+
model.topics = ["DEFAULT__openc3_log_messages", "NOSCOPE__openc3_log_messages"]
|
|
11
|
+
model.update
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
ScopeModel.get_all_models(scope: nil).each do |scope, scope_model|
|
|
15
|
+
parent = "#{scope}__SCOPEMULTI__#{scope}"
|
|
16
|
+
|
|
17
|
+
# Remove NOTIFICATION log microservice from scopes
|
|
18
|
+
model = MicroserviceModel.get_model(name: "#{scope}__NOTIFICATION__LOG", scope: scope)
|
|
19
|
+
if model
|
|
20
|
+
model.destroy
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Add Scope Cleanup microservice to scopes
|
|
24
|
+
model = MicroserviceModel.get_model(name: "#{scope}__SCOPECLEANUP__#{scope}", scope: scope)
|
|
25
|
+
unless model
|
|
26
|
+
scope_model.deploy_scopecleanup_microservice("", {}, parent)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
model = MicroserviceModel.get_model(name: parent, scope: scope)
|
|
30
|
+
if model
|
|
31
|
+
model.cmd.delete("#{scope}__NOTIFICATION__LOG")
|
|
32
|
+
unless model.cmd.include?("#{scope}__SCOPECLEANUP__#{scope}")
|
|
33
|
+
model.cmd << "#{scope}__SCOPECLEANUP__#{scope}"
|
|
34
|
+
end
|
|
35
|
+
model.update
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
unless ENV['OPENC3_NO_MIGRATE']
|
|
43
|
+
OpenC3::NoScopeLogMessages.run
|
|
44
|
+
end
|
|
@@ -221,7 +221,7 @@ module OpenC3
|
|
|
221
221
|
# Load microservice files
|
|
222
222
|
data = File.read(filename, mode: "rb")
|
|
223
223
|
OpenC3.set_working_dir(File.dirname(filename)) do
|
|
224
|
-
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
|
|
224
|
+
data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable? and File.basename(filename)[0] != '_'
|
|
225
225
|
end
|
|
226
226
|
unless validate_only
|
|
227
227
|
@bucket.put_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: key, body: data)
|
|
@@ -32,6 +32,11 @@ module OpenC3
|
|
|
32
32
|
PRIMARY_KEY = 'openc3_scopes'
|
|
33
33
|
|
|
34
34
|
attr_accessor :children
|
|
35
|
+
attr_accessor :text_log_cycle_time
|
|
36
|
+
attr_accessor :text_log_cycle_size
|
|
37
|
+
attr_accessor :text_log_retain_time
|
|
38
|
+
attr_accessor :tool_log_retain_time
|
|
39
|
+
attr_accessor :cleanup_poll_time
|
|
35
40
|
|
|
36
41
|
# NOTE: The following three class methods are used by the ModelController
|
|
37
42
|
# and are reimplemented to enable various Model class methods to work
|
|
@@ -62,8 +67,31 @@ module OpenC3
|
|
|
62
67
|
end
|
|
63
68
|
end
|
|
64
69
|
|
|
65
|
-
def initialize(name:,
|
|
66
|
-
|
|
70
|
+
def initialize(name:,
|
|
71
|
+
text_log_cycle_time: 600,
|
|
72
|
+
text_log_cycle_size: 50_000_000,
|
|
73
|
+
text_log_retain_time: nil,
|
|
74
|
+
tool_log_retain_time: nil,
|
|
75
|
+
cleanup_poll_time: 900,
|
|
76
|
+
updated_at: nil,
|
|
77
|
+
scope: nil
|
|
78
|
+
)
|
|
79
|
+
super(
|
|
80
|
+
PRIMARY_KEY,
|
|
81
|
+
name: name,
|
|
82
|
+
text_log_cycle_time: text_log_cycle_time,
|
|
83
|
+
text_log_cycle_size: text_log_cycle_size,
|
|
84
|
+
text_log_retain_time: text_log_retain_time,
|
|
85
|
+
tool_log_retain_time: tool_log_retain_time,
|
|
86
|
+
cleanup_poll_time: cleanup_poll_time,
|
|
87
|
+
updated_at: updated_at,
|
|
88
|
+
scope: name
|
|
89
|
+
)
|
|
90
|
+
@text_log_cycle_time = text_log_cycle_time
|
|
91
|
+
@text_log_cycle_size = text_log_cycle_size
|
|
92
|
+
@text_log_retain_time = text_log_retain_time
|
|
93
|
+
@tool_log_retain_time = tool_log_retain_time
|
|
94
|
+
@cleanup_poll_time = cleanup_poll_time
|
|
67
95
|
@children = []
|
|
68
96
|
end
|
|
69
97
|
|
|
@@ -89,41 +117,31 @@ module OpenC3
|
|
|
89
117
|
|
|
90
118
|
def as_json(*a)
|
|
91
119
|
{ 'name' => @name,
|
|
92
|
-
'updated_at' => @updated_at
|
|
120
|
+
'updated_at' => @updated_at,
|
|
121
|
+
'text_log_cycle_time' => @text_log_cycle_time,
|
|
122
|
+
'text_log_cycle_size' => @text_log_cycle_size,
|
|
123
|
+
'text_log_retain_time' => @text_log_retain_time,
|
|
124
|
+
'tool_log_retain_time' => @tool_log_retain_time,
|
|
125
|
+
'cleanup_poll_time' => @cleanup_poll_time,
|
|
126
|
+
}
|
|
93
127
|
end
|
|
94
128
|
|
|
95
129
|
def deploy_openc3_log_messages_microservice(gem_path, variables, parent)
|
|
96
130
|
microservice_name = "#{@scope}__OPENC3__LOG"
|
|
131
|
+
topics = ["#{@scope}__openc3_log_messages"]
|
|
132
|
+
# Also log the NOSCOPE messages with this microservice for the DEFAULT scope
|
|
133
|
+
if @scope == 'DEFAULT'
|
|
134
|
+
topics << "NOSCOPE__openc3_log_messages"
|
|
135
|
+
end
|
|
97
136
|
microservice = MicroserviceModel.new(
|
|
98
137
|
name: microservice_name,
|
|
99
138
|
cmd: ["ruby", "text_log_microservice.rb", microservice_name],
|
|
100
139
|
work_dir: '/openc3/lib/openc3/microservices',
|
|
101
140
|
options: [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
# ["CYCLE_SIZE", "50_000_000"] # Keep at most ~50MB per log
|
|
105
|
-
],
|
|
106
|
-
topics: ["#{@scope}__openc3_log_messages"],
|
|
107
|
-
parent: parent,
|
|
108
|
-
scope: @scope
|
|
109
|
-
)
|
|
110
|
-
microservice.create
|
|
111
|
-
microservice.deploy(gem_path, variables)
|
|
112
|
-
@children << microservice_name if parent
|
|
113
|
-
Logger.info "Configured microservice #{microservice_name}"
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def deploy_openc3_notifications_microservice(gem_path, variables, parent)
|
|
117
|
-
microservice_name = "#{@scope}__NOTIFICATION__LOG"
|
|
118
|
-
microservice = MicroserviceModel.new(
|
|
119
|
-
name: microservice_name,
|
|
120
|
-
cmd: ["ruby", "text_log_microservice.rb", microservice_name],
|
|
121
|
-
work_dir: '/openc3/lib/openc3/microservices',
|
|
122
|
-
options: [
|
|
123
|
-
# The following options are optional (600 and 50_000_000 are the defaults)
|
|
124
|
-
["CYCLE_TIME", "3600"], # Keep at most 1 hour per log
|
|
141
|
+
["CYCLE_TIME", @text_log_cycle_time],
|
|
142
|
+
["CYCLE_SIZE", @text_log_cycle_size],
|
|
125
143
|
],
|
|
126
|
-
topics:
|
|
144
|
+
topics: topics,
|
|
127
145
|
parent: parent,
|
|
128
146
|
scope: @scope
|
|
129
147
|
)
|
|
@@ -192,6 +210,21 @@ module OpenC3
|
|
|
192
210
|
Logger.info "Configured microservice #{microservice_name}"
|
|
193
211
|
end
|
|
194
212
|
|
|
213
|
+
def deploy_scopecleanup_microservice(gem_path, variables, parent)
|
|
214
|
+
microservice_name = "#{@scope}__SCOPECLEANUP__#{@scope}"
|
|
215
|
+
microservice = MicroserviceModel.new(
|
|
216
|
+
name: microservice_name,
|
|
217
|
+
cmd: ["ruby", "scope_cleanup_microservice.rb", microservice_name],
|
|
218
|
+
work_dir: '/openc3/lib/openc3/microservices',
|
|
219
|
+
parent: parent,
|
|
220
|
+
scope: @scope
|
|
221
|
+
)
|
|
222
|
+
microservice.create
|
|
223
|
+
microservice.deploy(gem_path, variables)
|
|
224
|
+
@children << microservice_name if parent
|
|
225
|
+
Logger.info "Configured microservice #{microservice_name}"
|
|
226
|
+
end
|
|
227
|
+
|
|
195
228
|
def deploy_scopemulti_microservice(gem_path, variables)
|
|
196
229
|
microservice_name = "#{@scope}__SCOPEMULTI__#{@scope}"
|
|
197
230
|
microservice = MicroserviceModel.new(
|
|
@@ -220,17 +253,12 @@ module OpenC3
|
|
|
220
253
|
# Create UNKNOWN target for display of unknown data
|
|
221
254
|
model = TargetModel.new(name: "UNKNOWN", scope: @scope)
|
|
222
255
|
model.create
|
|
223
|
-
# Not deployed - we only want raw packet logging for UNKNOWN
|
|
224
|
-
# TODO: Cleanup support
|
|
225
256
|
|
|
226
257
|
@parent = "#{@scope}__SCOPEMULTI__#{@scope}"
|
|
227
258
|
|
|
228
259
|
# OpenC3 Log Microservice
|
|
229
260
|
deploy_openc3_log_messages_microservice(gem_path, variables, @parent)
|
|
230
261
|
|
|
231
|
-
# Notification Log Microservice
|
|
232
|
-
deploy_openc3_notifications_microservice(gem_path, variables, @parent)
|
|
233
|
-
|
|
234
262
|
# UNKNOWN CommandLog Microservice
|
|
235
263
|
deploy_unknown_commandlog_microservice(gem_path, variables, @parent)
|
|
236
264
|
|
|
@@ -240,6 +268,9 @@ module OpenC3
|
|
|
240
268
|
# Periodic Microservice
|
|
241
269
|
deploy_periodic_microservice(gem_path, variables, @parent)
|
|
242
270
|
|
|
271
|
+
# Scope Cleanup Microservice
|
|
272
|
+
deploy_scopecleanup_microservice(gem_path, variables, @parent)
|
|
273
|
+
|
|
243
274
|
# Multi Microservice to parent other scope microservices
|
|
244
275
|
deploy_scopemulti_microservice(gem_path, variables)
|
|
245
276
|
end
|
|
@@ -247,9 +278,9 @@ module OpenC3
|
|
|
247
278
|
def undeploy
|
|
248
279
|
model = MicroserviceModel.get_model(name: "#{@scope}__SCOPEMULTI__#{@scope}", scope: @scope)
|
|
249
280
|
model.destroy if model
|
|
250
|
-
model = MicroserviceModel.get_model(name: "#{@scope}
|
|
281
|
+
model = MicroserviceModel.get_model(name: "#{@scope}__SCOPECLEANUP__#{@scope}", scope: @scope)
|
|
251
282
|
model.destroy if model
|
|
252
|
-
model = MicroserviceModel.get_model(name: "#{@scope}
|
|
283
|
+
model = MicroserviceModel.get_model(name: "#{@scope}__OPENC3__LOG", scope: @scope)
|
|
253
284
|
model.destroy if model
|
|
254
285
|
model = MicroserviceModel.get_model(name: "#{@scope}__COMMANDLOG__UNKNOWN", scope: @scope)
|
|
255
286
|
model.destroy if model
|
|
@@ -44,6 +44,7 @@ module OpenC3
|
|
|
44
44
|
class TargetModel < Model
|
|
45
45
|
PRIMARY_KEY = 'openc3_targets'
|
|
46
46
|
VALID_TYPES = %i(CMD TLM)
|
|
47
|
+
ERB_EXTENSIONS = %w(.txt .rb .py .json .yaml .yml)
|
|
47
48
|
ITEM_MAP_CACHE_TIMEOUT = 10.0
|
|
48
49
|
@@item_map_cache = {}
|
|
49
50
|
|
|
@@ -346,6 +347,8 @@ module OpenC3
|
|
|
346
347
|
cleanup_poll_time: 900,
|
|
347
348
|
needs_dependencies: false,
|
|
348
349
|
target_microservices: {'REDUCER' => [[]]},
|
|
350
|
+
reducer_disable: false,
|
|
351
|
+
reducer_max_cpu_utilization: 30.0,
|
|
349
352
|
scope:
|
|
350
353
|
)
|
|
351
354
|
super("#{scope}__#{PRIMARY_KEY}", name: name, plugin: plugin, updated_at: updated_at,
|
|
@@ -360,6 +363,7 @@ module OpenC3
|
|
|
360
363
|
reduced_minute_log_retain_time: reduced_minute_log_retain_time,
|
|
361
364
|
reduced_hour_log_retain_time: reduced_hour_log_retain_time, reduced_day_log_retain_time: reduced_day_log_retain_time,
|
|
362
365
|
cleanup_poll_time: cleanup_poll_time, needs_dependencies: needs_dependencies, target_microservices: target_microservices,
|
|
366
|
+
reducer_disable: reducer_disable, reducer_max_cpu_utilization: reducer_max_cpu_utilization,
|
|
363
367
|
scope: scope)
|
|
364
368
|
@folder_name = folder_name
|
|
365
369
|
@requires = requires
|
|
@@ -390,6 +394,8 @@ module OpenC3
|
|
|
390
394
|
@cleanup_poll_time = cleanup_poll_time
|
|
391
395
|
@needs_dependencies = needs_dependencies
|
|
392
396
|
@target_microservices = target_microservices
|
|
397
|
+
@reducer_disable = reducer_disable
|
|
398
|
+
@reducer_max_cpu_utilization = reducer_max_cpu_utilization
|
|
393
399
|
@bucket = Bucket.getClient()
|
|
394
400
|
@children = []
|
|
395
401
|
end
|
|
@@ -427,7 +433,9 @@ module OpenC3
|
|
|
427
433
|
'reduced_day_log_retain_time' => @reduced_day_log_retain_time,
|
|
428
434
|
'cleanup_poll_time' => @cleanup_poll_time,
|
|
429
435
|
'needs_dependencies' => @needs_dependencies,
|
|
430
|
-
'target_microservices' => @target_microservices.as_json(:allow_nan => true)
|
|
436
|
+
'target_microservices' => @target_microservices.as_json(:allow_nan => true),
|
|
437
|
+
'reducer_disable' => @reducer_disable,
|
|
438
|
+
'reducer_max_cpu_utilization' => @reducer_max_cpu_utilization
|
|
431
439
|
}
|
|
432
440
|
end
|
|
433
441
|
|
|
@@ -509,6 +517,11 @@ module OpenC3
|
|
|
509
517
|
@reduced_hour_log_retain_time = reduced_log_retain_time.to_i
|
|
510
518
|
@reduced_day_log_retain_time = reduced_log_retain_time.to_i
|
|
511
519
|
end
|
|
520
|
+
when 'REDUCER_DISABLE', 'REDUCER_DISABLED' # Handle typos
|
|
521
|
+
@reducer_disable = true
|
|
522
|
+
when 'REDUCER_MAX_CPU_UTILIZATION', 'REDUCED_MAX_CPU_UTILIZATION' # Handle typos
|
|
523
|
+
parser.verify_num_parameters(1, 1, "#{keyword} <Max cpu utilization to allocate to the reducer microservice - 0.0 to 100.0>")
|
|
524
|
+
@reducer_max_cpu_utilization = Float(parameters[0])
|
|
512
525
|
when 'CLEANUP_POLL_TIME'
|
|
513
526
|
parser.verify_num_parameters(1, 1, "#{keyword} <Cleanup polling period in seconds>")
|
|
514
527
|
@cleanup_poll_time = parameters[0].to_i
|
|
@@ -556,7 +569,9 @@ module OpenC3
|
|
|
556
569
|
data = File.read(filename, mode: "rb")
|
|
557
570
|
begin
|
|
558
571
|
OpenC3.set_working_dir(File.dirname(filename)) do
|
|
559
|
-
|
|
572
|
+
if ERB_EXTENSIONS.include?(File.extname(filename).downcase) and File.basename(filename)[0] != '_'
|
|
573
|
+
data = ERB.new(data.force_encoding("UTF-8").comment_erb(), trim_mode: "-").result(binding.set_variables(variables))
|
|
574
|
+
end
|
|
560
575
|
end
|
|
561
576
|
rescue => error
|
|
562
577
|
# ERB error parsing a screen is just a logger error because life can go on
|
|
@@ -666,7 +681,7 @@ module OpenC3
|
|
|
666
681
|
|
|
667
682
|
begin
|
|
668
683
|
OpenC3.set_working_dir(File.dirname(path)) do
|
|
669
|
-
return ERB.new(File.read(path), trim_mode: "-").result(b)
|
|
684
|
+
return ERB.new(File.read(path).force_encoding("UTF-8").comment_erb(), trim_mode: "-").result(b)
|
|
670
685
|
end
|
|
671
686
|
rescue => error
|
|
672
687
|
raise "ERB error parsing: #{path}: #{error.formatted}"
|
|
@@ -909,6 +924,9 @@ module OpenC3
|
|
|
909
924
|
folder_name: @folder_name,
|
|
910
925
|
cmd: ["ruby", "reducer_microservice.rb", microservice_name],
|
|
911
926
|
work_dir: '/openc3/lib/openc3/microservices',
|
|
927
|
+
options: [
|
|
928
|
+
["MAX_CPU_UTILIZATION", @reducer_max_cpu_utilization],
|
|
929
|
+
],
|
|
912
930
|
topics: topics,
|
|
913
931
|
plugin: @plugin,
|
|
914
932
|
parent: parent,
|
|
@@ -1053,8 +1071,10 @@ module OpenC3
|
|
|
1053
1071
|
end
|
|
1054
1072
|
|
|
1055
1073
|
# Reducer Microservice
|
|
1056
|
-
|
|
1057
|
-
|
|
1074
|
+
unless @reducer_disable
|
|
1075
|
+
deploy_target_microservices('REDUCER', decom_topic_list, "#{@scope}__DECOM__{#{@name}}") do |topics, instance, parent|
|
|
1076
|
+
deploy_reducer_microservice(gem_path, variables, topics, instance, parent)
|
|
1077
|
+
end
|
|
1058
1078
|
end
|
|
1059
1079
|
end
|
|
1060
1080
|
|
|
@@ -155,8 +155,19 @@ module OpenC3
|
|
|
155
155
|
end
|
|
156
156
|
|
|
157
157
|
def create(update: false, force: false)
|
|
158
|
+
tools = self.class.all(scope: @scope)
|
|
159
|
+
|
|
160
|
+
# Make sure a tool with this folder_name doesn't already exist
|
|
161
|
+
unless update
|
|
162
|
+
tools.each do |_tool_name, tool|
|
|
163
|
+
if tool['folder_name'] == @folder_name
|
|
164
|
+
raise "Tool with folder_name #{@folder_name} already exists at create"
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Autoset tool position
|
|
158
170
|
unless @position
|
|
159
|
-
tools = self.class.all(scope: @scope)
|
|
160
171
|
_, tool = tools.max_by { |_tool_name, tool| tool['position'] }
|
|
161
172
|
if tool
|
|
162
173
|
@position = tool['position'] + 1
|
|
@@ -164,6 +175,7 @@ module OpenC3
|
|
|
164
175
|
@position = 0
|
|
165
176
|
end
|
|
166
177
|
end
|
|
178
|
+
|
|
167
179
|
super(update: update, force: force)
|
|
168
180
|
end
|
|
169
181
|
|
|
@@ -228,7 +240,7 @@ module OpenC3
|
|
|
228
240
|
|
|
229
241
|
# Load tool files
|
|
230
242
|
data = File.read(filename, mode: "rb")
|
|
231
|
-
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
|
243
|
+
data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
|
232
244
|
unless validate_only
|
|
233
245
|
client = Bucket.getClient()
|
|
234
246
|
cache_control = BucketUtilities.get_cache_control(filename)
|
|
@@ -124,7 +124,7 @@ module OpenC3
|
|
|
124
124
|
# Load widget file
|
|
125
125
|
data = File.read(filename, mode: "rb")
|
|
126
126
|
OpenC3.set_working_dir(File.dirname(filename)) do
|
|
127
|
-
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
|
127
|
+
data = ERB.new(data.comment_erb(), trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
|
128
128
|
end
|
|
129
129
|
unless validate_only
|
|
130
130
|
cache_control = BucketUtilities.get_cache_control(@filename)
|
|
@@ -32,13 +32,21 @@ module OpenC3
|
|
|
32
32
|
attr_accessor :packet_time
|
|
33
33
|
attr_accessor :stored
|
|
34
34
|
attr_accessor :json_hash
|
|
35
|
+
attr_accessor :received_time
|
|
36
|
+
attr_accessor :extra
|
|
35
37
|
|
|
36
|
-
def initialize(cmd_or_tlm, target_name, packet_name,
|
|
38
|
+
def initialize(cmd_or_tlm, target_name, packet_name, time_nsec_since_epoch, stored, json_data, key_map = nil, received_time_nsec_since_epoch: nil, extra: nil)
|
|
37
39
|
@cmd_or_tlm = cmd_or_tlm.intern
|
|
38
40
|
@target_name = target_name
|
|
39
41
|
@packet_name = packet_name
|
|
40
|
-
@packet_time = ::Time.from_nsec_from_epoch(
|
|
42
|
+
@packet_time = ::Time.from_nsec_from_epoch(time_nsec_since_epoch)
|
|
41
43
|
@stored = ConfigParser.handle_true_false(stored)
|
|
44
|
+
if received_time_nsec_since_epoch
|
|
45
|
+
@received_time = ::Time.from_nsec_from_epoch(received_time_nsec_since_epoch)
|
|
46
|
+
else
|
|
47
|
+
@received_time = @packet_time
|
|
48
|
+
end
|
|
49
|
+
@extra = extra
|
|
42
50
|
@json_hash = json_data
|
|
43
51
|
@json_hash = JSON.parse(json_data, :allow_nan => true, :create_additions => true) if String === json_data
|
|
44
52
|
if key_map
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# GNU Affero General Public License for more details.
|
|
15
15
|
|
|
16
16
|
# Modified by OpenC3, Inc.
|
|
17
|
-
# All changes Copyright
|
|
17
|
+
# All changes Copyright 2023, OpenC3, Inc.
|
|
18
18
|
# All Rights Reserved
|
|
19
19
|
#
|
|
20
20
|
# This file may also be used under the terms of a commercial license
|
|
@@ -127,6 +127,7 @@ module OpenC3
|
|
|
127
127
|
@extra = nil
|
|
128
128
|
@cmd_or_tlm = nil
|
|
129
129
|
@template = nil
|
|
130
|
+
@packet_time = nil
|
|
130
131
|
end
|
|
131
132
|
|
|
132
133
|
# Sets the target name this packet is associated with. Unidentified packets
|
|
@@ -267,10 +268,18 @@ module OpenC3
|
|
|
267
268
|
if item
|
|
268
269
|
return read_item(item, :CONVERTED, @buffer)
|
|
269
270
|
else
|
|
270
|
-
|
|
271
|
+
if @packet_time
|
|
272
|
+
return @packet_time
|
|
273
|
+
else
|
|
274
|
+
return @received_time
|
|
275
|
+
end
|
|
271
276
|
end
|
|
272
277
|
end
|
|
273
278
|
|
|
279
|
+
def packet_time=(time)
|
|
280
|
+
@packet_time = time
|
|
281
|
+
end
|
|
282
|
+
|
|
274
283
|
# Calculates a unique hashing sum that changes if the parts of the packet configuration change that could affect
|
|
275
284
|
# the "shape" of the packet. This value is cached and that packet should not be changed if this method is being used
|
|
276
285
|
def config_name
|
|
@@ -294,9 +303,7 @@ module OpenC3
|
|
|
294
303
|
begin
|
|
295
304
|
internal_buffer_equals(buffer)
|
|
296
305
|
rescue RuntimeError
|
|
297
|
-
|
|
298
|
-
Logger.instance.error "#{@target_name} #{@packet_name} received with actual packet length of #{buffer.length} but defined length of #{@defined_length}"
|
|
299
|
-
end
|
|
306
|
+
Logger.instance.error "#{@target_name} #{@packet_name} received with actual packet length of #{buffer.length} but defined length of #{@defined_length}"
|
|
300
307
|
end
|
|
301
308
|
@read_conversion_cache.clear if @read_conversion_cache
|
|
302
309
|
process()
|
|
@@ -709,10 +716,10 @@ module OpenC3
|
|
|
709
716
|
if item.write_conversion
|
|
710
717
|
value = item.write_conversion.call(value, self, buffer)
|
|
711
718
|
else
|
|
712
|
-
raise "Cannot write DERIVED item #{item.name} without a write conversion" if item.data_type == :DERIVED
|
|
719
|
+
raise "Cannot write DERIVED item #{item.name} without a write conversion" if item.data_type == :DERIVED and @accessor.enforce_derived_write_conversion(item)
|
|
713
720
|
end
|
|
714
721
|
begin
|
|
715
|
-
super(item, value, :RAW, buffer)
|
|
722
|
+
super(item, value, :RAW, buffer)
|
|
716
723
|
rescue ArgumentError => err
|
|
717
724
|
if item.states and String === value and err.message =~ /invalid value for/
|
|
718
725
|
raise "Unknown state #{value} for #{item.name}"
|
|
@@ -1051,7 +1058,8 @@ module OpenC3
|
|
|
1051
1058
|
config['messages_disabled'] = true if @messages_disabled
|
|
1052
1059
|
config['disabled'] = true if @disabled
|
|
1053
1060
|
config['hidden'] = true if @hidden
|
|
1054
|
-
config['accessor'] = @accessor.to_s
|
|
1061
|
+
config['accessor'] = @accessor.class.to_s
|
|
1062
|
+
config['accessor_args'] = @accessor.args
|
|
1055
1063
|
config['template'] = Base64.encode64(@template) if @template
|
|
1056
1064
|
|
|
1057
1065
|
if @processors
|
|
@@ -1092,7 +1100,12 @@ module OpenC3
|
|
|
1092
1100
|
packet.hidden = hash['hidden']
|
|
1093
1101
|
if hash['accessor']
|
|
1094
1102
|
begin
|
|
1095
|
-
|
|
1103
|
+
accessor = OpenC3::const_get(hash['accessor'])
|
|
1104
|
+
if hash['accessor_args'] and hash['accessor_args'].length > 0
|
|
1105
|
+
packet.accessor = accessor.new(packet, *hash['accessor_args'])
|
|
1106
|
+
else
|
|
1107
|
+
packet.accessor = accessor.new(packet)
|
|
1108
|
+
end
|
|
1096
1109
|
rescue => error
|
|
1097
1110
|
Logger.instance.error "#{packet.target_name} #{packet.packet_name} accessor of #{hash['accessor']} could not be found due to #{error}"
|
|
1098
1111
|
end
|
|
@@ -1110,6 +1123,13 @@ module OpenC3
|
|
|
1110
1123
|
# Read all the RAW at once because this could be optimized by the accessor
|
|
1111
1124
|
json_hash = read_items(@sorted_items)
|
|
1112
1125
|
|
|
1126
|
+
# Decom extra into the values (all raw)
|
|
1127
|
+
if @extra
|
|
1128
|
+
@extra.each do |key, value|
|
|
1129
|
+
json_hash[key.upcase] = value
|
|
1130
|
+
end
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1113
1133
|
# Now read all other value types - no accessor required
|
|
1114
1134
|
@sorted_items.each do |item|
|
|
1115
1135
|
given_raw = json_hash[item.name]
|
|
@@ -1119,6 +1139,7 @@ module OpenC3
|
|
|
1119
1139
|
limits_state = item.limits.state
|
|
1120
1140
|
json_hash["#{item.name}__L"] = limits_state if limits_state
|
|
1121
1141
|
end
|
|
1142
|
+
|
|
1122
1143
|
json_hash
|
|
1123
1144
|
end
|
|
1124
1145
|
|
|
@@ -433,10 +433,14 @@ module OpenC3
|
|
|
433
433
|
@current_packet.disabled = true
|
|
434
434
|
when 'ACCESSOR'
|
|
435
435
|
usage = "#{keyword} <Accessor class name>"
|
|
436
|
-
parser.verify_num_parameters(1,
|
|
436
|
+
parser.verify_num_parameters(1, nil, usage)
|
|
437
437
|
begin
|
|
438
438
|
klass = OpenC3.require_class(params[0])
|
|
439
|
-
|
|
439
|
+
if params.length > 1
|
|
440
|
+
@current_packet.accessor = klass.new(@current_packet, *params[1..-1])
|
|
441
|
+
else
|
|
442
|
+
@current_packet.accessor = klass.new(@current_packet)
|
|
443
|
+
end
|
|
440
444
|
rescue Exception => err
|
|
441
445
|
raise parser.error(err)
|
|
442
446
|
end
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
# GNU Affero General Public License for more details.
|
|
15
15
|
|
|
16
16
|
# Modified by OpenC3, Inc.
|
|
17
|
-
# All changes Copyright
|
|
17
|
+
# All changes Copyright 2023, OpenC3, Inc.
|
|
18
18
|
# All Rights Reserved
|
|
19
19
|
#
|
|
20
|
-
# 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/packets/packet_item'
|
|
@@ -158,6 +158,7 @@ module OpenC3
|
|
|
158
158
|
return nil if data_type == :STRING or data_type == :BLOCK
|
|
159
159
|
|
|
160
160
|
index = append? ? 3 : 4
|
|
161
|
+
return nil if @parser.parameters[index] == 'nil'
|
|
161
162
|
min = ConfigParser.handle_defined_constants(
|
|
162
163
|
@parser.parameters[index].convert_to_value, get_data_type(), get_bit_size()
|
|
163
164
|
)
|
|
@@ -183,9 +184,13 @@ module OpenC3
|
|
|
183
184
|
return @parser.parameters[index]
|
|
184
185
|
end
|
|
185
186
|
else
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
187
|
+
if data_type != :DERIVED
|
|
188
|
+
return ConfigParser.handle_defined_constants(
|
|
189
|
+
@parser.parameters[index + 2].convert_to_value, data_type, get_bit_size()
|
|
190
|
+
)
|
|
191
|
+
else
|
|
192
|
+
return @parser.parameters[index + 2].convert_to_value
|
|
193
|
+
end
|
|
189
194
|
end
|
|
190
195
|
end
|
|
191
196
|
|
|
@@ -248,7 +253,7 @@ module OpenC3
|
|
|
248
253
|
data_type = get_data_type()
|
|
249
254
|
rescue
|
|
250
255
|
# If the data type could not be determined set something
|
|
251
|
-
data_type
|
|
256
|
+
data_type = :INT
|
|
252
257
|
end
|
|
253
258
|
# STRING and BLOCK types do not have min or max values
|
|
254
259
|
if data_type == :STRING || data_type == :BLOCK
|
|
@@ -54,7 +54,7 @@ module OpenC3
|
|
|
54
54
|
# required data size is allowed.
|
|
55
55
|
attr_accessor :short_buffer_allowed
|
|
56
56
|
|
|
57
|
-
# @return [Accessor]
|
|
57
|
+
# @return [Accessor] Instance of class used to access raw data of structure from buffer
|
|
58
58
|
attr_reader :accessor
|
|
59
59
|
|
|
60
60
|
if RUBY_ENGINE != 'ruby' or ENV['OPENC3_NO_EXT']
|
|
@@ -92,7 +92,7 @@ module OpenC3
|
|
|
92
92
|
@fixed_size = true
|
|
93
93
|
@short_buffer_allowed = false
|
|
94
94
|
@mutex = nil
|
|
95
|
-
@accessor = BinaryAccessor
|
|
95
|
+
@accessor = BinaryAccessor.new(self)
|
|
96
96
|
else
|
|
97
97
|
raise(ArgumentError, "Unknown endianness '#{default_endianness}', must be :BIG_ENDIAN or :LITTLE_ENDIAN")
|
|
98
98
|
end
|
|
@@ -107,8 +107,6 @@ module OpenC3
|
|
|
107
107
|
# @return Value based on the item definition. This could be a string, integer,
|
|
108
108
|
# float, or array of values.
|
|
109
109
|
def read_item(item, value_type = :RAW, buffer = @buffer)
|
|
110
|
-
return nil if item.data_type == :DERIVED
|
|
111
|
-
|
|
112
110
|
buffer = allocate_buffer_if_needed() unless buffer
|
|
113
111
|
return @accessor.read_item(item, buffer)
|
|
114
112
|
end
|
|
@@ -141,7 +139,10 @@ module OpenC3
|
|
|
141
139
|
# @param accessor [Accessor] The class to use as an accessor
|
|
142
140
|
def accessor=(accessor)
|
|
143
141
|
@accessor = accessor
|
|
144
|
-
|
|
142
|
+
if @accessor.enforce_short_buffer_allowed
|
|
143
|
+
@short_buffer_allowed = true
|
|
144
|
+
end
|
|
145
|
+
return accessor
|
|
145
146
|
end
|
|
146
147
|
|
|
147
148
|
# Read a list of items in the structure
|
|
@@ -493,6 +494,8 @@ module OpenC3
|
|
|
493
494
|
# Use instance_variable_set since we have overriden buffer= to do
|
|
494
495
|
# additional work that isn't neccessary here
|
|
495
496
|
structure.instance_variable_set("@buffer".freeze, @buffer.clone) if @buffer
|
|
497
|
+
# Need to update reference packet in the Accessor
|
|
498
|
+
structure.accessor.packet = structure
|
|
496
499
|
return structure
|
|
497
500
|
end
|
|
498
501
|
alias dup clone
|
|
@@ -567,13 +570,17 @@ module OpenC3
|
|
|
567
570
|
raise ArgumentError, "Buffer class is #{buffer.class} but must be String" unless String === buffer
|
|
568
571
|
|
|
569
572
|
@buffer = buffer.dup
|
|
570
|
-
@
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
573
|
+
if @accessor.enforce_encoding
|
|
574
|
+
@buffer.force_encoding(@accessor.enforce_encoding)
|
|
575
|
+
end
|
|
576
|
+
if @accessor.enforce_length
|
|
577
|
+
if @buffer.length != @defined_length
|
|
578
|
+
if @buffer.length < @defined_length
|
|
579
|
+
resize_buffer()
|
|
580
|
+
raise "Buffer length less than defined length" unless @short_buffer_allowed
|
|
581
|
+
elsif @fixed_size and @defined_length != 0
|
|
582
|
+
raise "Buffer length greater than defined length"
|
|
583
|
+
end
|
|
577
584
|
end
|
|
578
585
|
end
|
|
579
586
|
end
|
|
@@ -104,7 +104,7 @@ module OpenC3
|
|
|
104
104
|
if part == "targets_modified" and ENV['OPENC3_LOCAL_MODE']
|
|
105
105
|
local_file = OpenC3::LocalMode.open_local_file(path, scope: scope)
|
|
106
106
|
if local_file
|
|
107
|
-
OpenC3::Logger.info "Reading local #{scope}/#{path}"
|
|
107
|
+
OpenC3::Logger.info "Reading local #{scope}/#{part}/#{path}"
|
|
108
108
|
file = Tempfile.new('target', binmode: true)
|
|
109
109
|
file.filename = path
|
|
110
110
|
file.write(local_file.read)
|