cosmos 5.0.4 → 5.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/cosmos +182 -41
- data/data/config/plugins.yaml +10 -0
- data/ext/cosmos/ext/cosmos_io/cosmos_io.c +14 -14
- data/ext/cosmos/ext/packet/packet.c +3 -3
- data/ext/cosmos/ext/structure/structure.c +31 -31
- data/lib/cosmos/api/tlm_api.rb +4 -4
- data/lib/cosmos/logs/log_writer.rb +76 -27
- data/lib/cosmos/microservices/interface_microservice.rb +0 -15
- data/lib/cosmos/models/gem_model.rb +7 -1
- data/lib/cosmos/models/interface_model.rb +16 -7
- data/lib/cosmos/models/metadata_model.rb +39 -15
- data/lib/cosmos/models/microservice_model.rb +6 -3
- data/lib/cosmos/models/model.rb +7 -0
- data/lib/cosmos/models/note_model.rb +4 -6
- data/lib/cosmos/models/plugin_model.rb +107 -47
- data/lib/cosmos/models/scope_model.rb +2 -0
- data/lib/cosmos/models/sorted_model.rb +3 -1
- data/lib/cosmos/models/target_model.rb +24 -15
- data/lib/cosmos/models/tool_model.rb +8 -8
- data/lib/cosmos/models/widget_model.rb +10 -10
- data/lib/cosmos/packets/packet.rb +1 -1
- data/lib/cosmos/packets/structure.rb +30 -33
- data/lib/cosmos/script/calendar.rb +13 -2
- data/lib/cosmos/tools/table_manager/table_config.rb +16 -1
- data/lib/cosmos/tools/table_manager/table_manager_core.rb +213 -309
- data/lib/cosmos/topics/config_topic.rb +68 -0
- data/lib/cosmos/version.rb +5 -5
- metadata +7 -8
- data/bin/xtce_converter +0 -92
@@ -32,6 +32,7 @@ require 'cosmos/models/tool_model'
|
|
32
32
|
require 'cosmos/models/widget_model'
|
33
33
|
require 'cosmos/models/microservice_model'
|
34
34
|
require 'tmpdir'
|
35
|
+
require 'tempfile'
|
35
36
|
|
36
37
|
module Cosmos
|
37
38
|
# Represents a COSMOS plugin that can consist of targets, interfaces, routers
|
@@ -41,6 +42,9 @@ module Cosmos
|
|
41
42
|
PRIMARY_KEY = 'cosmos_plugins'
|
42
43
|
|
43
44
|
attr_accessor :variables
|
45
|
+
attr_accessor :plugin_txt_lines
|
46
|
+
attr_accessor :needs_dependencies
|
47
|
+
|
44
48
|
|
45
49
|
# NOTE: The following three class methods are used by the ModelController
|
46
50
|
# and are reimplemented to enable various Model class methods to work
|
@@ -58,71 +62,100 @@ module Cosmos
|
|
58
62
|
|
59
63
|
# Called by the PluginsController to parse the plugin variables
|
60
64
|
# Doesn't actaully create the plugin during the phase
|
61
|
-
def self.install_phase1(gem_file_path, existing_variables
|
62
|
-
|
63
|
-
|
64
|
-
# Load gem to internal gem server
|
65
|
-
Cosmos::GemModel.put(gem_file_path, gem_install: false, scope: scope)
|
66
|
-
|
67
|
-
# Extract gem and process plugin.txt to determine what VARIABLEs need to be filled in
|
68
|
-
pkg = Gem::Package.new(gem_file_path)
|
65
|
+
def self.install_phase1(gem_file_path, existing_variables: nil, existing_plugin_txt_lines: nil, process_existing: false, scope:, validate_only: false)
|
66
|
+
gem_name = File.basename(gem_file_path).split("__")[0]
|
69
67
|
|
70
68
|
temp_dir = Dir.mktmpdir
|
69
|
+
tf = nil
|
71
70
|
begin
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
71
|
+
if File.exists?(gem_file_path)
|
72
|
+
# Load gem to internal gem server
|
73
|
+
Cosmos::GemModel.put(gem_file_path, gem_install: false, scope: scope) unless validate_only
|
74
|
+
else
|
75
|
+
gem_file_path = Cosmos::GemModel.get(temp_dir, gem_name)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Extract gem and process plugin.txt to determine what VARIABLEs need to be filled in
|
79
|
+
pkg = Gem::Package.new(gem_file_path)
|
80
|
+
|
81
|
+
if existing_plugin_txt_lines and process_existing
|
82
|
+
# This is only used in cosmos load when everything is known
|
83
|
+
plugin_txt_lines = existing_plugin_txt_lines
|
84
|
+
file_data = existing_plugin_txt_lines.join("\n")
|
85
|
+
tf = Tempfile.new("plugin.txt")
|
86
|
+
tf.write(file_data)
|
87
|
+
tf.close
|
88
|
+
plugin_txt_path = tf.path
|
89
|
+
else
|
90
|
+
# Otherwise we always process the new and return both
|
91
|
+
pkg.extract_files(temp_dir)
|
92
|
+
plugin_txt_path = File.join(temp_dir, 'plugin.txt')
|
93
|
+
plugin_text = File.read(plugin_txt_path)
|
94
|
+
plugin_txt_lines = []
|
95
|
+
plugin_text.each_line do |line|
|
96
|
+
plugin_txt_lines << line.chomp
|
95
97
|
end
|
98
|
+
end
|
99
|
+
|
100
|
+
parser = Cosmos::ConfigParser.new("http://cosmosc2.com")
|
96
101
|
|
97
|
-
|
98
|
-
|
102
|
+
# Phase 1 Gather Variables
|
103
|
+
variables = {}
|
104
|
+
parser.parse_file(plugin_txt_path,
|
105
|
+
false,
|
106
|
+
true,
|
107
|
+
false) do |keyword, params|
|
108
|
+
case keyword
|
109
|
+
when 'VARIABLE'
|
110
|
+
usage = "#{keyword} <Variable Name> <Default Value>"
|
111
|
+
parser.verify_num_parameters(2, nil, usage)
|
112
|
+
variable_name = params[0]
|
113
|
+
value = params[1..-1].join(" ")
|
114
|
+
variables[variable_name] = value
|
115
|
+
if existing_variables && existing_variables.key?(variable_name)
|
116
|
+
variables[variable_name] = existing_variables[variable_name]
|
117
|
+
end
|
118
|
+
# Ignore everything else during phase 1
|
119
|
+
end
|
99
120
|
end
|
121
|
+
|
122
|
+
model = PluginModel.new(name: gem_name, variables: variables, plugin_txt_lines: plugin_txt_lines, scope: scope)
|
123
|
+
result = model.as_json
|
124
|
+
result['existing_plugin_txt_lines'] = existing_plugin_txt_lines if existing_plugin_txt_lines and not process_existing and existing_plugin_txt_lines != result['plugin_txt_lines']
|
125
|
+
return result
|
100
126
|
ensure
|
101
127
|
FileUtils.remove_entry(temp_dir) if temp_dir and File.exist?(temp_dir)
|
128
|
+
tf.unlink if tf
|
102
129
|
end
|
103
130
|
end
|
104
131
|
|
105
132
|
# Called by the PluginsController to create the plugin
|
106
133
|
# Because this uses ERB it must be run in a seperate process from the API to
|
107
134
|
# prevent corruption and single require problems in the current proces
|
108
|
-
def self.install_phase2(
|
135
|
+
def self.install_phase2(plugin_hash, scope:, validate_only: false)
|
109
136
|
rubys3_client = Aws::S3::Client.new
|
110
137
|
|
111
138
|
# Ensure config bucket exists
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
139
|
+
unless validate_only
|
140
|
+
begin
|
141
|
+
rubys3_client.head_bucket(bucket: 'config')
|
142
|
+
rescue Aws::S3::Errors::NotFound
|
143
|
+
rubys3_client.create_bucket(bucket: 'config')
|
144
|
+
end
|
116
145
|
end
|
117
146
|
|
118
147
|
# Register plugin to aid in uninstall if install fails
|
119
|
-
|
120
|
-
plugin_model.
|
148
|
+
plugin_hash.delete("existing_plugin_txt_lines")
|
149
|
+
plugin_model = PluginModel.new(**(plugin_hash.transform_keys(&:to_sym)), scope: scope)
|
150
|
+
plugin_model.create unless validate_only
|
121
151
|
|
122
152
|
temp_dir = Dir.mktmpdir
|
123
153
|
begin
|
154
|
+
tf = nil
|
155
|
+
|
124
156
|
# Get the gem from local gem server
|
125
|
-
|
157
|
+
gem_name = plugin_hash['name'].split("__")[0]
|
158
|
+
gem_file_path = Cosmos::GemModel.get(temp_dir, gem_name)
|
126
159
|
|
127
160
|
# Actually install the gem now (slow)
|
128
161
|
Cosmos::GemModel.install(gem_file_path, scope: scope)
|
@@ -133,6 +166,11 @@ module Cosmos
|
|
133
166
|
pkg = Gem::Package.new(gem_file_path)
|
134
167
|
needs_dependencies = pkg.spec.runtime_dependencies.length > 0
|
135
168
|
pkg.extract_files(gem_path)
|
169
|
+
needs_dependencies = true if Dir.exist?(File.join(gem_path, 'lib'))
|
170
|
+
if needs_dependencies
|
171
|
+
plugin_model.needs_dependencies = true
|
172
|
+
plugin_model.update
|
173
|
+
end
|
136
174
|
|
137
175
|
# Temporarily add all lib folders from the gem to the end of the load path
|
138
176
|
load_dirs = []
|
@@ -145,7 +183,12 @@ module Cosmos
|
|
145
183
|
end
|
146
184
|
|
147
185
|
# Process plugin.txt file
|
148
|
-
|
186
|
+
file_data = plugin_hash['plugin_txt_lines'].join("\n")
|
187
|
+
tf = Tempfile.new("plugin.txt")
|
188
|
+
tf.write(file_data)
|
189
|
+
tf.close
|
190
|
+
plugin_txt_path = tf.path
|
191
|
+
variables = plugin_hash['variables']
|
149
192
|
if File.exist?(plugin_txt_path)
|
150
193
|
parser = Cosmos::ConfigParser.new("http://cosmosc2.com")
|
151
194
|
|
@@ -156,8 +199,8 @@ module Cosmos
|
|
156
199
|
# Ignore during phase 2
|
157
200
|
when 'TARGET', 'INTERFACE', 'ROUTER', 'MICROSERVICE', 'TOOL', 'WIDGET'
|
158
201
|
if current_model
|
159
|
-
current_model.create
|
160
|
-
current_model.deploy(gem_path, variables)
|
202
|
+
current_model.create unless validate_only
|
203
|
+
current_model.deploy(gem_path, variables, validate_only: validate_only)
|
161
204
|
current_model = nil
|
162
205
|
end
|
163
206
|
current_model = Cosmos.const_get((keyword.capitalize + 'Model').intern).handle_config(parser, keyword, params, plugin: plugin_model.name, needs_dependencies: needs_dependencies, scope: scope)
|
@@ -170,8 +213,8 @@ module Cosmos
|
|
170
213
|
end
|
171
214
|
end
|
172
215
|
if current_model
|
173
|
-
current_model.create
|
174
|
-
current_model.deploy(gem_path, variables)
|
216
|
+
current_model.create unless validate_only
|
217
|
+
current_model.deploy(gem_path, variables, validate_only: validate_only)
|
175
218
|
current_model = nil
|
176
219
|
end
|
177
220
|
end
|
@@ -182,21 +225,28 @@ module Cosmos
|
|
182
225
|
end
|
183
226
|
rescue => err
|
184
227
|
# Install failed - need to cleanup
|
185
|
-
plugin_model.destroy
|
228
|
+
plugin_model.destroy unless validate_only
|
186
229
|
raise err
|
187
230
|
ensure
|
188
231
|
FileUtils.remove_entry(temp_dir) if temp_dir and File.exist?(temp_dir)
|
232
|
+
tf.unlink if tf
|
189
233
|
end
|
234
|
+
|
235
|
+
return plugin_model.as_json
|
190
236
|
end
|
191
237
|
|
192
238
|
def initialize(
|
193
239
|
name:,
|
194
240
|
variables: {},
|
241
|
+
plugin_txt_lines: [],
|
242
|
+
needs_dependencies: false,
|
195
243
|
updated_at: nil,
|
196
244
|
scope:
|
197
245
|
)
|
198
246
|
super("#{scope}__#{PRIMARY_KEY}", name: name, updated_at: updated_at, scope: scope)
|
199
247
|
@variables = variables
|
248
|
+
@plugin_txt_lines = plugin_txt_lines
|
249
|
+
@needs_dependencies = ConfigParser.handle_true_false(needs_dependencies)
|
200
250
|
end
|
201
251
|
|
202
252
|
def create(update: false, force: false)
|
@@ -208,6 +258,8 @@ module Cosmos
|
|
208
258
|
{
|
209
259
|
'name' => @name,
|
210
260
|
'variables' => @variables,
|
261
|
+
'plugin_txt_lines' => @plugin_txt_lines,
|
262
|
+
'needs_dependencies' => @needs_dependencies,
|
211
263
|
'updated_at' => @updated_at
|
212
264
|
}
|
213
265
|
end
|
@@ -220,5 +272,13 @@ module Cosmos
|
|
220
272
|
end
|
221
273
|
end
|
222
274
|
end
|
275
|
+
|
276
|
+
# Reinstall
|
277
|
+
def restore
|
278
|
+
plugin_hash = self.as_json
|
279
|
+
plugin_hash['name'] = plugin_hash['name'].split("__")[0]
|
280
|
+
Cosmos::PluginModel.install_phase2(plugin_hash, scope: @scope)
|
281
|
+
@destroyed = false
|
282
|
+
end
|
223
283
|
end
|
224
284
|
end
|
@@ -119,6 +119,7 @@ module Cosmos
|
|
119
119
|
def create(update: false)
|
120
120
|
validate_start(update: update)
|
121
121
|
@updated_at = Time.now.to_nsec_from_epoch
|
122
|
+
SortedModel.destroy(scope: @scope, start: update) if update
|
122
123
|
Store.zadd(@primary_key, @start, JSON.generate(as_json()))
|
123
124
|
if update
|
124
125
|
notify(kind: 'updated')
|
@@ -129,8 +130,9 @@ module Cosmos
|
|
129
130
|
|
130
131
|
# Update the Redis hash at primary_key
|
131
132
|
def update(start:)
|
133
|
+
orig_start = @start
|
132
134
|
@start = start
|
133
|
-
create(update:
|
135
|
+
create(update: orig_start)
|
134
136
|
end
|
135
137
|
|
136
138
|
# destroy the activity from the redis database
|
@@ -22,6 +22,7 @@ require 'cosmos/models/model'
|
|
22
22
|
require 'cosmos/models/cvt_model'
|
23
23
|
require 'cosmos/models/microservice_model'
|
24
24
|
require 'cosmos/topics/limits_event_topic'
|
25
|
+
require 'cosmos/topics/config_topic'
|
25
26
|
require 'cosmos/system'
|
26
27
|
require 'cosmos/utilities/s3'
|
27
28
|
require 'cosmos/utilities/zip'
|
@@ -360,7 +361,7 @@ module Cosmos
|
|
360
361
|
return nil
|
361
362
|
end
|
362
363
|
|
363
|
-
def deploy(gem_path, variables)
|
364
|
+
def deploy(gem_path, variables, validate_only: false)
|
364
365
|
rubys3_client = Aws::S3::Client.new
|
365
366
|
variables["target_name"] = @name
|
366
367
|
start_path = "/targets/#{@folder_name}/"
|
@@ -389,14 +390,23 @@ module Cosmos
|
|
389
390
|
FileUtils.mkdir_p(File.dirname(local_path))
|
390
391
|
File.open(local_path, 'wb') { |file| file.write(data) }
|
391
392
|
found = true
|
392
|
-
rubys3_client.put_object(bucket: 'config', key: key, body: data)
|
393
|
+
rubys3_client.put_object(bucket: 'config', key: key, body: data) unless validate_only
|
393
394
|
end
|
394
395
|
raise "No target files found at #{target_path}" unless found
|
395
396
|
|
396
397
|
target_folder = File.join(temp_dir, @name)
|
397
|
-
|
398
|
-
system =
|
399
|
-
|
398
|
+
# Build a System for just this target
|
399
|
+
system = System.new([@name], temp_dir)
|
400
|
+
if variables["xtce_output"]
|
401
|
+
puts "Converting target #{@name} to .xtce files in #{variables["xtce_output"]}/#{@name}"
|
402
|
+
system.packet_config.to_xtce(variables["xtce_output"])
|
403
|
+
end
|
404
|
+
unless validate_only
|
405
|
+
build_target_archive(rubys3_client, temp_dir, target_folder)
|
406
|
+
system = update_store(system)
|
407
|
+
deploy_microservices(gem_path, variables, system)
|
408
|
+
ConfigTopic.write({ kind: 'created', type: 'target', name: @name, plugin: @plugin }, scope: @scope)
|
409
|
+
end
|
400
410
|
ensure
|
401
411
|
FileUtils.remove_entry(temp_dir) if temp_dir and File.exist?(temp_dir)
|
402
412
|
end
|
@@ -430,6 +440,7 @@ module Cosmos
|
|
430
440
|
model = MicroserviceModel.get_model(name: "#{@scope}__#{type}__#{@name}", scope: @scope)
|
431
441
|
model.destroy if model
|
432
442
|
end
|
443
|
+
ConfigTopic.write({ kind: 'deleted', type: 'target', name: @name, plugin: @plugin }, scope: @scope)
|
433
444
|
end
|
434
445
|
|
435
446
|
##################################################
|
@@ -497,9 +508,7 @@ module Cosmos
|
|
497
508
|
end
|
498
509
|
end
|
499
510
|
|
500
|
-
def update_store(
|
501
|
-
# Build a System for just this target
|
502
|
-
system = System.new([@name], temp_dir)
|
511
|
+
def update_store(system)
|
503
512
|
target = system.targets[@name]
|
504
513
|
|
505
514
|
# Add in the information from the target and update
|
@@ -606,7 +615,7 @@ module Cosmos
|
|
606
615
|
],
|
607
616
|
topics: command_topic_list,
|
608
617
|
target_names: [@name],
|
609
|
-
plugin: plugin,
|
618
|
+
plugin: @plugin,
|
610
619
|
needs_dependencies: @needs_dependencies,
|
611
620
|
scope: @scope
|
612
621
|
)
|
@@ -629,7 +638,7 @@ module Cosmos
|
|
629
638
|
],
|
630
639
|
topics: decom_command_topic_list,
|
631
640
|
target_names: [@name],
|
632
|
-
plugin: plugin,
|
641
|
+
plugin: @plugin,
|
633
642
|
needs_dependencies: @needs_dependencies,
|
634
643
|
scope: @scope
|
635
644
|
)
|
@@ -654,7 +663,7 @@ module Cosmos
|
|
654
663
|
],
|
655
664
|
topics: packet_topic_list,
|
656
665
|
target_names: [@name],
|
657
|
-
plugin: plugin,
|
666
|
+
plugin: @plugin,
|
658
667
|
needs_dependencies: @needs_dependencies,
|
659
668
|
scope: @scope
|
660
669
|
)
|
@@ -677,7 +686,7 @@ module Cosmos
|
|
677
686
|
],
|
678
687
|
topics: decom_topic_list,
|
679
688
|
target_names: [@name],
|
680
|
-
plugin: plugin,
|
689
|
+
plugin: @plugin,
|
681
690
|
needs_dependencies: @needs_dependencies,
|
682
691
|
scope: @scope
|
683
692
|
)
|
@@ -694,7 +703,7 @@ module Cosmos
|
|
694
703
|
work_dir: '/cosmos/lib/cosmos/microservices',
|
695
704
|
topics: packet_topic_list,
|
696
705
|
target_names: [@name],
|
697
|
-
plugin: plugin,
|
706
|
+
plugin: @plugin,
|
698
707
|
needs_dependencies: @needs_dependencies,
|
699
708
|
scope: @scope
|
700
709
|
)
|
@@ -710,7 +719,7 @@ module Cosmos
|
|
710
719
|
cmd: ["ruby", "reducer_microservice.rb", microservice_name],
|
711
720
|
work_dir: '/cosmos/lib/cosmos/microservices',
|
712
721
|
topics: decom_topic_list,
|
713
|
-
plugin: plugin,
|
722
|
+
plugin: @plugin,
|
714
723
|
needs_dependencies: @needs_dependencies,
|
715
724
|
scope: @scope
|
716
725
|
)
|
@@ -727,7 +736,7 @@ module Cosmos
|
|
727
736
|
name: microservice_name,
|
728
737
|
cmd: ["ruby", "cleanup_microservice.rb", microservice_name],
|
729
738
|
work_dir: '/cosmos/lib/cosmos/microservices',
|
730
|
-
plugin: plugin,
|
739
|
+
plugin: @plugin,
|
731
740
|
scope: @scope
|
732
741
|
)
|
733
742
|
microservice.create
|
@@ -209,13 +209,11 @@ module Cosmos
|
|
209
209
|
return nil
|
210
210
|
end
|
211
211
|
|
212
|
-
def deploy(gem_path, variables)
|
212
|
+
def deploy(gem_path, variables, validate_only: false)
|
213
213
|
return unless @folder_name
|
214
214
|
|
215
|
-
rubys3_client = Aws::S3::Client.new
|
216
|
-
|
217
215
|
# Ensure tools bucket exists
|
218
|
-
Cosmos::S3Utilities.ensure_public_bucket('tools')
|
216
|
+
Cosmos::S3Utilities.ensure_public_bucket('tools') unless validate_only
|
219
217
|
|
220
218
|
variables["tool_name"] = @name
|
221
219
|
start_path = "/tools/#{@folder_name}/"
|
@@ -223,16 +221,17 @@ module Cosmos
|
|
223
221
|
next if filename == '.' or filename == '..' or File.directory?(filename)
|
224
222
|
|
225
223
|
key = filename.split(gem_path + '/tools/')[-1]
|
226
|
-
|
227
224
|
extension = filename.split('.')[-1]
|
228
225
|
content_type = Rack::Mime.mime_type(".#{extension}")
|
229
226
|
|
230
|
-
cache_control = Cosmos::S3Utilities.get_cache_control(filename)
|
231
|
-
|
232
227
|
# Load tool files
|
233
228
|
data = File.read(filename, mode: "rb")
|
234
229
|
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
235
|
-
|
230
|
+
unless validate_only
|
231
|
+
cache_control = Cosmos::S3Utilities.get_cache_control(filename)
|
232
|
+
Aws::S3::Client.new.put_object(bucket: 'tools', content_type: content_type, cache_control: cache_control, key: key, body: data)
|
233
|
+
ConfigTopic.write({ kind: 'created', type: 'tool', name: @folder_name, plugin: @plugin }, scope: @scope)
|
234
|
+
end
|
236
235
|
end
|
237
236
|
end
|
238
237
|
|
@@ -242,6 +241,7 @@ module Cosmos
|
|
242
241
|
prefix = "#{@folder_name}/"
|
243
242
|
rubys3_client.list_objects(bucket: 'tools', prefix: prefix).contents.each do |object|
|
244
243
|
rubys3_client.delete_object(bucket: 'tools', key: object.key)
|
244
|
+
ConfigTopic.write({ kind: 'deleted', type: 'tool', name: @folder_name, plugin: @plugin }, scope: @scope)
|
245
245
|
end
|
246
246
|
end
|
247
247
|
end
|
@@ -108,25 +108,25 @@ module Cosmos
|
|
108
108
|
raise ConfigParser::Error.new(parser, "Unknown keyword and parameters for Widget: #{keyword} #{parameters.join(" ")}")
|
109
109
|
end
|
110
110
|
|
111
|
-
def deploy(gem_path, variables)
|
112
|
-
rubys3_client = Aws::S3::Client.new
|
113
|
-
|
111
|
+
def deploy(gem_path, variables, validate_only: false)
|
114
112
|
# Ensure tools bucket exists
|
115
|
-
Cosmos::S3Utilities.ensure_public_bucket('tools')
|
113
|
+
Cosmos::S3Utilities.ensure_public_bucket('tools') unless validate_only
|
116
114
|
|
117
115
|
filename = gem_path + "/tools/widgets/" + @full_name + '/' + @filename
|
118
116
|
|
119
|
-
cache_control = Cosmos::S3Utilities.get_cache_control(@filename)
|
120
|
-
|
121
117
|
# Load widget file
|
122
118
|
data = File.read(filename, mode: "rb")
|
123
119
|
Cosmos.set_working_dir(File.dirname(filename)) do
|
124
120
|
data = ERB.new(data, trim_mode: "-").result(binding.set_variables(variables)) if data.is_printable?
|
125
121
|
end
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
122
|
+
unless validate_only
|
123
|
+
cache_control = Cosmos::S3Utilities.get_cache_control(@filename)
|
124
|
+
# TODO: support widgets that aren't just a single js file (and its associated map file)
|
125
|
+
rubys3_client = Aws::S3::Client.new
|
126
|
+
rubys3_client.put_object(bucket: 'tools', content_type: 'application/javascript', cache_control: cache_control, key: @s3_key, body: data)
|
127
|
+
data = File.read(filename + '.map', mode: "rb")
|
128
|
+
rubys3_client.put_object(bucket: 'tools', content_type: 'application/json', cache_control: cache_control, key: @s3_key + '.map', body: data)
|
129
|
+
end
|
130
130
|
end
|
131
131
|
|
132
132
|
def undeploy
|
@@ -98,7 +98,7 @@ module Cosmos
|
|
98
98
|
# @param buffer [String] String buffer to hold the packet data
|
99
99
|
# @param item_class [Class] Class used to instantiate items (Must be a
|
100
100
|
# subclass of PacketItem)
|
101
|
-
def initialize(target_name, packet_name, default_endianness = :BIG_ENDIAN, description = nil, buffer =
|
101
|
+
def initialize(target_name, packet_name, default_endianness = :BIG_ENDIAN, description = nil, buffer = nil, item_class = PacketItem)
|
102
102
|
super(default_endianness, buffer, item_class)
|
103
103
|
# Explictly call the defined setter methods
|
104
104
|
self.target_name = target_name
|
@@ -66,7 +66,7 @@ module Cosmos
|
|
66
66
|
# @param buffer [String] Buffer used to store the structure
|
67
67
|
# @param item_class [Class] Class used to instantiate new structure items.
|
68
68
|
# Must be StructureItem or one of its subclasses.
|
69
|
-
def initialize(default_endianness = BinaryAccessor::HOST_ENDIANNESS, buffer =
|
69
|
+
def initialize(default_endianness = BinaryAccessor::HOST_ENDIANNESS, buffer = nil, item_class = StructureItem)
|
70
70
|
if (default_endianness == :BIG_ENDIAN) || (default_endianness == :LITTLE_ENDIAN)
|
71
71
|
@default_endianness = default_endianness
|
72
72
|
if buffer
|
@@ -102,14 +102,11 @@ module Cosmos
|
|
102
102
|
def read_item(item, value_type = :RAW, buffer = @buffer)
|
103
103
|
return nil if item.data_type == :DERIVED
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
else
|
109
|
-
return BinaryAccessor.read(item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness)
|
110
|
-
end
|
105
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
106
|
+
if item.array_size
|
107
|
+
return BinaryAccessor.read_array(item.bit_offset, item.bit_size, item.data_type, item.array_size, buffer, item.endianness)
|
111
108
|
else
|
112
|
-
|
109
|
+
return BinaryAccessor.read(item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness)
|
113
110
|
end
|
114
111
|
end
|
115
112
|
|
@@ -117,9 +114,8 @@ module Cosmos
|
|
117
114
|
#
|
118
115
|
# @return [Integer] Size of the buffer in bytes
|
119
116
|
def length
|
120
|
-
|
121
|
-
|
122
|
-
return 0
|
117
|
+
allocate_buffer_if_needed()
|
118
|
+
return @buffer.length
|
123
119
|
end
|
124
120
|
|
125
121
|
# Resize the buffer at least the defined length of the structure
|
@@ -129,12 +125,23 @@ module Cosmos
|
|
129
125
|
if @buffer.length < @defined_length
|
130
126
|
@buffer << (ZERO_STRING * (@defined_length - @buffer.length))
|
131
127
|
end
|
128
|
+
else
|
129
|
+
allocate_buffer_if_needed()
|
132
130
|
end
|
133
131
|
|
134
132
|
return self
|
135
133
|
end
|
136
134
|
end
|
137
135
|
|
136
|
+
# Allocate a buffer if not available
|
137
|
+
def allocate_buffer_if_needed
|
138
|
+
unless @buffer
|
139
|
+
@buffer = ZERO_STRING * @defined_length
|
140
|
+
@buffer.force_encoding(ASCII_8BIT_STRING)
|
141
|
+
end
|
142
|
+
return @buffer
|
143
|
+
end
|
144
|
+
|
138
145
|
# Indicates if any items have been defined for this structure
|
139
146
|
# @return [TrueClass or FalseClass]
|
140
147
|
def defined?
|
@@ -340,14 +347,11 @@ module Cosmos
|
|
340
347
|
# parameter to check whether to perform conversions on the item.
|
341
348
|
# @param buffer [String] The binary buffer to write the value to
|
342
349
|
def write_item(item, value, value_type = :RAW, buffer = @buffer)
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
else
|
347
|
-
BinaryAccessor.write(value, item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness, item.overflow)
|
348
|
-
end
|
350
|
+
buffer = allocate_buffer_if_needed() unless buffer
|
351
|
+
if item.array_size
|
352
|
+
BinaryAccessor.write_array(value, item.bit_offset, item.bit_size, item.data_type, item.array_size, buffer, item.endianness, item.overflow)
|
349
353
|
else
|
350
|
-
|
354
|
+
BinaryAccessor.write(value, item.bit_offset, item.bit_size, item.data_type, buffer, item.endianness, item.overflow)
|
351
355
|
end
|
352
356
|
end
|
353
357
|
|
@@ -432,14 +436,11 @@ module Cosmos
|
|
432
436
|
# @param copy [TrueClass/FalseClass] Whether to copy the buffer
|
433
437
|
# @return [String] Data buffer backing the structure
|
434
438
|
def buffer(copy = true)
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
else
|
439
|
-
return @buffer
|
440
|
-
end
|
439
|
+
local_buffer = allocate_buffer_if_needed()
|
440
|
+
if copy
|
441
|
+
return local_buffer.dup
|
441
442
|
else
|
442
|
-
return
|
443
|
+
return local_buffer
|
443
444
|
end
|
444
445
|
end
|
445
446
|
|
@@ -525,15 +526,11 @@ module Cosmos
|
|
525
526
|
module MethodMissing
|
526
527
|
# Method missing provides reading/writing item values as if they were methods to the class
|
527
528
|
def method_missing(name, value = nil)
|
528
|
-
if
|
529
|
-
|
530
|
-
|
531
|
-
return write(name.to_s[0..-2], value)
|
532
|
-
else
|
533
|
-
return read(name.to_s)
|
534
|
-
end
|
529
|
+
if value
|
530
|
+
# Strip off the equals sign before looking up the item
|
531
|
+
return write(name.to_s[0..-2], value)
|
535
532
|
else
|
536
|
-
|
533
|
+
return read(name.to_s)
|
537
534
|
end
|
538
535
|
end
|
539
536
|
end
|
@@ -42,6 +42,9 @@ module Cosmos
|
|
42
42
|
# @param start [Time] Metadata time value, if nil will be current time
|
43
43
|
# @return The result of the method call.
|
44
44
|
def set_metadata(metadata, color: nil, start: nil)
|
45
|
+
unless metadata.is_a?(Hash)
|
46
|
+
raise "metadata must be a Hash: #{metadata} is a #{metadata.class}"
|
47
|
+
end
|
45
48
|
color = color.nil? ? '#003784' : color
|
46
49
|
data = { color: color, metadata: metadata }
|
47
50
|
data[:start] = start.iso8601 unless start.nil?
|
@@ -52,12 +55,20 @@ module Cosmos
|
|
52
55
|
|
53
56
|
# Updates the metadata
|
54
57
|
#
|
55
|
-
# @param start [Integer] Metadata time value as integer seconds from epoch
|
56
58
|
# @param metadata [Hash<Symbol, Variable>] A hash of metadata
|
57
59
|
# @param color [String] Events color to show on Calendar tool, if nil will be blue
|
60
|
+
# @param start [Integer] Metadata time value as integer seconds from epoch
|
58
61
|
# @return The result of the method call.
|
59
|
-
def update_metadata(
|
62
|
+
def update_metadata(metadata, color: nil, start: nil)
|
63
|
+
unless metadata.is_a?(Hash)
|
64
|
+
raise "metadata must be a Hash: #{metadata} is a #{metadata.class}"
|
65
|
+
end
|
60
66
|
color = color.nil? ? '#003784' : color
|
67
|
+
if start == nil
|
68
|
+
existing = get_metadata()
|
69
|
+
start = existing['start']
|
70
|
+
metadata = existing['metadata'].merge(metadata)
|
71
|
+
end
|
61
72
|
data = { :color => color, :metadata => metadata }
|
62
73
|
data[:start] = Time.at(start).iso8601
|
63
74
|
response = $api_server.request('put', "/cosmos-api/metadata/#{start}", data: data, json: true)
|