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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 35a757bea46ad5b21ac348aa90b6163595d04c702b752b728f628d7dd82f6132
|
|
4
|
+
data.tar.gz: 149be2f48cdb7864a3665bf46982a1e16fb37541f68203387297c14d0d55e7d8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1595ea101a9473b1aa5a1894d08bcd5704943fae771f9e58c4506b905cae9cb5957ab0fc961349ec9ecc4466a3ae34b6987a2a9d21ed8b9d2b0d31592c16908b
|
|
7
|
+
data.tar.gz: afbf06dfc4d4dbbfd7916146b6ee2b3005959bae650735127710b257a675487591adb5739744e603ef5eb20cc545b4dc79962021aaef00127c9aa76017a4ba3e
|
data/ext/openc3/ext/crc/crc.c
CHANGED
data/lib/openc3/api/cmd_api.rb
CHANGED
|
@@ -393,7 +393,7 @@ module OpenC3
|
|
|
393
393
|
# Check if any of the parameters have DISABLE_MESSAGES
|
|
394
394
|
cmd_params.each do |key, value|
|
|
395
395
|
item = packet['items'].find { |item| item['name'] == key.to_s }
|
|
396
|
-
if item['states'] && item['states'][value] && item['states'][value]["messages_disabled"]
|
|
396
|
+
if item && item['states'] && item['states'][value] && item['states'][value]["messages_disabled"]
|
|
397
397
|
log_message = false
|
|
398
398
|
end
|
|
399
399
|
end
|
|
@@ -124,14 +124,22 @@ module OpenC3
|
|
|
124
124
|
when :BLUE, :GREEN, :GREEN_LOW, :GREEN_HIGH
|
|
125
125
|
@logger.info message
|
|
126
126
|
when :YELLOW, :YELLOW_LOW, :YELLOW_HIGH
|
|
127
|
+
notification = NotificationModel.new(
|
|
128
|
+
time: time_nsec,
|
|
129
|
+
severity: "caution",
|
|
130
|
+
url: "/tools/limitsmonitor",
|
|
131
|
+
title: "#{packet.target_name} #{packet.packet_name} #{item.name} #{item.limits.state}",
|
|
132
|
+
body: "#{item.name} is #{item.limits.state}"
|
|
133
|
+
)
|
|
134
|
+
NotificationsTopic.write_notification(notification.as_json(:allow_nan => true), scope: @scope)
|
|
127
135
|
@logger.warn message
|
|
128
136
|
when :RED, :RED_LOW, :RED_HIGH
|
|
129
137
|
notification = NotificationModel.new(
|
|
130
138
|
time: time_nsec,
|
|
131
139
|
severity: "critical",
|
|
132
140
|
url: "/tools/limitsmonitor",
|
|
133
|
-
title: "#{packet.target_name} #{packet.packet_name} #{item.name}
|
|
134
|
-
body: "
|
|
141
|
+
title: "#{packet.target_name} #{packet.packet_name} #{item.name} #{item.limits.state}",
|
|
142
|
+
body: "#{item.name} is #{item.limits.state}"
|
|
135
143
|
)
|
|
136
144
|
NotificationsTopic.write_notification(notification.as_json(:allow_nan => true), scope: @scope)
|
|
137
145
|
@logger.error message
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
require 'openc3/microservices/microservice'
|
|
24
24
|
require 'openc3/models/reaction_model'
|
|
25
25
|
require 'openc3/models/notification_model'
|
|
26
|
+
require 'openc3/topics/notifications_topic'
|
|
26
27
|
require 'openc3/models/trigger_model'
|
|
27
28
|
require 'openc3/topics/autonomic_topic'
|
|
28
29
|
require 'openc3/utilities/authentication'
|
|
@@ -30,12 +31,12 @@ require 'openc3/utilities/authentication'
|
|
|
30
31
|
require 'openc3/script'
|
|
31
32
|
|
|
32
33
|
module OpenC3
|
|
33
|
-
|
|
34
|
-
# This should remain a thread safe implamentation. This is the in memory
|
|
34
|
+
# This should remain a thread safe implementation. This is the in memory
|
|
35
35
|
# cache that should mirror the database. This will update two hash
|
|
36
36
|
# variables and will track triggers to lookup what triggers link to what
|
|
37
37
|
# reactions.
|
|
38
38
|
class ReactionBase
|
|
39
|
+
attr_reader :reactions
|
|
39
40
|
|
|
40
41
|
def initialize(scope:)
|
|
41
42
|
@scope = scope
|
|
@@ -45,7 +46,7 @@ module OpenC3
|
|
|
45
46
|
@lookup = Hash.new
|
|
46
47
|
end
|
|
47
48
|
|
|
48
|
-
# RETURNS an Array of
|
|
49
|
+
# RETURNS an Array of actively snoozed reactions
|
|
49
50
|
def get_snoozed
|
|
50
51
|
data = nil
|
|
51
52
|
@reactions_mutex.synchronize do
|
|
@@ -53,15 +54,15 @@ module OpenC3
|
|
|
53
54
|
end
|
|
54
55
|
ret = Array.new
|
|
55
56
|
return ret unless data
|
|
56
|
-
data.each do |
|
|
57
|
+
data.each do |_name, r_hash|
|
|
57
58
|
data = Marshal.load( Marshal.dump(r_hash) )
|
|
58
59
|
reaction = ReactionModel.from_json(data, name: data['name'], scope: data['scope'])
|
|
59
|
-
ret << reaction if reaction.
|
|
60
|
+
ret << reaction if reaction.enabled && reaction.snoozed_until
|
|
60
61
|
end
|
|
61
62
|
return ret
|
|
62
63
|
end
|
|
63
64
|
|
|
64
|
-
# RETURNS an Array of
|
|
65
|
+
# RETURNS an Array of actively NOT snoozed reactions
|
|
65
66
|
def get_reactions(trigger_name:)
|
|
66
67
|
array_value = nil
|
|
67
68
|
@lookup_mutex.synchronize do
|
|
@@ -69,26 +70,25 @@ module OpenC3
|
|
|
69
70
|
end
|
|
70
71
|
ret = Array.new
|
|
71
72
|
return ret unless array_value
|
|
72
|
-
array_value.each do |
|
|
73
|
+
array_value.each do |name|
|
|
73
74
|
@reactions_mutex.synchronize do
|
|
74
75
|
data = Marshal.load( Marshal.dump(@reactions[name]) )
|
|
75
76
|
reaction = ReactionModel.from_json(data, name: data['name'], scope: data['scope'])
|
|
76
|
-
ret << reaction if reaction.
|
|
77
|
+
ret << reaction if reaction.enabled && reaction.snoozed_until.nil?
|
|
77
78
|
end
|
|
78
79
|
end
|
|
79
80
|
return ret
|
|
80
81
|
end
|
|
81
82
|
|
|
82
|
-
# Update the
|
|
83
|
-
# database
|
|
83
|
+
# Update the memory database with a HASH of reactions from the external database
|
|
84
84
|
def setup(reactions:)
|
|
85
85
|
@reactions_mutex.synchronize do
|
|
86
86
|
@reactions = Marshal.load( Marshal.dump(reactions) )
|
|
87
87
|
end
|
|
88
88
|
@lookup_mutex.synchronize do
|
|
89
89
|
@lookup = Hash.new
|
|
90
|
-
reactions.each do |
|
|
91
|
-
reaction['triggers'].each do |
|
|
90
|
+
reactions.each do |reaction_name, reaction|
|
|
91
|
+
reaction['triggers'].each do |trigger|
|
|
92
92
|
trigger_name = trigger['name']
|
|
93
93
|
if @lookup[trigger_name].nil?
|
|
94
94
|
@lookup[trigger_name] = [reaction_name]
|
|
@@ -132,7 +132,7 @@ module OpenC3
|
|
|
132
132
|
@reactions_mutex.synchronize do
|
|
133
133
|
@reactions[reaction_name] = reaction
|
|
134
134
|
end
|
|
135
|
-
reaction['triggers'].each do |
|
|
135
|
+
reaction['triggers'].each do |trigger|
|
|
136
136
|
trigger_name = trigger['name']
|
|
137
137
|
@lookup_mutex.synchronize do
|
|
138
138
|
if @lookup[trigger_name].nil?
|
|
@@ -147,30 +147,30 @@ module OpenC3
|
|
|
147
147
|
# Updates a reaction to the in memory database. This current does not
|
|
148
148
|
# update the lookup Hash for the triggers.
|
|
149
149
|
def update(reaction:)
|
|
150
|
-
reaction_name = reaction['name']
|
|
151
150
|
@reactions_mutex.synchronize do
|
|
152
|
-
|
|
151
|
+
model = ReactionModel.from_json(reaction, name: reaction['name'], scope: reaction['scope'])
|
|
152
|
+
model.update()
|
|
153
|
+
@reactions[reaction['name']] = model.as_json(:allow_nan => true)
|
|
153
154
|
end
|
|
154
155
|
end
|
|
155
156
|
|
|
156
157
|
# Removes a reaction to the in memory database.
|
|
157
158
|
def remove(reaction:)
|
|
158
|
-
reaction_name = reaction['name']
|
|
159
159
|
@reactions_mutex.synchronize do
|
|
160
|
-
@reactions.delete(
|
|
160
|
+
@reactions.delete(reaction['name'])
|
|
161
|
+
ReactionModel.delete(name: reaction['name'], scope: reaction['scope'])
|
|
161
162
|
end
|
|
162
|
-
reaction['triggers'].each do |
|
|
163
|
+
reaction['triggers'].each do |trigger|
|
|
163
164
|
trigger_name = trigger['name']
|
|
164
165
|
@lookup_mutex.synchronize do
|
|
165
|
-
@lookup[trigger_name].delete(
|
|
166
|
+
@lookup[trigger_name].delete(reaction['name'])
|
|
166
167
|
end
|
|
167
168
|
end
|
|
168
169
|
end
|
|
169
170
|
end
|
|
170
171
|
|
|
171
|
-
# This should remain a thread safe
|
|
172
|
+
# This should remain a thread safe implementation.
|
|
172
173
|
class QueueBase
|
|
173
|
-
|
|
174
174
|
attr_reader :queue
|
|
175
175
|
|
|
176
176
|
def initialize(scope:)
|
|
@@ -182,9 +182,8 @@ module OpenC3
|
|
|
182
182
|
end
|
|
183
183
|
end
|
|
184
184
|
|
|
185
|
-
# This should remain a thread safe
|
|
185
|
+
# This should remain a thread safe implementation.
|
|
186
186
|
class SnoozeBase
|
|
187
|
-
|
|
188
187
|
def initialize(scope:)
|
|
189
188
|
# store the round robin watch
|
|
190
189
|
@watch_mutex = Mutex.new
|
|
@@ -207,7 +206,6 @@ module OpenC3
|
|
|
207
206
|
# Shared between the monitor thread and the manager thread to
|
|
208
207
|
# share the resources.
|
|
209
208
|
class ReactionShare
|
|
210
|
-
|
|
211
209
|
attr_reader :reaction_base, :queue_base, :snooze_base
|
|
212
210
|
|
|
213
211
|
def initialize(scope:)
|
|
@@ -215,7 +213,6 @@ module OpenC3
|
|
|
215
213
|
@queue_base = QueueBase.new(scope: scope)
|
|
216
214
|
@snooze_base = SnoozeBase.new(scope: scope)
|
|
217
215
|
end
|
|
218
|
-
|
|
219
216
|
end
|
|
220
217
|
|
|
221
218
|
# The Reaction worker is a very simple thread pool worker. Once the manager
|
|
@@ -262,7 +259,7 @@ module OpenC3
|
|
|
262
259
|
when 'reaction'
|
|
263
260
|
run_reaction(reaction: reaction(data: data))
|
|
264
261
|
when 'trigger'
|
|
265
|
-
|
|
262
|
+
process_true_trigger(data: data)
|
|
266
263
|
end
|
|
267
264
|
rescue StandardError => e
|
|
268
265
|
@logger.error "ReactionWorker-#{@ident} failed to evaluate kind: #{kind} data: #{data}\n#{e.formatted}"
|
|
@@ -271,8 +268,8 @@ module OpenC3
|
|
|
271
268
|
@logger.info "ReactionWorker-#{@ident} exiting"
|
|
272
269
|
end
|
|
273
270
|
|
|
274
|
-
def
|
|
275
|
-
@share.reaction_base.get_reactions(trigger_name: data['name']).each do |
|
|
271
|
+
def process_true_trigger(data:)
|
|
272
|
+
@share.reaction_base.get_reactions(trigger_name: data['name']).each do |reaction|
|
|
276
273
|
run_reaction(reaction: reaction)
|
|
277
274
|
end
|
|
278
275
|
end
|
|
@@ -285,7 +282,21 @@ module OpenC3
|
|
|
285
282
|
end
|
|
286
283
|
|
|
287
284
|
def run_action(reaction:, action:)
|
|
285
|
+
reaction.updated_at = Time.now.to_nsec_from_epoch
|
|
286
|
+
reaction_json = reaction.as_json(:allow_nan => true)
|
|
287
|
+
# Let the frontend know which action is being run
|
|
288
|
+
# because we can combine commands and scripts with notifications
|
|
289
|
+
reaction_json['action'] = action['type']
|
|
290
|
+
notification = {
|
|
291
|
+
'kind' => 'run',
|
|
292
|
+
'type' => 'reaction',
|
|
293
|
+
'data' => JSON.generate(reaction_json),
|
|
294
|
+
}
|
|
295
|
+
AutonomicTopic.write_notification(notification, scope: @scope)
|
|
296
|
+
|
|
288
297
|
case action['type']
|
|
298
|
+
when 'notify'
|
|
299
|
+
run_notify(reaction: reaction, action: action)
|
|
289
300
|
when 'command'
|
|
290
301
|
run_command(reaction: reaction, action: action)
|
|
291
302
|
when 'script'
|
|
@@ -293,21 +304,31 @@ module OpenC3
|
|
|
293
304
|
end
|
|
294
305
|
end
|
|
295
306
|
|
|
307
|
+
def run_notify(reaction:, action:)
|
|
308
|
+
notification = NotificationModel.new(
|
|
309
|
+
time: Time.now.to_nsec_from_epoch,
|
|
310
|
+
severity: action['severity'],
|
|
311
|
+
url: "/tools/autonomic/reactions",
|
|
312
|
+
title: "#{reaction.name} run",
|
|
313
|
+
body: action['value']
|
|
314
|
+
)
|
|
315
|
+
NotificationsTopic.write_notification(notification.as_json(:allow_nan => true), scope: @scope)
|
|
316
|
+
@logger.info "ReactionWorker-#{@ident} #{reaction.name} notify action complete, body: #{action['value']}, severity: #{action['severity']}"
|
|
317
|
+
end
|
|
318
|
+
|
|
296
319
|
def run_command(reaction:, action:)
|
|
297
|
-
@logger.debug "ReactionWorker-#{@ident} running reaction #{reaction.name}, command: '#{action['value']}' "
|
|
298
320
|
begin
|
|
299
321
|
username = reaction.username
|
|
300
322
|
token = get_token(username)
|
|
301
323
|
raise "No token available for username: #{username}" unless token
|
|
302
324
|
cmd_no_hazardous_check(action['value'], scope: @scope, token: token)
|
|
303
|
-
@logger.info "ReactionWorker-#{@ident} #{reaction.name} command action complete, #{action['value']}"
|
|
325
|
+
@logger.info "ReactionWorker-#{@ident} #{reaction.name} command action complete, command: #{action['value']}"
|
|
304
326
|
rescue StandardError => e
|
|
305
327
|
@logger.error "ReactionWorker-#{@ident} #{reaction.name} command action failed, #{action}\n#{e.message}"
|
|
306
328
|
end
|
|
307
329
|
end
|
|
308
330
|
|
|
309
331
|
def run_script(reaction:, action:)
|
|
310
|
-
@logger.debug "ReactionWorker-#{@ident} running reaction #{reaction.name}, script: '#{action['value']}'"
|
|
311
332
|
begin
|
|
312
333
|
username = reaction.username
|
|
313
334
|
token = get_token(username)
|
|
@@ -351,7 +372,7 @@ module OpenC3
|
|
|
351
372
|
|
|
352
373
|
def generate_thread_pool()
|
|
353
374
|
thread_pool = []
|
|
354
|
-
@worker_count.times do |
|
|
375
|
+
@worker_count.times do |i|
|
|
355
376
|
worker = ReactionWorker.new(name: @name, logger: @logger, scope: @scope, share: @share, ident: i)
|
|
356
377
|
thread_pool << Thread.new { worker.run }
|
|
357
378
|
end
|
|
@@ -376,7 +397,7 @@ module OpenC3
|
|
|
376
397
|
end
|
|
377
398
|
|
|
378
399
|
def active_triggers(reaction:)
|
|
379
|
-
reaction.triggers.each do |
|
|
400
|
+
reaction.triggers.each do |trigger|
|
|
380
401
|
t = TriggerModel.get(name: trigger['name'], group: trigger['group'], scope: @scope)
|
|
381
402
|
return true if t && t.state
|
|
382
403
|
end
|
|
@@ -384,16 +405,11 @@ module OpenC3
|
|
|
384
405
|
end
|
|
385
406
|
|
|
386
407
|
def manage_snoozed_reactions(current_time:)
|
|
387
|
-
@share.reaction_base.get_snoozed.each do |
|
|
408
|
+
@share.reaction_base.get_snoozed.each do |reaction|
|
|
388
409
|
time_difference = reaction.snoozed_until - current_time
|
|
389
410
|
if time_difference <= 0 && @share.snooze_base.not_queued?(reaction: reaction)
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
@logger.debug "#{reaction.name} review set to false, setting snoozed_until back to nil"
|
|
393
|
-
@share.reaction_base.wake(name: reaction.name)
|
|
394
|
-
next
|
|
395
|
-
end
|
|
396
|
-
if active_triggers(reaction: reaction)
|
|
411
|
+
# LEVEL triggers mean we run if the trigger is active
|
|
412
|
+
if reaction.triggerLevel == 'LEVEL' and active_triggers(reaction: reaction)
|
|
397
413
|
@share.queue_base.enqueue(kind: 'reaction', data: reaction.as_json(:allow_nan => true))
|
|
398
414
|
else
|
|
399
415
|
@share.reaction_base.wake(name: reaction.name)
|
|
@@ -404,7 +420,7 @@ module OpenC3
|
|
|
404
420
|
|
|
405
421
|
def shutdown
|
|
406
422
|
@cancel_thread = true
|
|
407
|
-
@worker_count.times do |
|
|
423
|
+
@worker_count.times do |i|
|
|
408
424
|
@share.queue_base.enqueue(kind: nil, data: nil)
|
|
409
425
|
end
|
|
410
426
|
end
|
|
@@ -415,8 +431,39 @@ module OpenC3
|
|
|
415
431
|
# AutonomicTopic for changes.
|
|
416
432
|
class ReactionMicroservice < Microservice
|
|
417
433
|
attr_reader :name, :scope, :share, :manager, :manager_thread
|
|
434
|
+
TOPIC_LOOKUP = {
|
|
435
|
+
'group' => {
|
|
436
|
+
'created' => :no_op,
|
|
437
|
+
'updated' => :no_op,
|
|
438
|
+
'deleted' => :no_op,
|
|
439
|
+
},
|
|
440
|
+
'trigger' => {
|
|
441
|
+
'error' => :no_op,
|
|
442
|
+
'created' => :no_op,
|
|
443
|
+
'updated' => :no_op,
|
|
444
|
+
'deleted' => :no_op,
|
|
445
|
+
'enabled' => :no_op,
|
|
446
|
+
'disabled' => :no_op,
|
|
447
|
+
'true' => :trigger_true_event,
|
|
448
|
+
'false' => :no_op,
|
|
449
|
+
},
|
|
450
|
+
'reaction' => {
|
|
451
|
+
'run' => :no_op,
|
|
452
|
+
'deployed' => :no_op,
|
|
453
|
+
'undeployed' => :no_op,
|
|
454
|
+
'created' => :reaction_created_event,
|
|
455
|
+
'updated' => :reaction_updated_event,
|
|
456
|
+
'deleted' => :reaction_deleted_event,
|
|
457
|
+
'enabled' => :reaction_enabled_event,
|
|
458
|
+
'disabled' => :reaction_disabled_event,
|
|
459
|
+
'snoozed' => :no_op,
|
|
460
|
+
'awakened' => :no_op,
|
|
461
|
+
'executed' => :reaction_execute_event,
|
|
462
|
+
}
|
|
463
|
+
}
|
|
418
464
|
|
|
419
465
|
def initialize(*args)
|
|
466
|
+
# The name is passed in via the reaction_model as "#{scope}__OPENC3__REACTION"
|
|
420
467
|
super(*args)
|
|
421
468
|
@share = ReactionShare.new(scope: @scope)
|
|
422
469
|
@manager = ReactionSnoozeManager.new(name: @name, logger: @logger, scope: @scope, share: @share)
|
|
@@ -426,53 +473,36 @@ module OpenC3
|
|
|
426
473
|
|
|
427
474
|
def run
|
|
428
475
|
@logger.info "ReactionMicroservice running"
|
|
476
|
+
# Let the frontend know that the microservice has been deployed and is running
|
|
477
|
+
notification = {
|
|
478
|
+
'kind' => 'deployed',
|
|
479
|
+
'type' => 'reaction',
|
|
480
|
+
# name and updated_at fields are required for Event formatting
|
|
481
|
+
'data' => JSON.generate({
|
|
482
|
+
'name' => @name,
|
|
483
|
+
'updated_at' => Time.now.to_nsec_from_epoch,
|
|
484
|
+
}),
|
|
485
|
+
}
|
|
486
|
+
AutonomicTopic.write_notification(notification, scope: @scope)
|
|
487
|
+
|
|
429
488
|
@manager_thread = Thread.new { @manager.run }
|
|
430
489
|
loop do
|
|
431
490
|
reactions = ReactionModel.all(scope: @scope)
|
|
432
491
|
@share.reaction_base.setup(reactions: reactions)
|
|
433
492
|
break if @cancel_thread
|
|
434
|
-
|
|
435
493
|
block_for_updates()
|
|
436
494
|
break if @cancel_thread
|
|
437
495
|
end
|
|
438
496
|
@logger.info "ReactionMicroservice exiting"
|
|
439
497
|
end
|
|
440
498
|
|
|
441
|
-
def topic_lookup_functions
|
|
442
|
-
return {
|
|
443
|
-
'group' => {
|
|
444
|
-
'created' => :no_op,
|
|
445
|
-
'updated' => :no_op,
|
|
446
|
-
'deleted' => :no_op,
|
|
447
|
-
},
|
|
448
|
-
'trigger' => {
|
|
449
|
-
'created' => :no_op,
|
|
450
|
-
'updated' => :no_op,
|
|
451
|
-
'deleted' => :no_op,
|
|
452
|
-
'enabled' => :trigger_enabled_event,
|
|
453
|
-
'disabled' => :no_op,
|
|
454
|
-
'activated' => :no_op,
|
|
455
|
-
'deactivated' => :no_op,
|
|
456
|
-
},
|
|
457
|
-
'reaction' => {
|
|
458
|
-
'created' => :reaction_created_event,
|
|
459
|
-
'updated' => :refresh_event,
|
|
460
|
-
'deleted' => :reaction_deleted_event,
|
|
461
|
-
'sleep' => :no_op,
|
|
462
|
-
'awaken' => :no_op,
|
|
463
|
-
'activated' => :reaction_updated_event,
|
|
464
|
-
'deactivated' => :reaction_updated_event,
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
end
|
|
468
|
-
|
|
469
499
|
def block_for_updates
|
|
470
500
|
@read_topic = true
|
|
471
|
-
while @read_topic
|
|
501
|
+
while @read_topic && !@cancel_thread
|
|
472
502
|
begin
|
|
473
503
|
AutonomicTopic.read_topics(@topics) do |_topic, _msg_id, msg_hash, _redis|
|
|
474
504
|
@logger.debug "ReactionMicroservice block_for_updates: #{msg_hash.to_s}"
|
|
475
|
-
public_send(
|
|
505
|
+
public_send(TOPIC_LOOKUP[msg_hash['type']][msg_hash['kind']], msg_hash)
|
|
476
506
|
end
|
|
477
507
|
rescue StandardError => e
|
|
478
508
|
@logger.error "ReactionMicroservice failed to read topics #{@topics}\n#{e.formatted}"
|
|
@@ -484,29 +514,70 @@ module OpenC3
|
|
|
484
514
|
@logger.debug "ReactionMicroservice web socket event: #{data}"
|
|
485
515
|
end
|
|
486
516
|
|
|
487
|
-
def
|
|
488
|
-
@logger.debug "ReactionMicroservice
|
|
517
|
+
def reaction_updated_event(msg_hash)
|
|
518
|
+
@logger.debug "ReactionMicroservice reaction updated msg_hash: #{msg_hash}"
|
|
519
|
+
reaction = JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true)
|
|
520
|
+
@share.reaction_base.update(reaction: reaction)
|
|
489
521
|
@read_topic = false
|
|
490
522
|
end
|
|
491
523
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
@logger.debug "ReactionMicroservice trigger event msg_hash: #{msg_hash}"
|
|
524
|
+
def trigger_true_event(msg_hash)
|
|
525
|
+
@logger.debug "ReactionMicroservice trigger true msg_hash: #{msg_hash}"
|
|
495
526
|
@share.queue_base.enqueue(kind: 'trigger', data: JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true))
|
|
496
527
|
end
|
|
497
528
|
|
|
498
529
|
# Add the reaction to the shared data.
|
|
499
530
|
def reaction_created_event(msg_hash)
|
|
500
531
|
@logger.debug "ReactionMicroservice reaction created msg_hash: #{msg_hash}"
|
|
501
|
-
|
|
532
|
+
reaction = JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true)
|
|
533
|
+
@share.reaction_base.add(reaction: reaction)
|
|
534
|
+
|
|
535
|
+
# If the reaction triggerLevel is LEVEL we have to check its triggers
|
|
536
|
+
# on add because if the trigger is active it should run
|
|
537
|
+
if reaction['triggerLevel'] == 'LEVEL'
|
|
538
|
+
reaction['triggers'].each do |trigger_hash|
|
|
539
|
+
trigger = TriggerModel.get(name: trigger_hash['name'], group: trigger_hash['group'], scope: reaction['scope'])
|
|
540
|
+
if trigger && trigger.state
|
|
541
|
+
@logger.info "ReactionMicroservice reaction #{reaction['name']} created. Since triggerLevel is 'LEVEL' it was run due to #{trigger.name}."
|
|
542
|
+
@share.queue_base.enqueue(kind: 'reaction', data: reaction)
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
end
|
|
502
546
|
end
|
|
503
547
|
|
|
504
548
|
# Update the reaction to the shared data.
|
|
505
|
-
def
|
|
506
|
-
@logger.debug "ReactionMicroservice reaction
|
|
549
|
+
def reaction_enabled_event(msg_hash)
|
|
550
|
+
@logger.debug "ReactionMicroservice reaction enabled msg_hash: #{msg_hash}"
|
|
551
|
+
reaction = JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true)
|
|
552
|
+
@share.reaction_base.update(reaction: reaction)
|
|
553
|
+
|
|
554
|
+
# If the reaction triggerLevel is LEVEL we have to check its triggers
|
|
555
|
+
# on add because if the trigger is active it should run
|
|
556
|
+
if reaction['triggerLevel'] == 'LEVEL'
|
|
557
|
+
reaction['triggers'].each do |trigger_hash|
|
|
558
|
+
trigger = TriggerModel.get(name: trigger_hash['name'], group: trigger_hash['group'], scope: reaction['scope'])
|
|
559
|
+
if trigger && trigger.state
|
|
560
|
+
@logger.info "ReactionMicroservice reaction #{reaction['name']} enabled. Since triggerLevel is 'LEVEL' it was run due to #{trigger.name}."
|
|
561
|
+
@share.queue_base.enqueue(kind: 'reaction', data: reaction)
|
|
562
|
+
end
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
# Update the reaction to the shared data.
|
|
568
|
+
def reaction_disabled_event(msg_hash)
|
|
569
|
+
@logger.debug "ReactionMicroservice reaction disabled msg_hash: #{msg_hash}"
|
|
507
570
|
@share.reaction_base.update(reaction: JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true))
|
|
508
571
|
end
|
|
509
572
|
|
|
573
|
+
# Add the reaction to the shared data.
|
|
574
|
+
def reaction_execute_event(msg_hash)
|
|
575
|
+
@logger.debug "ReactionMicroservice reaction execute msg_hash: #{msg_hash}"
|
|
576
|
+
reaction = JSON.parse(msg_hash['data'], :allow_nan => true, :create_additions => true)
|
|
577
|
+
@share.reaction_base.update(reaction: reaction)
|
|
578
|
+
@share.queue_base.enqueue(kind: 'reaction', data: reaction)
|
|
579
|
+
end
|
|
580
|
+
|
|
510
581
|
# Remove the reaction from the shared data
|
|
511
582
|
def reaction_deleted_event(msg_hash)
|
|
512
583
|
@logger.debug "ReactionMicroservice reaction deleted msg_hash: #{msg_hash}"
|
|
@@ -136,7 +136,7 @@ module OpenC3
|
|
|
136
136
|
|
|
137
137
|
# Shared between the monitor thread and the manager thread to
|
|
138
138
|
# share the planned activities. This should remain a thread
|
|
139
|
-
# safe
|
|
139
|
+
# safe implementation.
|
|
140
140
|
class Schedule
|
|
141
141
|
def initialize(name)
|
|
142
142
|
@name = name
|