openc3 5.8.1 → 5.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/openc3/ext/crc/crc.c +1 -1
- data/lib/openc3/api/cmd_api.rb +1 -1
- data/lib/openc3/microservices/decom_microservice.rb +10 -2
- data/lib/openc3/microservices/reaction_microservice.rb +152 -81
- data/lib/openc3/microservices/timeline_microservice.rb +1 -1
- data/lib/openc3/microservices/trigger_group_microservice.rb +188 -118
- data/lib/openc3/migrations/20230615000000_autonomic.rb +86 -0
- data/lib/openc3/models/activity_model.rb +2 -4
- data/lib/openc3/models/microservice_model.rb +6 -2
- data/lib/openc3/models/model.rb +1 -3
- data/lib/openc3/models/reaction_model.rb +124 -119
- data/lib/openc3/models/scope_model.rb +15 -3
- data/lib/openc3/models/timeline_model.rb +1 -3
- data/lib/openc3/models/trigger_group_model.rb +16 -50
- data/lib/openc3/models/trigger_model.rb +86 -123
- data/lib/openc3/packets/json_packet.rb +2 -3
- data/lib/openc3/script/commands.rb +10 -0
- data/lib/openc3/script/script.rb +1 -0
- data/lib/openc3/top_level.rb +0 -12
- data/lib/openc3/utilities/authorization.rb +1 -1
- data/lib/openc3/utilities/bucket_require.rb +5 -1
- data/lib/openc3/utilities/bucket_utilities.rb +4 -1
- data/lib/openc3/utilities/cli_generator.rb +56 -4
- data/lib/openc3/utilities/ruby_lex_utils.rb +4 -0
- data/lib/openc3/version.rb +6 -6
- data/templates/plugin/README.md +54 -4
- data/templates/plugin/Rakefile +31 -3
- data/templates/tool_angular/.editorconfig +16 -0
- data/templates/tool_angular/.gitignore +44 -0
- data/templates/tool_angular/.vscode/extensions.json +4 -0
- data/templates/tool_angular/.vscode/launch.json +20 -0
- data/templates/tool_angular/.vscode/tasks.json +42 -0
- data/templates/tool_angular/angular.json +111 -0
- data/templates/tool_angular/extra-webpack.config.js +8 -0
- data/templates/tool_angular/package.json +47 -0
- data/templates/tool_angular/src/app/app-routing.module.ts +15 -0
- data/templates/tool_angular/src/app/app.component.html +31 -0
- data/templates/tool_angular/src/app/app.component.scss +26 -0
- data/templates/tool_angular/src/app/app.component.spec.ts +29 -0
- data/templates/tool_angular/src/app/app.component.ts +51 -0
- data/templates/tool_angular/src/app/app.module.ts +30 -0
- data/templates/tool_angular/src/app/custom-overlay-container.ts +17 -0
- data/templates/tool_angular/src/app/empty-route/empty-route.component.ts +7 -0
- data/templates/tool_angular/src/app/openc3-api.d.ts +1 -0
- data/templates/tool_angular/src/assets/.gitkeep +0 -0
- data/templates/tool_angular/src/environments/environment.prod.ts +3 -0
- data/templates/tool_angular/src/environments/environment.ts +16 -0
- data/templates/tool_angular/src/favicon.ico +0 -0
- data/templates/tool_angular/src/index.html +13 -0
- data/templates/tool_angular/src/main.single-spa.ts +40 -0
- data/templates/tool_angular/src/single-spa/asset-url.ts +12 -0
- data/templates/tool_angular/src/single-spa/single-spa-props.ts +8 -0
- data/templates/tool_angular/src/styles.scss +1 -0
- data/templates/tool_angular/tsconfig.app.json +13 -0
- data/templates/tool_angular/tsconfig.json +33 -0
- data/templates/tool_angular/tsconfig.spec.json +14 -0
- data/templates/tool_angular/yarn.lock +8080 -0
- data/templates/tool_react/.eslintrc +7 -0
- data/templates/tool_react/.gitignore +72 -0
- data/templates/tool_react/.prettierignore +8 -0
- data/templates/tool_react/babel.config.json +29 -0
- data/templates/tool_react/jest.config.js +12 -0
- data/templates/tool_react/package.json +53 -0
- data/templates/tool_react/src/openc3-tool_name.js +24 -0
- data/templates/tool_react/src/root.component.js +88 -0
- data/templates/tool_react/src/root.component.test.js +9 -0
- data/templates/tool_react/webpack.config.js +27 -0
- data/templates/tool_react/yarn.lock +6854 -0
- data/templates/tool_svelte/.gitignore +72 -0
- data/templates/tool_svelte/.prettierignore +8 -0
- data/templates/tool_svelte/babel.config.js +12 -0
- data/templates/tool_svelte/build/smui.css +5 -0
- data/templates/tool_svelte/jest.config.js +9 -0
- data/templates/tool_svelte/package.json +46 -0
- data/templates/tool_svelte/rollup.config.js +72 -0
- data/templates/tool_svelte/src/App.svelte +42 -0
- data/templates/tool_svelte/src/App.test.js +9 -0
- data/templates/tool_svelte/src/services/api.js +92 -0
- data/templates/tool_svelte/src/services/axios.js +85 -0
- data/templates/tool_svelte/src/services/cable.js +65 -0
- data/templates/tool_svelte/src/services/config-parser.js +199 -0
- data/templates/tool_svelte/src/services/openc3-api.js +647 -0
- data/templates/tool_svelte/src/theme/_smui-theme.scss +25 -0
- data/templates/tool_svelte/src/tool_name.js +17 -0
- data/templates/tool_svelte/yarn.lock +5052 -0
- data/templates/tool_vue/.browserslistrc +16 -0
- data/templates/tool_vue/.env.standalone +1 -0
- data/templates/tool_vue/.eslintrc.js +43 -0
- data/templates/tool_vue/.gitignore +2 -0
- data/templates/tool_vue/.nycrc +3 -0
- data/templates/tool_vue/.prettierrc.js +5 -0
- data/templates/tool_vue/babel.config.json +11 -0
- data/templates/tool_vue/jsconfig.json +6 -0
- data/templates/tool_vue/package.json +52 -0
- data/templates/tool_vue/src/App.vue +15 -0
- data/templates/tool_vue/src/main.js +38 -0
- data/templates/tool_vue/src/router.js +29 -0
- data/templates/tool_vue/src/tools/tool_name/tool_name.vue +63 -0
- data/templates/tool_vue/vue.config.js +30 -0
- data/templates/tool_vue/yarn.lock +9145 -0
- data/templates/widget/package.json +9 -9
- data/templates/widget/yarn.lock +77 -73
- metadata +76 -2
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'openc3/utilities/migration'
|
2
|
+
require 'openc3/models/trigger_group_model'
|
3
|
+
require 'openc3/models/trigger_model'
|
4
|
+
require 'openc3/models/reaction_model'
|
5
|
+
|
6
|
+
module OpenC3
|
7
|
+
class Autonomic < Migration
|
8
|
+
def self.run
|
9
|
+
ScopeModel.names.each do |scope|
|
10
|
+
puts "Processing scope #{scope}"
|
11
|
+
|
12
|
+
# Update all old TriggerModels just so they work when we delete the ReactionModel
|
13
|
+
# Because the ReactionModel verifies the triggers
|
14
|
+
delete_all_triggers = false
|
15
|
+
groups = TriggerGroupModel.all(scope: scope)
|
16
|
+
groups.each do |key, group_hash|
|
17
|
+
puts "Processing group #{group_hash['name']}"
|
18
|
+
if group_hash.has_key?('color')
|
19
|
+
group_hash.delete('color')
|
20
|
+
group = TriggerGroupModel.from_json(group_hash, name: group_hash['name'], scope: scope)
|
21
|
+
group.update()
|
22
|
+
end
|
23
|
+
TriggerModel.all(group: group_hash['name'], scope: scope).each do |key, model_hash|
|
24
|
+
if model_hash.has_key?('description') or model_hash.has_key?('active')
|
25
|
+
puts "Updating TriggerModel: #{model_hash['name']}"
|
26
|
+
model_hash.delete('description')
|
27
|
+
model_hash.delete('active')
|
28
|
+
model_hash['left'] = {'type' => 'item', 'target' => 'TGT', 'packet' => 'PKT', 'item' => 'ITEM', 'valueType' => 'CONVERTED'}
|
29
|
+
model_hash['operator'] = 'CHANGES'
|
30
|
+
model_hash['right'] = nil
|
31
|
+
TriggerModel.from_json(model_hash, name: model_hash['name'], scope: scope).update()
|
32
|
+
delete_all_triggers = true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Remove all old ReactionModels
|
38
|
+
ReactionModel.all(scope: scope).each do |key, model_hash|
|
39
|
+
if model_hash.has_key?('description') or model_hash.has_key?('review') or model_hash.has_key?('active')
|
40
|
+
# Can't delete directly because delete calls get which calls from_json which calls new
|
41
|
+
# and at that point we get missing keyword: :triggerLevel (ArgumentError)
|
42
|
+
# So update to add triggerLevel
|
43
|
+
model_hash['triggerLevel'] = 'EDGE'
|
44
|
+
model_hash.delete('description')
|
45
|
+
model_hash.delete('review')
|
46
|
+
model_hash.delete('active')
|
47
|
+
ReactionModel.from_json(model_hash, name: model_hash['name'], scope: scope).update()
|
48
|
+
puts "Deleting ReactionModel: #{model_hash['name']}"
|
49
|
+
ReactionModel.delete(name: model_hash['name'], scope: scope)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Remove all old TriggerModels and TriggerGroupModels
|
54
|
+
if delete_all_triggers
|
55
|
+
groups = TriggerGroupModel.all(scope: scope)
|
56
|
+
groups.each do |key, group_hash|
|
57
|
+
TriggerModel.all(group: group_hash['name'], scope: scope).each do |key, trigger_hash|
|
58
|
+
puts "Deleting TriggerModel: #{trigger_hash['name']}"
|
59
|
+
TriggerModel.delete(name: trigger_hash['name'], group: group_hash['name'], scope: scope)
|
60
|
+
end
|
61
|
+
group = TriggerGroupModel.from_json(group_hash, name: group_hash['name'], scope: scope)
|
62
|
+
group.undeploy()
|
63
|
+
puts "Deleting TriggerGroupModel: #{group_hash['name']}"
|
64
|
+
TriggerGroupModel.delete(name: group_hash['name'], scope: scope)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Create DEFAULT trigger group model
|
69
|
+
model = TriggerGroupModel.get(name: 'DEFAULT', scope: scope)
|
70
|
+
unless model
|
71
|
+
puts "Creating TriggerGroupModel: DEFAULT"
|
72
|
+
model = TriggerGroupModel.new(name: 'DEFAULT', scope: scope)
|
73
|
+
model.create()
|
74
|
+
model.deploy()
|
75
|
+
end
|
76
|
+
end
|
77
|
+
rescue => error
|
78
|
+
puts error.message
|
79
|
+
puts error.backtrace
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
unless ENV['OPENC3_NO_MIGRATE']
|
85
|
+
OpenC3::Autonomic.run
|
86
|
+
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
|
# https://www.rubydoc.info/gems/redis/Redis/Commands/SortedSets
|
@@ -107,9 +107,7 @@ module OpenC3
|
|
107
107
|
def self.from_json(json, name:, scope:)
|
108
108
|
json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
|
109
109
|
raise "json data is nil" if json.nil?
|
110
|
-
|
111
|
-
json.transform_keys!(&:to_sym)
|
112
|
-
self.new(**json, name: name, scope: scope)
|
110
|
+
self.new(**json.transform_keys(&:to_sym), name: name, scope: scope)
|
113
111
|
end
|
114
112
|
|
115
113
|
attr_reader :duration, :start, :stop, :kind, :data, :events, :fulfillment
|
@@ -228,7 +228,9 @@ module OpenC3
|
|
228
228
|
end
|
229
229
|
end
|
230
230
|
unless validate_only
|
231
|
-
|
231
|
+
config = { kind: 'created', type: 'microservice', name: @name }
|
232
|
+
config[:plugin] = @plugin if @plugin
|
233
|
+
ConfigTopic.write(config, scope: @scope)
|
232
234
|
end
|
233
235
|
end
|
234
236
|
|
@@ -237,7 +239,9 @@ module OpenC3
|
|
237
239
|
@bucket.list_objects(bucket: ENV['OPENC3_CONFIG_BUCKET'], prefix: prefix).each do |object|
|
238
240
|
@bucket.delete_object(bucket: ENV['OPENC3_CONFIG_BUCKET'], key: object.key)
|
239
241
|
end
|
240
|
-
|
242
|
+
config = { kind: 'deleted', type: 'microservice', name: @name }
|
243
|
+
config[:plugin] = @plugin if @plugin
|
244
|
+
ConfigTopic.write(config, scope: @scope)
|
241
245
|
rescue Exception => error
|
242
246
|
Logger.error("Error undeploying microservice model #{@name} in scope #{@scope} due to #{error}")
|
243
247
|
end
|
data/lib/openc3/models/model.rb
CHANGED
@@ -85,10 +85,8 @@ module OpenC3
|
|
85
85
|
def self.from_json(json, scope:)
|
86
86
|
json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
|
87
87
|
raise "json data is nil" if json.nil?
|
88
|
-
|
89
88
|
json[:scope] = scope
|
90
|
-
json.transform_keys
|
91
|
-
self.new(**json, scope: scope)
|
89
|
+
self.new(**json.transform_keys(&:to_sym), scope: scope)
|
92
90
|
end
|
93
91
|
|
94
92
|
# Calls self.get and then from_json to turn the Hash configuration into a Ruby Model object.
|
@@ -27,47 +27,22 @@ require 'openc3/topics/autonomic_topic'
|
|
27
27
|
|
28
28
|
module OpenC3
|
29
29
|
class ReactionError < StandardError; end
|
30
|
-
|
31
30
|
class ReactionInputError < ReactionError; end
|
32
31
|
|
33
|
-
# {
|
34
|
-
# "description": "POSX greater than 200",
|
35
|
-
# "snooze": 300,
|
36
|
-
# "review": true,
|
37
|
-
# "triggers": [
|
38
|
-
# {
|
39
|
-
# "name": "TV0-1234",
|
40
|
-
# "group": "foo",
|
41
|
-
# }
|
42
|
-
# ],
|
43
|
-
# "actions": [
|
44
|
-
# {
|
45
|
-
# "type": "command",
|
46
|
-
# "value": "INST CLEAR",
|
47
|
-
# }
|
48
|
-
# ]
|
49
|
-
# }
|
50
32
|
class ReactionModel < Model
|
51
33
|
PRIMARY_KEY = '__openc3__reaction'.freeze
|
52
|
-
COMMAND_REACTION = 'command'.freeze
|
53
34
|
SCRIPT_REACTION = 'script'.freeze
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def self.reactions(scope:)
|
64
|
-
reactions = Array.new
|
65
|
-
Store.hgetall("#{scope}#{PRIMARY_KEY}").each do |key, value|
|
66
|
-
data = JSON.parse(value, :allow_nan => true, :create_additions => true)
|
67
|
-
reaction = self.from_json(data, name: data['name'], scope: data['scope'])
|
68
|
-
reactions << reaction if reaction.active
|
35
|
+
COMMAND_REACTION = 'command'.freeze
|
36
|
+
NOTIFY_REACTION = 'notify'.freeze
|
37
|
+
ACTION_TYPES = [SCRIPT_REACTION, COMMAND_REACTION, NOTIFY_REACTION]
|
38
|
+
|
39
|
+
def self.create_unique_name(scope:)
|
40
|
+
reaction_names = self.names(scope: scope) # comes back sorted
|
41
|
+
num = 1 # Users count with 1
|
42
|
+
if reaction_names[-1]
|
43
|
+
num = reaction_names[-1][5..-1].to_i + 1
|
69
44
|
end
|
70
|
-
return
|
45
|
+
return "REACT#{num}"
|
71
46
|
end
|
72
47
|
|
73
48
|
# @return [ReactionModel] Return the object with the name at
|
@@ -89,10 +64,10 @@ module OpenC3
|
|
89
64
|
end
|
90
65
|
|
91
66
|
# Check dependents before delete.
|
92
|
-
def self.delete(name:, scope
|
67
|
+
def self.delete(name:, scope:)
|
93
68
|
model = self.get(name: name, scope: scope)
|
94
69
|
if model.nil?
|
95
|
-
raise ReactionInputError.new "
|
70
|
+
raise ReactionInputError.new "reaction '#{name}' does not exist"
|
96
71
|
end
|
97
72
|
model.triggers.each do | trigger |
|
98
73
|
trigger_model = TriggerModel.get(name: trigger['name'], group: trigger['group'], scope: scope)
|
@@ -100,29 +75,79 @@ module OpenC3
|
|
100
75
|
trigger_model.update()
|
101
76
|
end
|
102
77
|
Store.hdel("#{scope}#{PRIMARY_KEY}", name)
|
103
|
-
|
78
|
+
# No notification as this is only called via reaction_controller which already notifies
|
79
|
+
|
80
|
+
# undeploy only actually runs if no reactions are left
|
81
|
+
model.undeploy()
|
104
82
|
end
|
105
83
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
84
|
+
attr_reader :name, :scope, :snooze, :triggers, :actions, :enabled, :triggerLevel, :snoozed_until
|
85
|
+
attr_accessor :username
|
86
|
+
|
87
|
+
def initialize(
|
88
|
+
name:,
|
89
|
+
scope:,
|
90
|
+
snooze:,
|
91
|
+
actions:,
|
92
|
+
triggers:,
|
93
|
+
triggerLevel:,
|
94
|
+
enabled: true,
|
95
|
+
snoozed_until: nil,
|
96
|
+
username: nil,
|
97
|
+
updated_at: nil
|
98
|
+
)
|
99
|
+
super("#{scope}#{PRIMARY_KEY}", name: name, scope: scope)
|
100
|
+
@microservice_name = "#{scope}__OPENC3__REACTION"
|
101
|
+
@enabled = enabled
|
102
|
+
@snoozed_until = snoozed_until
|
103
|
+
@triggerLevel = validate_level(triggerLevel)
|
104
|
+
@snooze = validate_snooze(snooze)
|
105
|
+
@actions = validate_actions(actions)
|
106
|
+
@triggers = validate_triggers(triggers)
|
107
|
+
@username = username
|
108
|
+
@updated_at = updated_at
|
109
|
+
end
|
110
|
+
|
111
|
+
# Modifiers for the reaction_controller update action
|
112
|
+
def triggerLevel=(triggerLevel)
|
113
|
+
@triggerLevel = validate_level(triggerLevel)
|
114
|
+
end
|
115
|
+
def snooze=(snooze)
|
116
|
+
@snooze = validate_snooze(snooze)
|
117
|
+
end
|
118
|
+
def actions=(actions)
|
119
|
+
@actions = validate_actions(actions)
|
120
|
+
end
|
121
|
+
def triggers=(triggers)
|
122
|
+
@triggers = validate_triggers(triggers)
|
123
|
+
end
|
124
|
+
|
125
|
+
def validate_level(level)
|
126
|
+
case level
|
127
|
+
when 'EDGE', 'LEVEL'
|
128
|
+
return level
|
129
|
+
else
|
130
|
+
raise ReactionInputError.new "invalid triggerLevel, must be EDGE or LEVEL: #{level}"
|
110
131
|
end
|
111
|
-
return snooze
|
112
132
|
end
|
113
133
|
|
114
|
-
|
115
|
-
|
134
|
+
def validate_snooze(snooze)
|
135
|
+
Integer(snooze)
|
136
|
+
rescue
|
137
|
+
raise ReactionInputError.new "invalid snooze value: #{snooze}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def validate_triggers(triggers)
|
116
141
|
unless triggers.is_a?(Array)
|
117
|
-
raise ReactionInputError.new "invalid
|
142
|
+
raise ReactionInputError.new "invalid triggers, must be array of hashes: #{triggers}"
|
118
143
|
end
|
119
144
|
trigger_hash = Hash.new()
|
120
145
|
triggers.each do | trigger |
|
121
146
|
unless trigger.is_a?(Hash)
|
122
|
-
raise ReactionInputError.new "invalid trigger
|
147
|
+
raise ReactionInputError.new "invalid trigger, must be hash: #{trigger}"
|
123
148
|
end
|
124
149
|
if trigger['name'].nil? || trigger['group'].nil?
|
125
|
-
raise ReactionInputError.new "
|
150
|
+
raise ReactionInputError.new "invalid trigger, must contain 'name' and 'group' keys: #{trigger}"
|
126
151
|
end
|
127
152
|
trigger_name = trigger['name']
|
128
153
|
unless trigger_hash[trigger_name].nil?
|
@@ -134,60 +159,27 @@ module OpenC3
|
|
134
159
|
return triggers
|
135
160
|
end
|
136
161
|
|
137
|
-
|
138
|
-
def validate_actions(actions:)
|
162
|
+
def validate_actions(actions)
|
139
163
|
unless actions.is_a?(Array)
|
140
|
-
raise ReactionInputError.new "invalid actions
|
164
|
+
raise ReactionInputError.new "invalid actions, must be array of hashes: #{actions}"
|
141
165
|
end
|
142
166
|
actions.each do | action |
|
143
167
|
unless action.is_a?(Hash)
|
144
|
-
raise ReactionInputError.new "invalid action
|
168
|
+
raise ReactionInputError.new "invalid action, must be a hash: #{action}"
|
145
169
|
end
|
146
170
|
action_type = action['type']
|
147
171
|
if action_type.nil?
|
148
|
-
raise ReactionInputError.new "
|
172
|
+
raise ReactionInputError.new "invalid action, must contain 'type': #{action}"
|
149
173
|
elsif action['value'].nil?
|
150
|
-
raise ReactionInputError.new "
|
174
|
+
raise ReactionInputError.new "invalid action, must contain 'value': #{action}"
|
151
175
|
end
|
152
|
-
unless
|
153
|
-
raise ReactionInputError.new "
|
176
|
+
unless ACTION_TYPES.include?(action_type)
|
177
|
+
raise ReactionInputError.new "invalid action type '#{action_type}', must be one of #{ACTION_TYPES}"
|
154
178
|
end
|
155
179
|
end
|
156
180
|
return actions
|
157
181
|
end
|
158
182
|
|
159
|
-
attr_reader :name, :scope, :description, :snooze, :triggers, :actions, :active, :review, :snoozed_until
|
160
|
-
attr_accessor :username
|
161
|
-
|
162
|
-
def initialize(
|
163
|
-
name:,
|
164
|
-
scope:,
|
165
|
-
description:,
|
166
|
-
snooze:,
|
167
|
-
actions:,
|
168
|
-
triggers:,
|
169
|
-
active: true,
|
170
|
-
review: true,
|
171
|
-
snoozed_until: nil,
|
172
|
-
username: nil,
|
173
|
-
updated_at: nil
|
174
|
-
)
|
175
|
-
if name.nil? || scope.nil? || description.nil? || snooze.nil? || triggers.nil? || actions.nil?
|
176
|
-
raise ReactionInputError.new "#{name}, #{scope}, #{description}, #{snooze}, #{triggers}, or #{actions} must not be nil"
|
177
|
-
end
|
178
|
-
super("#{scope}#{PRIMARY_KEY}", name: name, scope: scope)
|
179
|
-
@microservice_name = "#{scope}__OPENC3__REACTION"
|
180
|
-
@active = active
|
181
|
-
@review = review
|
182
|
-
@description = description
|
183
|
-
@snoozed_until = snoozed_until
|
184
|
-
@snooze = validate_snooze(snooze: snooze)
|
185
|
-
@actions = validate_actions(actions: actions)
|
186
|
-
@triggers = validate_triggers(triggers: triggers)
|
187
|
-
@username = username
|
188
|
-
@updated_at = updated_at
|
189
|
-
end
|
190
|
-
|
191
183
|
def verify_triggers
|
192
184
|
trigger_models = []
|
193
185
|
@triggers.each do | trigger |
|
@@ -208,7 +200,7 @@ module OpenC3
|
|
208
200
|
|
209
201
|
def create
|
210
202
|
unless Store.hget(@primary_key, @name).nil?
|
211
|
-
raise ReactionInputError.new "
|
203
|
+
raise ReactionInputError.new "existing reaction found: #{@name}"
|
212
204
|
end
|
213
205
|
verify_triggers()
|
214
206
|
@updated_at = Time.now.to_nsec_from_epoch
|
@@ -220,41 +212,43 @@ module OpenC3
|
|
220
212
|
verify_triggers()
|
221
213
|
@updated_at = Time.now.to_nsec_from_epoch
|
222
214
|
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
223
|
-
|
215
|
+
# No notification as this is only called via reaction_controller which already notifies
|
224
216
|
end
|
225
217
|
|
226
|
-
def
|
227
|
-
@
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
218
|
+
def notify_enable
|
219
|
+
@enabled = true
|
220
|
+
notify(kind: 'enabled')
|
221
|
+
# update() will be called by the reaction_microservice
|
222
|
+
end
|
223
|
+
|
224
|
+
def notify_disable
|
225
|
+
@enabled = false
|
226
|
+
# disabling clears the snooze so when it's enabled it can immediately run
|
227
|
+
@snoozed_until = nil
|
228
|
+
notify(kind: 'disabled')
|
229
|
+
# update() will be called by the reaction_microservice
|
232
230
|
end
|
233
231
|
|
234
|
-
def
|
235
|
-
|
232
|
+
def notify_execute
|
233
|
+
# Set updated_at because the event is all we get ... no update later
|
236
234
|
@updated_at = Time.now.to_nsec_from_epoch
|
237
|
-
|
238
|
-
notify(kind: 'deactivated')
|
235
|
+
notify(kind: 'executed')
|
239
236
|
end
|
240
237
|
|
241
238
|
def sleep
|
242
|
-
@
|
243
|
-
|
244
|
-
|
245
|
-
|
239
|
+
if @snooze > 0
|
240
|
+
@snoozed_until = Time.now.to_i + @snooze
|
241
|
+
@updated_at = Time.now.to_nsec_from_epoch
|
242
|
+
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
243
|
+
notify(kind: 'snoozed')
|
244
|
+
end
|
246
245
|
end
|
247
246
|
|
248
247
|
def awaken
|
249
248
|
@snoozed_until = nil
|
250
249
|
@updated_at = Time.now.to_nsec_from_epoch
|
251
250
|
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
252
|
-
notify(kind: '
|
253
|
-
end
|
254
|
-
|
255
|
-
# @return [String] generated from the TriggerModel
|
256
|
-
def to_s
|
257
|
-
return "(ReactionModel :: #{@name} :: #{@active} :: #{@review} :: #{@description} :: #{@snooze} :: #{@snoozed_until})"
|
251
|
+
notify(kind: 'awakened')
|
258
252
|
end
|
259
253
|
|
260
254
|
# @return [Hash] generated from the ReactionModel
|
@@ -262,9 +256,8 @@ module OpenC3
|
|
262
256
|
return {
|
263
257
|
'name' => @name,
|
264
258
|
'scope' => @scope,
|
265
|
-
'
|
266
|
-
'
|
267
|
-
'description' => @description,
|
259
|
+
'enabled' => @enabled,
|
260
|
+
'triggerLevel' => @triggerLevel,
|
268
261
|
'snooze' => @snooze,
|
269
262
|
'snoozed_until' => @snoozed_until,
|
270
263
|
'triggers' => @triggers,
|
@@ -278,9 +271,7 @@ module OpenC3
|
|
278
271
|
def self.from_json(json, name:, scope:)
|
279
272
|
json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
|
280
273
|
raise "json data is nil" if json.nil?
|
281
|
-
|
282
|
-
json.transform_keys!(&:to_sym)
|
283
|
-
self.new(**json, name: name, scope: scope)
|
274
|
+
self.new(**json.transform_keys(&:to_sym), name: name, scope: scope)
|
284
275
|
end
|
285
276
|
|
286
277
|
# @return [] update the redis stream / reaction topic that something has changed
|
@@ -317,9 +308,23 @@ module OpenC3
|
|
317
308
|
end
|
318
309
|
|
319
310
|
def undeploy
|
320
|
-
|
321
|
-
|
322
|
-
|
311
|
+
return unless ReactionModel.names(scope: @scope).empty?
|
312
|
+
|
313
|
+
model = MicroserviceModel.get_model(name: @microservice_name, scope: @scope)
|
314
|
+
if model
|
315
|
+
# Let the frontend know that the microservice is shutting down
|
316
|
+
# Custom event which matches the 'deployed' event in ReactionMicroservice
|
317
|
+
notification = {
|
318
|
+
'kind' => 'undeployed',
|
319
|
+
'type' => 'reaction',
|
320
|
+
# name and updated_at fields are required for Event formatting
|
321
|
+
'data' => JSON.generate({
|
322
|
+
'name' => @microservice_name,
|
323
|
+
'updated_at' => Time.now.to_nsec_from_epoch,
|
324
|
+
}),
|
325
|
+
}
|
326
|
+
AutonomicTopic.write_notification(notification, scope: @scope)
|
327
|
+
model.destroy
|
323
328
|
end
|
324
329
|
end
|
325
330
|
end
|
@@ -25,6 +25,7 @@ require 'openc3/models/model'
|
|
25
25
|
require 'openc3/models/plugin_model'
|
26
26
|
require 'openc3/models/microservice_model'
|
27
27
|
require 'openc3/models/setting_model'
|
28
|
+
require 'openc3/models/trigger_group_model'
|
28
29
|
|
29
30
|
module OpenC3
|
30
31
|
class ScopeModel < Model
|
@@ -49,9 +50,7 @@ module OpenC3
|
|
49
50
|
def self.from_json(json, scope: nil)
|
50
51
|
json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
|
51
52
|
raise "json data is nil" if json.nil?
|
52
|
-
|
53
|
-
json.transform_keys!(&:to_sym)
|
54
|
-
self.new(**json, scope: scope)
|
53
|
+
self.new(**json.transform_keys(&:to_sym), scope: scope)
|
55
54
|
end
|
56
55
|
|
57
56
|
def self.get_model(name:, scope: nil)
|
@@ -210,6 +209,14 @@ module OpenC3
|
|
210
209
|
def deploy(gem_path, variables)
|
211
210
|
seed_database()
|
212
211
|
|
212
|
+
# Create DEFAULT trigger group model
|
213
|
+
model = TriggerGroupModel.get(name: 'DEFAULT', scope: @scope)
|
214
|
+
unless model
|
215
|
+
model = TriggerGroupModel.new(name: 'DEFAULT', scope: @scope)
|
216
|
+
model.create()
|
217
|
+
model.deploy()
|
218
|
+
end
|
219
|
+
|
213
220
|
# Create UNKNOWN target for display of unknown data
|
214
221
|
model = TargetModel.new(name: "UNKNOWN", scope: @scope)
|
215
222
|
model.create
|
@@ -250,11 +257,16 @@ module OpenC3
|
|
250
257
|
model.destroy if model
|
251
258
|
model = MicroserviceModel.get_model(name: "#{@scope}__PERIODIC__#{@scope}", scope: @scope)
|
252
259
|
model.destroy if model
|
260
|
+
model = MicroserviceModel.get_model(name: "#{@scope}__TRIGGER_GROUP__DEFAULT", scope: @scope)
|
261
|
+
model.destroy if model
|
262
|
+
|
253
263
|
# Delete the topics we created for the scope
|
254
264
|
Topic.del("#{@scope}__COMMAND__{UNKNOWN}__UNKNOWN")
|
255
265
|
Topic.del("#{@scope}__TELEMETRY__{UNKNOWN}__UNKNOWN")
|
256
266
|
Topic.del("#{@scope}__openc3_targets")
|
257
267
|
Topic.del("#{@scope}__CONFIG")
|
268
|
+
Topic.del("#{@scope}__openc3_autonomic")
|
269
|
+
Topic.del("#{@scope}__TRIGGER__GROUP")
|
258
270
|
end
|
259
271
|
|
260
272
|
def seed_database
|
@@ -71,9 +71,7 @@ module OpenC3
|
|
71
71
|
def self.from_json(json, name:, scope:)
|
72
72
|
json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
|
73
73
|
raise "json data is nil" if json.nil?
|
74
|
-
|
75
|
-
json.transform_keys!(&:to_sym)
|
76
|
-
self.new(**json, name: name, scope: scope)
|
74
|
+
self.new(**json.transform_keys(&:to_sym), name: name, scope: scope)
|
77
75
|
end
|
78
76
|
|
79
77
|
def initialize(name:, scope:, updated_at: nil, color: nil)
|