openc3 5.8.1 → 5.9.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/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)
|