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
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
|