Class: OpenC3::TriggerModel

Inherits:
Model show all
Defined in:
lib/openc3/models/trigger_model.rb

Overview

INPUT:

{
  "group": "someGroup",
  "left": {
    "type": "item",
    "target": "INST",
    "packet": "ADCS",
    "item": "POSX",
  },
  "operator": ">",
  "right": {
    "type": "value",
    "value": 690000,
  }
}

Constant Summary collapse

PRIMARY_KEY =
'__TRIGGERS__'.freeze
ITEM_TYPE =
'item'.freeze
LIMIT_TYPE =
'limit'.freeze
FLOAT_TYPE =
'float'.freeze
STRING_TYPE =
'string'.freeze
TRIGGER_TYPE =
'trigger'.freeze

Instance Attribute Summary collapse

Attributes inherited from Model

#plugin, #updated_at

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Model

#as_config, #deploy, #destroy, #destroyed?, filter, find_all_by_plugin, get_all_models, get_model, handle_config, set, store, #undeploy

Constructor Details

#initialize(name:, scope:, group:, left:, operator:, right:, state: false, active: true, description: nil, dependents: nil, updated_at: nil) ⇒ TriggerModel



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/openc3/models/trigger_model.rb', line 153

def initialize(
  name:,
  scope:,
  group:,
  left:,
  operator:,
  right:,
  state: false,
  active: true,
  description: nil,
  dependents: nil,
  updated_at: nil
)
  if name.nil? || scope.nil? || group.nil? || left.nil? || operator.nil? || right.nil?
    raise TriggerInputError.new "#{name}, #{scope}, #{group}, #{left}, #{operator}, or #{right} must not be nil"
  end
  super("#{scope}#{PRIMARY_KEY}#{group}", name: name, scope: scope)
  @roots = []
  @group = group
  @state = state
  @active = active
  @left = validate_operand(operand: left)
  @right = validate_operand(operand: right)
  @operator = validate_operator(operator: operator)
  @description = validate_description(description: description)
  @dependents = dependents
  @updated_at = updated_at
end

Instance Attribute Details

#activeObject (readonly)

Returns the value of attribute active.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def active
  @active
end

#dependentsObject (readonly)

Returns the value of attribute dependents.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def dependents
  @dependents
end

#groupObject (readonly)

Returns the value of attribute group.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def group
  @group
end

#leftObject (readonly)

Returns the value of attribute left.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def left
  @left
end

#nameObject (readonly)

Returns the value of attribute name.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def name
  @name
end

#operatorObject (readonly)

Returns the value of attribute operator.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def operator
  @operator
end

#rightObject (readonly)

Returns the value of attribute right.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def right
  @right
end

#rootsObject (readonly)

Returns the value of attribute roots.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def roots
  @roots
end

#scopeObject (readonly)

Returns the value of attribute scope.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def scope
  @scope
end

#stateObject (readonly)

Returns the value of attribute state.



150
151
152
# File 'lib/openc3/models/trigger_model.rb', line 150

def state
  @state
end

Class Method Details

.all(group:, scope:) ⇒ Array<Hash>



69
70
71
# File 'lib/openc3/models/trigger_model.rb', line 69

def self.all(group:, scope:)
  super("#{scope}#{PRIMARY_KEY}#{group}")
end

.create_mini_idObject



53
54
55
56
57
58
# File 'lib/openc3/models/trigger_model.rb', line 53

def self.create_mini_id
  time = (Time.now.to_f * 10_000_000).to_i
  jitter = rand(10_000_000) 
  key = "#{jitter}#{time}".to_i.to_s(36)
  return "TV0-#{key}"
end

.delete(name:, group:, scope:) ⇒ Object

Check dependents before delete.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/openc3/models/trigger_model.rb', line 79

def self.delete(name:, group:, scope:)
  model = self.get(name: name, group: group, scope: scope)
  if model.nil?
    raise TriggerInputError.new "invalid operation group: #{group} trigger: #{name} not found"
  end
  unless model.dependents.empty?
    raise TriggerError.new "failed to delete #{name} dependents: #{model.dependents}"
  end
  model.roots.each do | trigger |
    trigger_model = self.get(name: trigger, group: group, scope: scope)
    trigger_model.update_dependents(dependent: name, remove: true)
    trigger_model.update()
  end
  Store.hdel("#{scope}#{PRIMARY_KEY}#{group}", name)
  model.notify(kind: 'deleted')
end

.from_json(json, name:, scope:) ⇒ TriggerModel



299
300
301
302
303
304
305
# File 'lib/openc3/models/trigger_model.rb', line 299

def self.from_json(json, name:, scope:)
  json = JSON.parse(json, :allow_nan => true, :create_additions => true) if String === json
  raise "json data is nil" if json.nil?

  json.transform_keys!(&:to_sym)
  self.new(**json, name: name, scope: scope)
end

.get(name:, group:, scope:) ⇒ TriggerModel



61
62
63
64
65
66
# File 'lib/openc3/models/trigger_model.rb', line 61

def self.get(name:, group:, scope:)
  json = super("#{scope}#{PRIMARY_KEY}#{group}", name: name)
  unless json.nil?
    self.from_json(json, name: name, scope: scope)
  end
end

.names(group:, scope:) ⇒ Array<String>



74
75
76
# File 'lib/openc3/models/trigger_model.rb', line 74

def self.names(group:, scope:)
  super("#{scope}#{PRIMARY_KEY}#{group}")
end

Instance Method Details

#activateObject



237
238
239
240
241
242
# File 'lib/openc3/models/trigger_model.rb', line 237

def activate
  @active = true
  @updated_at = Time.now.to_nsec_from_epoch
  Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
  notify(kind: 'activated')
end

#as_json(*a) ⇒ Hash



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/openc3/models/trigger_model.rb', line 282

def as_json(*a)
  return {
    'name' => @name,
    'scope' => @scope,
    'state' => @state,
    'active' => @active,
    'group' => @group,
    'description' => @description,
    'dependents' => @dependents,
    'left' => @left,
    'operator' => @operator,
    'right' => @right,
    'updated_at' => @updated_at,
  }
end

#createObject



206
207
208
209
210
211
212
213
214
# File 'lib/openc3/models/trigger_model.rb', line 206

def create
  unless Store.hget(@primary_key, @name).nil?
    raise TriggerInputError.new "exsisting Trigger found: #{@name}"
  end
  verify_triggers()
  @updated_at = Time.now.to_nsec_from_epoch
  Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
  notify(kind: 'created')
end

#deactivateObject



244
245
246
247
248
249
250
# File 'lib/openc3/models/trigger_model.rb', line 244

def deactivate
  @active = false
  @state = false
  @updated_at = Time.now.to_nsec_from_epoch
  Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
  notify(kind: 'deactivated')
end

#disableObject



230
231
232
233
234
235
# File 'lib/openc3/models/trigger_model.rb', line 230

def disable
  @state = false
  @updated_at = Time.now.to_nsec_from_epoch
  Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
  notify(kind: 'disabled')
end

#enableObject



223
224
225
226
227
228
# File 'lib/openc3/models/trigger_model.rb', line 223

def enable
  @state = true
  @updated_at = Time.now.to_nsec_from_epoch
  Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
  notify(kind: 'enabled')
end

#generate_topicsObject

“#@scope__DECOM__#{@target}__#@packet”


257
258
259
260
261
262
263
264
265
266
# File 'lib/openc3/models/trigger_model.rb', line 257

def generate_topics
  topics = Hash.new
  if @left['type'] == ITEM_TYPE
    topics["#{@scope}__DECOM__{#{left['target']}}__#{left['packet']}"] = 1
  end
  if @right['type'] == ITEM_TYPE
    topics["#{@scope}__DECOM__{#{right['target']}}__#{right['packet']}"] = 1
  end
  return topics.keys
end

#log(kind:, message: nil) ⇒ Object



319
320
321
322
323
324
325
326
327
328
# File 'lib/openc3/models/trigger_model.rb', line 319

def log(kind:, message: nil)
  notification = {
    'kind' => kind,
    'type' => 'log',
    'time' => Time.now.to_i,
    'name' => @name,
  }
  notification['message'] = message unless message.nil?
  AutonomicTopic.write_notification(notification, scope: @scope)
end

#modifyObject



252
253
254
# File 'lib/openc3/models/trigger_model.rb', line 252

def modify
  raise "TODO"
end

#notify(kind:) ⇒ Object



308
309
310
311
312
313
314
315
# File 'lib/openc3/models/trigger_model.rb', line 308

def notify(kind:)
  notification = {
    'kind' => kind,
    'type' => 'trigger',
    'data' => JSON.generate(as_json(:allow_nan => true)),
  }
  AutonomicTopic.write_notification(notification, scope: @scope)
end

#to_sString



277
278
279
# File 'lib/openc3/models/trigger_model.rb', line 277

def to_s
  return "(TriggerModel :: #{@name} :: #{group} :: #{@description})"
end

#updateObject



216
217
218
219
220
221
# File 'lib/openc3/models/trigger_model.rb', line 216

def update
  verify_triggers()
  @updated_at = Time.now.to_nsec_from_epoch
  Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
  notify(kind: 'updated')
end

#update_dependents(dependent:, remove: false) ⇒ Object



268
269
270
271
272
273
274
# File 'lib/openc3/models/trigger_model.rb', line 268

def update_dependents(dependent:, remove: false)
  if remove
    @dependents.delete(dependent)
  elsif @dependents.index(dependent).nil?
    @dependents << dependent
  end
end

#validate_description(description:) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
# File 'lib/openc3/models/trigger_model.rb', line 138

def validate_description(description:)
  if description.nil?
    left_type = @left['type']
    right_type = @right['type']
    return "#{@left[left_type]} #{@operator} #{@right[right_type]}"
  end
  unless description.is_a?(String)
    raise TriggerInputError.new "invalid description: #{description}"
  end
  return description
end

#validate_operand(operand:) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/openc3/models/trigger_model.rb', line 96

def validate_operand(operand:)
  unless operand.is_a?(Hash)
    raise TriggerInputError.new "invalid operand: #{operand}"
  end
  operand_types = [ITEM_TYPE, LIMIT_TYPE, FLOAT_TYPE, STRING_TYPE, TRIGGER_TYPE]
  unless operand_types.include?(operand['type'])
    raise TriggerInputError.new "invalid operand type: #{operand['type']} must be of type: #{operand_types}"
  end
  if operand[operand['type']].nil?
    raise TriggerInputError.new "invalid operand must contain type: #{operand}"
  end
  case operand['type']
  when ITEM_TYPE
    if operand['target'].nil? || operand['packet'].nil? || operand['raw'].nil?
      raise TriggerInputError.new "invalid operand must contain target, packet, item, and raw: #{operand}"
    end
  when TRIGGER_TYPE
    @roots << operand[operand['type']]
  end
  return operand
end

#validate_operator(operator:) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/openc3/models/trigger_model.rb', line 118

def validate_operator(operator:)
  unless operator.is_a?(String)
    raise TriggerInputError.new "invalid operator: #{operator}"
  end
  operators = ['>', '<', '>=', '<=']
  match_operators = ['==', '!=']
  trigger_operators = ['AND', 'OR']
  if @roots.empty? && operators.include?(operator)
    return operator
  elsif @roots.empty? && match_operators.include?(operator)
    return operator
  elsif @roots.size() == 2 && trigger_operators.include?(operator)
    return operator
  elsif operators.include?(operator)
    raise TriggerInputError.new "invalid operator pair: '#{operator}' must be of type: #{trigger_operators}"
  else
    raise TriggerInputError.new "invalid operator: '#{operator}' must be of type: #{operators}"
  end
end

#verify_triggersObject



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/openc3/models/trigger_model.rb', line 182

def verify_triggers
  unless @group.is_a?(String)
    raise TriggerInputError.new "invalid group: #{@group}"
  end
  selected_group = OpenC3::TriggerGroupModel.get(name: @group, scope: @scope)
  if selected_group.nil?
    raise TriggerGroupInputError.new "failed to find group: #{@group}"
  end
  @dependents = [] if @dependents.nil?
  @roots.each do | trigger |
    model = TriggerModel.get(name: trigger, group: @group, scope: @scope)
    if model.nil?
      raise TriggerInputError.new "failed to find dependent trigger: #{trigger}"
    end
    if model.group != @group
      raise TriggerInputError.new "failed group dependent trigger: #{trigger}"
    end
    unless model.dependents.include?(@name)
      model.update_dependents(dependent: @name)
      model.update()
    end
  end
end