openc3 5.8.1 → 5.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/ext/openc3/ext/crc/crc.c +1 -1
  3. data/lib/openc3/api/cmd_api.rb +1 -1
  4. data/lib/openc3/microservices/decom_microservice.rb +10 -2
  5. data/lib/openc3/microservices/reaction_microservice.rb +152 -81
  6. data/lib/openc3/microservices/timeline_microservice.rb +1 -1
  7. data/lib/openc3/microservices/trigger_group_microservice.rb +188 -118
  8. data/lib/openc3/migrations/20230615000000_autonomic.rb +86 -0
  9. data/lib/openc3/models/activity_model.rb +2 -4
  10. data/lib/openc3/models/microservice_model.rb +6 -2
  11. data/lib/openc3/models/model.rb +1 -3
  12. data/lib/openc3/models/reaction_model.rb +124 -119
  13. data/lib/openc3/models/scope_model.rb +15 -3
  14. data/lib/openc3/models/timeline_model.rb +1 -3
  15. data/lib/openc3/models/trigger_group_model.rb +16 -50
  16. data/lib/openc3/models/trigger_model.rb +86 -123
  17. data/lib/openc3/packets/json_packet.rb +2 -3
  18. data/lib/openc3/script/commands.rb +10 -0
  19. data/lib/openc3/script/script.rb +1 -0
  20. data/lib/openc3/top_level.rb +0 -12
  21. data/lib/openc3/utilities/authorization.rb +1 -1
  22. data/lib/openc3/utilities/bucket_require.rb +5 -1
  23. data/lib/openc3/utilities/bucket_utilities.rb +4 -1
  24. data/lib/openc3/utilities/cli_generator.rb +56 -4
  25. data/lib/openc3/utilities/ruby_lex_utils.rb +4 -0
  26. data/lib/openc3/version.rb +6 -6
  27. data/templates/plugin/README.md +54 -4
  28. data/templates/plugin/Rakefile +31 -3
  29. data/templates/tool_angular/.editorconfig +16 -0
  30. data/templates/tool_angular/.gitignore +44 -0
  31. data/templates/tool_angular/.vscode/extensions.json +4 -0
  32. data/templates/tool_angular/.vscode/launch.json +20 -0
  33. data/templates/tool_angular/.vscode/tasks.json +42 -0
  34. data/templates/tool_angular/angular.json +111 -0
  35. data/templates/tool_angular/extra-webpack.config.js +8 -0
  36. data/templates/tool_angular/package.json +47 -0
  37. data/templates/tool_angular/src/app/app-routing.module.ts +15 -0
  38. data/templates/tool_angular/src/app/app.component.html +31 -0
  39. data/templates/tool_angular/src/app/app.component.scss +26 -0
  40. data/templates/tool_angular/src/app/app.component.spec.ts +29 -0
  41. data/templates/tool_angular/src/app/app.component.ts +51 -0
  42. data/templates/tool_angular/src/app/app.module.ts +30 -0
  43. data/templates/tool_angular/src/app/custom-overlay-container.ts +17 -0
  44. data/templates/tool_angular/src/app/empty-route/empty-route.component.ts +7 -0
  45. data/templates/tool_angular/src/app/openc3-api.d.ts +1 -0
  46. data/templates/tool_angular/src/assets/.gitkeep +0 -0
  47. data/templates/tool_angular/src/environments/environment.prod.ts +3 -0
  48. data/templates/tool_angular/src/environments/environment.ts +16 -0
  49. data/templates/tool_angular/src/favicon.ico +0 -0
  50. data/templates/tool_angular/src/index.html +13 -0
  51. data/templates/tool_angular/src/main.single-spa.ts +40 -0
  52. data/templates/tool_angular/src/single-spa/asset-url.ts +12 -0
  53. data/templates/tool_angular/src/single-spa/single-spa-props.ts +8 -0
  54. data/templates/tool_angular/src/styles.scss +1 -0
  55. data/templates/tool_angular/tsconfig.app.json +13 -0
  56. data/templates/tool_angular/tsconfig.json +33 -0
  57. data/templates/tool_angular/tsconfig.spec.json +14 -0
  58. data/templates/tool_angular/yarn.lock +8080 -0
  59. data/templates/tool_react/.eslintrc +7 -0
  60. data/templates/tool_react/.gitignore +72 -0
  61. data/templates/tool_react/.prettierignore +8 -0
  62. data/templates/tool_react/babel.config.json +29 -0
  63. data/templates/tool_react/jest.config.js +12 -0
  64. data/templates/tool_react/package.json +53 -0
  65. data/templates/tool_react/src/openc3-tool_name.js +24 -0
  66. data/templates/tool_react/src/root.component.js +88 -0
  67. data/templates/tool_react/src/root.component.test.js +9 -0
  68. data/templates/tool_react/webpack.config.js +27 -0
  69. data/templates/tool_react/yarn.lock +6854 -0
  70. data/templates/tool_svelte/.gitignore +72 -0
  71. data/templates/tool_svelte/.prettierignore +8 -0
  72. data/templates/tool_svelte/babel.config.js +12 -0
  73. data/templates/tool_svelte/build/smui.css +5 -0
  74. data/templates/tool_svelte/jest.config.js +9 -0
  75. data/templates/tool_svelte/package.json +46 -0
  76. data/templates/tool_svelte/rollup.config.js +72 -0
  77. data/templates/tool_svelte/src/App.svelte +42 -0
  78. data/templates/tool_svelte/src/App.test.js +9 -0
  79. data/templates/tool_svelte/src/services/api.js +92 -0
  80. data/templates/tool_svelte/src/services/axios.js +85 -0
  81. data/templates/tool_svelte/src/services/cable.js +65 -0
  82. data/templates/tool_svelte/src/services/config-parser.js +199 -0
  83. data/templates/tool_svelte/src/services/openc3-api.js +647 -0
  84. data/templates/tool_svelte/src/theme/_smui-theme.scss +25 -0
  85. data/templates/tool_svelte/src/tool_name.js +17 -0
  86. data/templates/tool_svelte/yarn.lock +5052 -0
  87. data/templates/tool_vue/.browserslistrc +16 -0
  88. data/templates/tool_vue/.env.standalone +1 -0
  89. data/templates/tool_vue/.eslintrc.js +43 -0
  90. data/templates/tool_vue/.gitignore +2 -0
  91. data/templates/tool_vue/.nycrc +3 -0
  92. data/templates/tool_vue/.prettierrc.js +5 -0
  93. data/templates/tool_vue/babel.config.json +11 -0
  94. data/templates/tool_vue/jsconfig.json +6 -0
  95. data/templates/tool_vue/package.json +52 -0
  96. data/templates/tool_vue/src/App.vue +15 -0
  97. data/templates/tool_vue/src/main.js +38 -0
  98. data/templates/tool_vue/src/router.js +29 -0
  99. data/templates/tool_vue/src/tools/tool_name/tool_name.vue +63 -0
  100. data/templates/tool_vue/vue.config.js +30 -0
  101. data/templates/tool_vue/yarn.lock +9145 -0
  102. data/templates/widget/package.json +9 -9
  103. data/templates/widget/yarn.lock +77 -73
  104. 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 "invalid group: #{name} not found"
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 "failed to delete #{name} triggers: #{triggers}"
63
+ raise TriggerGroupError.new "group '#{name}' has dependent triggers: #{triggers}"
70
64
  end
71
65
  end
72
66
 
73
- attr_reader :name, :scope, :color, :updated_at
67
+ attr_reader :name, :scope, :updated_at
74
68
 
75
- def initialize(name:, scope:, color: nil, updated_at: nil)
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 "invalid name: '#{name}' can not include an underscore '_'"
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 update_color(color: nil)
92
- if color.nil?
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
- def update
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 "(TriggerGroupModel :: #{@name})"
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
- model.destroy if model
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.create_mini_id
57
- time = (Time.now.to_f * 10_000_000).to_i
58
- jitter = rand(10_000_000)
59
- key = "#{jitter}#{time}".to_i.to_s(36)
60
- return "TV0-#{key}"
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 "invalid operation group: #{group} trigger: #{name} not found"
90
+ raise TriggerInputError.new "trigger #{group}:#{name} does not exist"
86
91
  end
87
92
  unless model.dependents.empty?
88
- raise TriggerError.new "failed to delete #{name} dependents: #{model.dependents}"
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
- model.notify(kind: 'deleted')
101
+ # No notification as this is only called via trigger_controller which already notifies
97
102
  end
98
103
 
99
- def validate_operand(operand:)
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: #{operand['type']} must be of type: #{operand_types}"
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 contain type: #{operand}"
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
- if operand['target'].nil? || operand['packet'].nil? || operand['raw'].nil?
113
- raise TriggerInputError.new "invalid operand must contain target, packet, item, and raw: #{operand}"
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
- unless operator.is_a?(String)
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 @roots.empty? && match_operators.include?(operator)
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 pair: '#{operator}' must be of type: #{trigger_operators}"
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 type: #{operators}"
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 "exsisting Trigger found: #{@name}"
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
- notify(kind: 'updated')
211
+ # No notification as this is only called via trigger_controller which already notifies
224
212
  end
225
213
 
226
- def enable
227
- @state = true
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 disable
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 activate
241
- @active = true
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 "(TriggerModel :: #{@name} :: #{group} :: #{@description})"
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
- 'active' => @active,
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
- value = @json_hash[name]
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:
@@ -38,6 +38,7 @@ require 'openc3/script/plugins'
38
38
  require 'openc3/utilities/authentication'
39
39
 
40
40
  $api_server = nil
41
+ $script_runner_api_server = nil
41
42
  $disconnect = false
42
43
  $openc3_scope = ENV['OPENC3_SCOPE'] || 'DEFAULT'
43
44
  $openc3_in_cluster = false
@@ -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("Current role is invalid for '#{permission}' permission")
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 Exception
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)