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
@@ -26,14 +26,8 @@ require 'openc3/topics/autonomic_topic'
|
|
26
26
|
|
27
27
|
module OpenC3
|
28
28
|
class TriggerGroupError < StandardError; end
|
29
|
-
|
30
29
|
class TriggerGroupInputError < TriggerGroupError; end
|
31
30
|
|
32
|
-
# INPUT:
|
33
|
-
# {
|
34
|
-
# "name": "FOOBAR",
|
35
|
-
# "color": "#000000",
|
36
|
-
# }
|
37
31
|
class TriggerGroupModel < Model
|
38
32
|
PRIMARY_KEY = '__TRIGGER__GROUP'.freeze
|
39
33
|
|
@@ -59,67 +53,39 @@ module OpenC3
|
|
59
53
|
def self.delete(name:, scope:)
|
60
54
|
model = self.get(name: name, scope: scope)
|
61
55
|
if model.nil?
|
62
|
-
raise TriggerGroupInputError.new "
|
56
|
+
raise TriggerGroupInputError.new "group '#{name}' does not exist"
|
63
57
|
end
|
64
58
|
triggers = TriggerModel.names(scope: scope, group: name)
|
65
59
|
if triggers.empty?
|
66
60
|
Store.hdel("#{scope}#{PRIMARY_KEY}", name)
|
67
61
|
model.notify(kind: 'deleted')
|
68
62
|
else
|
69
|
-
raise TriggerGroupError.new "
|
63
|
+
raise TriggerGroupError.new "group '#{name}' has dependent triggers: #{triggers}"
|
70
64
|
end
|
71
65
|
end
|
72
66
|
|
73
|
-
attr_reader :name, :scope, :
|
67
|
+
attr_reader :name, :scope, :updated_at
|
74
68
|
|
75
|
-
def initialize(name:, scope:,
|
76
|
-
if name.nil? || scope.nil?
|
77
|
-
raise GroupTriggerInputError.new "name, or scope must not be nil"
|
78
|
-
end
|
69
|
+
def initialize(name:, scope:, updated_at: nil)
|
79
70
|
unless name.is_a?(String)
|
80
|
-
raise TriggerGroupInputError.new "invalid name: '#{name}'"
|
71
|
+
raise TriggerGroupInputError.new "invalid group name: '#{name}'"
|
81
72
|
end
|
82
73
|
if name.include?('_')
|
83
|
-
raise TriggerGroupInputError.new "
|
74
|
+
raise TriggerGroupInputError.new "group name '#{name}' can not include an underscore"
|
84
75
|
end
|
85
76
|
super("#{scope}#{PRIMARY_KEY}", name: name, scope: scope)
|
86
77
|
@microservice_name = "#{scope}__TRIGGER_GROUP__#{name}"
|
87
|
-
update_color(color: color)
|
88
78
|
@updated_at = updated_at
|
89
79
|
end
|
90
80
|
|
91
|
-
def
|
92
|
-
|
93
|
-
color = '#%06x' % (rand * 0xffffff)
|
94
|
-
end
|
95
|
-
valid_color = color =~ /[0-9a-fA-F]{6}/
|
96
|
-
if valid_color.nil?
|
97
|
-
raise TriggerGroupInputError.new "invalid color must be in hex format. #FF0000"
|
98
|
-
end
|
99
|
-
unless color.start_with?('#')
|
100
|
-
color = "##{color}"
|
101
|
-
end
|
102
|
-
@color = color
|
103
|
-
end
|
104
|
-
|
105
|
-
def create
|
106
|
-
unless Store.hget(@primary_key, @name).nil?
|
107
|
-
raise TriggerGroupInputError.new "exsisting TriggerGroup found: #{@name}"
|
108
|
-
end
|
109
|
-
@updated_at = Time.now.to_nsec_from_epoch
|
110
|
-
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
81
|
+
def create(update: false)
|
82
|
+
super(update: update)
|
111
83
|
notify(kind: 'created')
|
112
84
|
end
|
113
85
|
|
114
|
-
|
115
|
-
@updated_at = Time.now.to_nsec_from_epoch
|
116
|
-
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
117
|
-
notify(kind: 'updated')
|
118
|
-
end
|
119
|
-
|
120
|
-
# @return [String] generated from the TriggerGroupModel
|
86
|
+
# @return [String] generated from the TriggerModel
|
121
87
|
def to_s
|
122
|
-
return "
|
88
|
+
return "OpenC3::TriggerGroupModel:#{@scope}:#{@name})"
|
123
89
|
end
|
124
90
|
|
125
91
|
# @return [Hash] generated from the TriggerGroupModel
|
@@ -127,7 +93,6 @@ module OpenC3
|
|
127
93
|
return {
|
128
94
|
'name' => @name,
|
129
95
|
'scope' => @scope,
|
130
|
-
'color' => @color,
|
131
96
|
'updated_at' => @updated_at,
|
132
97
|
}
|
133
98
|
end
|
@@ -136,9 +101,7 @@ module OpenC3
|
|
136
101
|
def self.from_json(json, name:, scope:)
|
137
102
|
json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
|
138
103
|
raise "json data is nil" if json.nil?
|
139
|
-
|
140
|
-
json.transform_keys!(&:to_sym)
|
141
|
-
self.new(**json, name: name, scope: scope)
|
104
|
+
self.new(**json.transform_keys(&:to_sym), name: name, scope: scope)
|
142
105
|
end
|
143
106
|
|
144
107
|
# @return [] update the redis stream / trigger topic that something has changed
|
@@ -173,15 +136,18 @@ module OpenC3
|
|
173
136
|
topics = ["#{@scope}__openc3_autonomic"]
|
174
137
|
if MicroserviceModel.get_model(name: @microservice_name, scope: @scope).nil?
|
175
138
|
create_microservice(topics: topics)
|
139
|
+
notify(kind: 'deployed')
|
176
140
|
end
|
177
141
|
end
|
178
142
|
|
179
143
|
def undeploy
|
180
144
|
if TriggerModel.names(scope: scope, group: name).empty?
|
181
145
|
model = MicroserviceModel.get_model(name: @microservice_name, scope: @scope)
|
182
|
-
|
146
|
+
if model
|
147
|
+
model.destroy
|
148
|
+
notify(kind: 'undeployed')
|
149
|
+
end
|
183
150
|
end
|
184
151
|
end
|
185
|
-
|
186
152
|
end
|
187
153
|
end
|
@@ -17,17 +17,18 @@
|
|
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
|
require 'openc3/models/model'
|
24
24
|
require 'openc3/models/microservice_model'
|
25
25
|
require 'openc3/models/target_model'
|
26
|
+
require 'openc3/models/trigger_group_model'
|
27
|
+
require 'openc3/models/reaction_model'
|
26
28
|
require 'openc3/topics/autonomic_topic'
|
27
29
|
|
28
30
|
module OpenC3
|
29
31
|
class TriggerError < StandardError; end
|
30
|
-
|
31
32
|
class TriggerInputError < TriggerError; end
|
32
33
|
|
33
34
|
# INPUT:
|
@@ -38,6 +39,7 @@ module OpenC3
|
|
38
39
|
# "target": "INST",
|
39
40
|
# "packet": "ADCS",
|
40
41
|
# "item": "POSX",
|
42
|
+
# "valueType": "RAW",
|
41
43
|
# },
|
42
44
|
# "operator": ">",
|
43
45
|
# "right": {
|
@@ -51,13 +53,16 @@ module OpenC3
|
|
51
53
|
LIMIT_TYPE = 'limit'.freeze
|
52
54
|
FLOAT_TYPE = 'float'.freeze
|
53
55
|
STRING_TYPE = 'string'.freeze
|
56
|
+
REGEX_TYPE = 'regex'.freeze
|
54
57
|
TRIGGER_TYPE = 'trigger'.freeze
|
55
58
|
|
56
|
-
def self.
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
59
|
+
def self.create_unique_name(group:, scope:)
|
60
|
+
trigger_names = self.names(group: group, scope: scope) # comes back sorted
|
61
|
+
num = 1 # Users count with 1
|
62
|
+
if trigger_names[-1]
|
63
|
+
num = trigger_names[-1][4..-1].to_i + 1
|
64
|
+
end
|
65
|
+
return "TRIG#{num}"
|
61
66
|
end
|
62
67
|
|
63
68
|
# @return [TriggerModel] Return the object with the name at
|
@@ -82,10 +87,10 @@ module OpenC3
|
|
82
87
|
def self.delete(name:, group:, scope:)
|
83
88
|
model = self.get(name: name, group: group, scope: scope)
|
84
89
|
if model.nil?
|
85
|
-
raise TriggerInputError.new "
|
90
|
+
raise TriggerInputError.new "trigger #{group}:#{name} does not exist"
|
86
91
|
end
|
87
92
|
unless model.dependents.empty?
|
88
|
-
raise TriggerError.new "
|
93
|
+
raise TriggerError.new "#{group}:#{name} has dependents: #{model.dependents}"
|
89
94
|
end
|
90
95
|
model.roots.each do | trigger |
|
91
96
|
trigger_model = self.get(name: trigger, group: group, scope: scope)
|
@@ -93,24 +98,67 @@ module OpenC3
|
|
93
98
|
trigger_model.update()
|
94
99
|
end
|
95
100
|
Store.hdel("#{scope}#{PRIMARY_KEY}#{group}", name)
|
96
|
-
|
101
|
+
# No notification as this is only called via trigger_controller which already notifies
|
97
102
|
end
|
98
103
|
|
99
|
-
|
104
|
+
attr_reader :name, :scope, :state, :group, :enabled, :left, :operator, :right, :dependents, :roots
|
105
|
+
|
106
|
+
def initialize(
|
107
|
+
name:,
|
108
|
+
scope:,
|
109
|
+
group:,
|
110
|
+
left:,
|
111
|
+
operator:,
|
112
|
+
right:,
|
113
|
+
state: false,
|
114
|
+
enabled: true,
|
115
|
+
dependents: nil,
|
116
|
+
updated_at: nil
|
117
|
+
)
|
118
|
+
super("#{scope}#{PRIMARY_KEY}#{group}", name: name, scope: scope)
|
119
|
+
@roots = []
|
120
|
+
@group = group
|
121
|
+
@state = state
|
122
|
+
@enabled = enabled
|
123
|
+
@left = validate_operand(operand: left)
|
124
|
+
@operator = validate_operator(operator: operator)
|
125
|
+
@right = validate_operand(operand: right, right: true)
|
126
|
+
@dependents = dependents
|
127
|
+
@updated_at = updated_at
|
128
|
+
selected_group = TriggerGroupModel.get(name: @group, scope: @scope)
|
129
|
+
if selected_group.nil?
|
130
|
+
raise TriggerInputError.new "failed to find group: '#{@group}'"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Modifiers for the trigger_controller update action
|
135
|
+
def left=(left)
|
136
|
+
@left = validate_operand(operand: left)
|
137
|
+
end
|
138
|
+
def right=(right)
|
139
|
+
@right = validate_operand(operand: right, right: true)
|
140
|
+
end
|
141
|
+
def operator=(operator)
|
142
|
+
@operator = validate_operator(operator: operator)
|
143
|
+
end
|
144
|
+
|
145
|
+
def validate_operand(operand:, right: false)
|
146
|
+
return operand if right and @operator.include?('CHANGE')
|
100
147
|
unless operand.is_a?(Hash)
|
101
148
|
raise TriggerInputError.new "invalid operand: #{operand}"
|
102
149
|
end
|
103
|
-
operand_types = [ITEM_TYPE, LIMIT_TYPE, FLOAT_TYPE, STRING_TYPE, TRIGGER_TYPE]
|
150
|
+
operand_types = [ITEM_TYPE, LIMIT_TYPE, FLOAT_TYPE, STRING_TYPE, REGEX_TYPE, TRIGGER_TYPE]
|
104
151
|
unless operand_types.include?(operand['type'])
|
105
|
-
raise TriggerInputError.new "invalid operand type
|
152
|
+
raise TriggerInputError.new "invalid operand, type '#{operand['type']}' must be one of #{operand_types}"
|
106
153
|
end
|
107
154
|
if operand[operand['type']].nil?
|
108
|
-
raise TriggerInputError.new "invalid operand must
|
155
|
+
raise TriggerInputError.new "invalid operand, type value '#{operand['type']}' must be a key: #{operand}"
|
109
156
|
end
|
110
157
|
case operand['type']
|
111
158
|
when ITEM_TYPE
|
112
|
-
|
113
|
-
|
159
|
+
# We don't need to check for 'item' because the above check already does it
|
160
|
+
if operand['target'].nil? || operand['packet'].nil? || operand['valueType'].nil?
|
161
|
+
raise TriggerInputError.new "invalid operand, must contain target, packet, item and valueType: #{operand}"
|
114
162
|
end
|
115
163
|
when TRIGGER_TYPE
|
116
164
|
@roots << operand[operand['type']]
|
@@ -119,85 +167,25 @@ module OpenC3
|
|
119
167
|
end
|
120
168
|
|
121
169
|
def validate_operator(operator:)
|
122
|
-
|
123
|
-
raise TriggerInputError.new "invalid operator: #{operator}"
|
124
|
-
end
|
125
|
-
operators = ['>', '<', '>=', '<=']
|
126
|
-
match_operators = ['==', '!=']
|
170
|
+
operators = ['>', '<', '>=', '<=', '==', '!=', 'CHANGES', 'DOES NOT CHANGE']
|
127
171
|
trigger_operators = ['AND', 'OR']
|
128
172
|
if @roots.empty? && operators.include?(operator)
|
129
173
|
return operator
|
130
|
-
elsif
|
131
|
-
return operator
|
132
|
-
elsif @roots.size() == 2 && trigger_operators.include?(operator)
|
174
|
+
elsif !@roots.empty? && trigger_operators.include?(operator)
|
133
175
|
return operator
|
134
176
|
elsif operators.include?(operator)
|
135
|
-
raise TriggerInputError.new "invalid operator
|
177
|
+
raise TriggerInputError.new "invalid operator for triggers: '#{operator}' must be one of #{trigger_operators}"
|
136
178
|
else
|
137
|
-
raise TriggerInputError.new "invalid operator: '#{operator}' must be of
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def validate_description(description:)
|
142
|
-
if description.nil?
|
143
|
-
left_type = @left['type']
|
144
|
-
right_type = @right['type']
|
145
|
-
return "#{@left[left_type]} #{@operator} #{@right[right_type]}"
|
146
|
-
end
|
147
|
-
unless description.is_a?(String)
|
148
|
-
raise TriggerInputError.new "invalid description: #{description}"
|
149
|
-
end
|
150
|
-
return description
|
151
|
-
end
|
152
|
-
|
153
|
-
attr_reader :name, :scope, :state, :group, :active, :left, :operator, :right, :dependents, :roots
|
154
|
-
|
155
|
-
#
|
156
|
-
def initialize(
|
157
|
-
name:,
|
158
|
-
scope:,
|
159
|
-
group:,
|
160
|
-
left:,
|
161
|
-
operator:,
|
162
|
-
right:,
|
163
|
-
state: false,
|
164
|
-
active: true,
|
165
|
-
description: nil,
|
166
|
-
dependents: nil,
|
167
|
-
updated_at: nil
|
168
|
-
)
|
169
|
-
if name.nil? || scope.nil? || group.nil? || left.nil? || operator.nil? || right.nil?
|
170
|
-
raise TriggerInputError.new "#{name}, #{scope}, #{group}, #{left}, #{operator}, or #{right} must not be nil"
|
179
|
+
raise TriggerInputError.new "invalid operator: '#{operator}' must be one of #{operators}"
|
171
180
|
end
|
172
|
-
super("#{scope}#{PRIMARY_KEY}#{group}", name: name, scope: scope)
|
173
|
-
@roots = []
|
174
|
-
@group = group
|
175
|
-
@state = state
|
176
|
-
@active = active
|
177
|
-
@left = validate_operand(operand: left)
|
178
|
-
@right = validate_operand(operand: right)
|
179
|
-
@operator = validate_operator(operator: operator)
|
180
|
-
@description = validate_description(description: description)
|
181
|
-
@dependents = dependents
|
182
|
-
@updated_at = updated_at
|
183
181
|
end
|
184
182
|
|
185
183
|
def verify_triggers
|
186
|
-
unless @group.is_a?(String)
|
187
|
-
raise TriggerInputError.new "invalid group: #{@group}"
|
188
|
-
end
|
189
|
-
selected_group = OpenC3::TriggerGroupModel.get(name: @group, scope: @scope)
|
190
|
-
if selected_group.nil?
|
191
|
-
raise TriggerGroupInputError.new "failed to find group: #{@group}"
|
192
|
-
end
|
193
184
|
@dependents = [] if @dependents.nil?
|
194
185
|
@roots.each do | trigger |
|
195
186
|
model = TriggerModel.get(name: trigger, group: @group, scope: @scope)
|
196
187
|
if model.nil?
|
197
|
-
raise TriggerInputError.new "failed to find dependent trigger: #{trigger}"
|
198
|
-
end
|
199
|
-
if model.group != @group
|
200
|
-
raise TriggerInputError.new "failed group dependent trigger: #{trigger}"
|
188
|
+
raise TriggerInputError.new "failed to find dependent trigger: '#{@group}:#{trigger}'"
|
201
189
|
end
|
202
190
|
unless model.dependents.include?(@name)
|
203
191
|
model.update_dependents(dependent: @name)
|
@@ -208,7 +196,7 @@ module OpenC3
|
|
208
196
|
|
209
197
|
def create
|
210
198
|
unless Store.hget(@primary_key, @name).nil?
|
211
|
-
raise TriggerInputError.new "
|
199
|
+
raise TriggerInputError.new "existing trigger found: '#{@name}'"
|
212
200
|
end
|
213
201
|
verify_triggers()
|
214
202
|
@updated_at = Time.now.to_nsec_from_epoch
|
@@ -220,40 +208,31 @@ module OpenC3
|
|
220
208
|
verify_triggers()
|
221
209
|
@updated_at = Time.now.to_nsec_from_epoch
|
222
210
|
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
223
|
-
|
211
|
+
# No notification as this is only called via trigger_controller which already notifies
|
224
212
|
end
|
225
213
|
|
226
|
-
def
|
227
|
-
@state =
|
214
|
+
def state=(value)
|
215
|
+
@state = value
|
228
216
|
@updated_at = Time.now.to_nsec_from_epoch
|
229
217
|
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
218
|
+
notify(kind: @state.to_s)
|
219
|
+
end
|
220
|
+
|
221
|
+
def notify_enable
|
222
|
+
@enabled = true
|
230
223
|
notify(kind: 'enabled')
|
231
224
|
end
|
232
225
|
|
233
|
-
def
|
226
|
+
def notify_disable
|
227
|
+
@enabled = false
|
234
228
|
@state = false
|
235
|
-
@updated_at = Time.now.to_nsec_from_epoch
|
236
|
-
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
237
229
|
notify(kind: 'disabled')
|
238
230
|
end
|
239
231
|
|
240
|
-
def
|
241
|
-
|
242
|
-
@updated_at = Time.now.to_nsec_from_epoch
|
243
|
-
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
244
|
-
notify(kind: 'activated')
|
245
|
-
end
|
246
|
-
|
247
|
-
def deactivate
|
248
|
-
@active = false
|
249
|
-
@state = false
|
232
|
+
def disable
|
233
|
+
notify_disable()
|
250
234
|
@updated_at = Time.now.to_nsec_from_epoch
|
251
235
|
Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
|
252
|
-
notify(kind: 'deactivated')
|
253
|
-
end
|
254
|
-
|
255
|
-
def modify
|
256
|
-
raise "TODO"
|
257
236
|
end
|
258
237
|
|
259
238
|
# ["#{@scope}__DECOM__{#{@target}}__#{@packet}"]
|
@@ -262,7 +241,7 @@ module OpenC3
|
|
262
241
|
if @left['type'] == ITEM_TYPE
|
263
242
|
topics["#{@scope}__DECOM__{#{left['target']}}__#{left['packet']}"] = 1
|
264
243
|
end
|
265
|
-
if @right['type'] == ITEM_TYPE
|
244
|
+
if @right and @right['type'] == ITEM_TYPE
|
266
245
|
topics["#{@scope}__DECOM__{#{right['target']}}__#{right['packet']}"] = 1
|
267
246
|
end
|
268
247
|
return topics.keys
|
@@ -278,7 +257,7 @@ module OpenC3
|
|
278
257
|
|
279
258
|
# @return [String] generated from the TriggerModel
|
280
259
|
def to_s
|
281
|
-
return "
|
260
|
+
return "OpenC3::TriggerModel:#{@scope}:#{group}:#{@name})"
|
282
261
|
end
|
283
262
|
|
284
263
|
# @return [Hash] generated from the TriggerModel
|
@@ -287,9 +266,8 @@ module OpenC3
|
|
287
266
|
'name' => @name,
|
288
267
|
'scope' => @scope,
|
289
268
|
'state' => @state,
|
290
|
-
'
|
269
|
+
'enabled' => @enabled,
|
291
270
|
'group' => @group,
|
292
|
-
'description' => @description,
|
293
271
|
'dependents' => @dependents,
|
294
272
|
'left' => @left,
|
295
273
|
'operator' => @operator,
|
@@ -302,9 +280,7 @@ module OpenC3
|
|
302
280
|
def self.from_json(json, name:, scope:)
|
303
281
|
json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
|
304
282
|
raise "json data is nil" if json.nil?
|
305
|
-
|
306
|
-
json.transform_keys!(&:to_sym)
|
307
|
-
self.new(**json, name: name, scope: scope)
|
283
|
+
self.new(**json.transform_keys(&:to_sym), name: name, scope: scope)
|
308
284
|
end
|
309
285
|
|
310
286
|
# @return [] update the redis stream / trigger topic that something has changed
|
@@ -316,18 +292,5 @@ module OpenC3
|
|
316
292
|
}
|
317
293
|
AutonomicTopic.write_notification(notification, scope: @scope)
|
318
294
|
end
|
319
|
-
|
320
|
-
# @param [String] kind - the status such as "event" or "error"
|
321
|
-
# @param [String] message - an optional message to include in the event
|
322
|
-
def log(kind:, message: nil)
|
323
|
-
notification = {
|
324
|
-
'kind' => kind,
|
325
|
-
'type' => 'log',
|
326
|
-
'time' => Time.now.to_i,
|
327
|
-
'name' => @name,
|
328
|
-
}
|
329
|
-
notification['message'] = message unless message.nil?
|
330
|
-
AutonomicTopic.write_notification(notification, scope: @scope)
|
331
|
-
end
|
332
295
|
end
|
333
296
|
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
|
require 'openc3'
|
@@ -110,8 +110,7 @@ module OpenC3
|
|
110
110
|
value = @json_hash["#{name}__C"]
|
111
111
|
return value if value
|
112
112
|
end
|
113
|
-
|
114
|
-
return value if value
|
113
|
+
return @json_hash[name]
|
115
114
|
end
|
116
115
|
|
117
116
|
def read_with_limits_state(name, value_type = :CONVERTED, reduced_type = nil)
|
@@ -168,6 +168,16 @@ module OpenC3
|
|
168
168
|
_cmd('cmd_raw_no_checks', nil, *args, **kwargs)
|
169
169
|
end
|
170
170
|
|
171
|
+
# Builds a command binary
|
172
|
+
#
|
173
|
+
# Accepts two different calling styles:
|
174
|
+
# build_command("TGT CMD with PARAM1 val, PARAM2 val")
|
175
|
+
# build_command('TGT','CMD',{'PARAM1'=>val,'PARAM2'=>val})
|
176
|
+
def build_command(*args, **kwargs)
|
177
|
+
extract_string_kwargs_to_args(args, kwargs)
|
178
|
+
$api_server.build_command(*args)
|
179
|
+
end
|
180
|
+
|
171
181
|
# Returns whether the specified command is hazardous
|
172
182
|
#
|
173
183
|
# Accepts two different calling styles:
|
data/lib/openc3/script/script.rb
CHANGED
data/lib/openc3/top_level.rb
CHANGED
@@ -349,17 +349,6 @@ module OpenC3
|
|
349
349
|
return log_file
|
350
350
|
end
|
351
351
|
|
352
|
-
# Catch fatal exceptions within the block
|
353
|
-
# This is intended to catch exceptions before the GUI is available
|
354
|
-
def self.catch_fatal_exception
|
355
|
-
yield
|
356
|
-
rescue Exception => error
|
357
|
-
unless SystemExit === error or SignalException === error
|
358
|
-
Logger.level = Logger::FATAL
|
359
|
-
OpenC3.handle_fatal_exception(error, false)
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
352
|
# Write a message to the Logger, write an exception file, and popup a GUI
|
364
353
|
# window if try_gui. Finally 'exit 1' is called to end the calling program.
|
365
354
|
#
|
@@ -369,7 +358,6 @@ module OpenC3
|
|
369
358
|
unless SystemExit === error or SignalException === error
|
370
359
|
$openc3_fatal_exception = error
|
371
360
|
self.write_exception_file(error)
|
372
|
-
Logger.level = Logger::FATAL
|
373
361
|
Logger.fatal "Fatal Exception! Exiting..."
|
374
362
|
Logger.fatal error.formatted
|
375
363
|
if $stdout != STDOUT
|
@@ -43,7 +43,7 @@ rescue LoadError
|
|
43
43
|
if $openc3_authorize
|
44
44
|
raise AuthError.new("Token is required") unless token
|
45
45
|
unless OpenC3::AuthModel.verify(token, permission: permission)
|
46
|
-
raise AuthError.new("
|
46
|
+
raise AuthError.new("Password is invalid for '#{permission}' permission")
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -39,6 +39,8 @@ OpenC3.disable_warnings do
|
|
39
39
|
@bucket_require_cache[args[0]] = true
|
40
40
|
return true
|
41
41
|
end
|
42
|
+
rescue LoadError => err
|
43
|
+
raise err
|
42
44
|
rescue Exception => err
|
43
45
|
raise LoadError, "#{err.class}:#{err.message}", err.backtrace
|
44
46
|
end
|
@@ -57,7 +59,9 @@ OpenC3.disable_warnings do
|
|
57
59
|
scope = $openc3_scope
|
58
60
|
end
|
59
61
|
OpenC3::BucketUtilities.bucket_load(*args, scope: scope)
|
60
|
-
rescue
|
62
|
+
rescue LoadError => err
|
63
|
+
raise err
|
64
|
+
rescue Exception => err
|
61
65
|
raise LoadError, "#{err.class}:#{err.message}", err.backtrace
|
62
66
|
end
|
63
67
|
end
|
@@ -31,17 +31,20 @@ module OpenC3
|
|
31
31
|
DIRECTORY_TIMESTAMP_FORMAT = "%Y%m%d"
|
32
32
|
|
33
33
|
def self.bucket_load(*args, scope: $openc3_scope)
|
34
|
+
scope = ENV['OPENC3_SCOPE'] unless scope
|
35
|
+
scope = 'DEFAULT' unless scope
|
34
36
|
path = args[0]
|
35
37
|
|
36
38
|
# Only support TARGET files
|
37
39
|
if path[0] == '/' or path.split('/')[0].to_s.upcase != path.split('/')[0]
|
38
|
-
raise LoadError
|
40
|
+
raise LoadError, "only relative TARGET files are allowed -- #{path}"
|
39
41
|
end
|
40
42
|
extension = File.extname(path)
|
41
43
|
path = path + '.rb' if extension == ""
|
42
44
|
|
43
45
|
# Retrieve the text of the script from S3
|
44
46
|
text = TargetFile.body(scope, path)
|
47
|
+
raise LoadError, "Bucket file #{path} not found for scope #{scope}" unless text
|
45
48
|
|
46
49
|
# Execute the script directly without instrumentation because we are doing require/load
|
47
50
|
Object.class_eval(text, path, 1)
|