Class: OpenC3::ReactionModel

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

Overview

{

  "description": "POSX greater than 200",
  "snooze": 300,
  "review": true,
  "triggers": [
    {
      "name": "TV0-1234",
      "group": "foo",
    }
  ],
  "actions": [
    {
      "type": "command",
      "value": "INST CLEAR",
    }
  ]
}

Constant Summary collapse

PRIMARY_KEY =
'__openc3__reaction'.freeze
COMMAND_REACTION =
'command'.freeze
SCRIPT_REACTION =
'script'.freeze

Instance Attribute Summary collapse

Attributes inherited from Model

#plugin, #updated_at

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Model

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

Constructor Details

#initialize(name:, scope:, description:, snooze:, actions:, triggers:, active: true, review: true, snoozed_until: nil, username: nil, updated_at: nil) ⇒ ReactionModel



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/openc3/models/reaction_model.rb', line 165

def initialize(
  name:,
  scope:,
  description:,
  snooze:,
  actions:,
  triggers:,
  active: true,
  review: true,
  snoozed_until: nil,
  username: nil,
  updated_at: nil
)
  if name.nil? || scope.nil? || description.nil? || snooze.nil? || triggers.nil? || actions.nil?
    raise ReactionInputError.new "#{name}, #{scope}, #{description}, #{snooze}, #{triggers}, or #{actions} must not be nil"
  end
  super("#{scope}#{PRIMARY_KEY}", name: name, scope: scope)
  @microservice_name = "#{scope}__OPENC3__REACTION"
  @active = active
  @review = review
  @description = description
  @snoozed_until = snoozed_until
  @snooze = validate_snooze(snooze: snooze)
  @actions = validate_actions(actions: actions)
  @triggers = validate_triggers(triggers: triggers)
  @username = username
  @updated_at = updated_at
end

Instance Attribute Details

#actionsObject (readonly)

Returns the value of attribute actions.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def actions
  @actions
end

#activeObject (readonly)

Returns the value of attribute active.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def active
  @active
end

#descriptionObject (readonly)

Returns the value of attribute description.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def description
  @description
end

#nameObject (readonly)

Returns the value of attribute name.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def name
  @name
end

#reviewObject (readonly)

Returns the value of attribute review.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def review
  @review
end

#scopeObject (readonly)

Returns the value of attribute scope.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def scope
  @scope
end

#snoozeObject (readonly)

Returns the value of attribute snooze.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def snooze
  @snooze
end

#snoozed_untilObject (readonly)

Returns the value of attribute snoozed_until.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def snoozed_until
  @snoozed_until
end

#triggersObject (readonly)

Returns the value of attribute triggers.



162
163
164
# File 'lib/openc3/models/reaction_model.rb', line 162

def triggers
  @triggers
end

#usernameObject

Returns the value of attribute username.



163
164
165
# File 'lib/openc3/models/reaction_model.rb', line 163

def username
  @username
end

Class Method Details

.all(scope:) ⇒ Array<Hash>



82
83
84
# File 'lib/openc3/models/reaction_model.rb', line 82

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

.create_mini_idObject



55
56
57
58
59
60
# File 'lib/openc3/models/reaction_model.rb', line 55

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 "RV0-#{key}"
end

.delete(name:, scope:, force: false) ⇒ Object

Check dependents before delete.



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/openc3/models/reaction_model.rb', line 92

def self.delete(name:, scope:, force: false)
  model = self.get(name: name, scope: scope)
  if model.nil?
    raise ReactionInputError.new "failed to find reaction: #{name}"
  end
  model.triggers.each do | trigger |
    trigger_model = TriggerModel.get(name: trigger['name'], group: trigger['group'], scope: scope)
    trigger_model.update_dependents(dependent: name, remove: true)
    trigger_model.update()
  end
  Store.hdel("#{scope}#{PRIMARY_KEY}", name)
  model.notify(kind: 'deleted')
end

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



281
282
283
284
285
286
287
# File 'lib/openc3/models/reaction_model.rb', line 281

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:, scope:) ⇒ ReactionModel



74
75
76
77
78
79
# File 'lib/openc3/models/reaction_model.rb', line 74

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

.names(scope:) ⇒ Array<String>



87
88
89
# File 'lib/openc3/models/reaction_model.rb', line 87

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

.reactions(scope:) ⇒ Array<ReactionModel>



63
64
65
66
67
68
69
70
71
# File 'lib/openc3/models/reaction_model.rb', line 63

def self.reactions(scope:)
  reactions = Array.new
  Store.hgetall("#{scope}#{PRIMARY_KEY}").each do |key, value|
    data = JSON.parse(value, :allow_nan => true, :create_additions => true)
    reaction = self.from_json(data, name: data['name'], scope: data['scope'])
    reactions << reaction if reaction.active
  end
  return reactions
end

Instance Method Details

#activateObject



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

def activate
  @active = true
  @snoozed_until = nil if @snoozed_until && @snoozed_until < Time.now.to_i
  @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



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/openc3/models/reaction_model.rb', line 264

def as_json(*a)
  return {
    'name' => @name,
    'scope' => @scope,
    'active' => @active,
    'review' => @review,
    'description' => @description,
    'snooze' => @snooze,
    'snoozed_until' => @snoozed_until,
    'triggers' => @triggers,
    'actions' => @actions,
    'username' => @username,
    'updated_at' => @updated_at
  }
end

#awakenObject



251
252
253
254
255
256
# File 'lib/openc3/models/reaction_model.rb', line 251

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

#createObject



212
213
214
215
216
217
218
219
220
# File 'lib/openc3/models/reaction_model.rb', line 212

def create
  unless Store.hget(@primary_key, @name).nil?
    raise ReactionInputError.new "exsisting Reaction 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

#create_microservice(topics:) ⇒ Object



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/openc3/models/reaction_model.rb', line 299

def create_microservice(topics:)
  # reaction Microservice
  microservice = MicroserviceModel.new(
    name: @microservice_name,
    folder_name: nil,
    cmd: ['ruby', 'reaction_microservice.rb', @microservice_name],
    work_dir: '/openc3/lib/openc3/microservices',
    options: [],
    topics: topics,
    target_names: [],
    plugin: nil,
    scope: @scope
  )
  microservice.create
end

#deactivateObject



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

def deactivate
  @active = 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

#deployObject



315
316
317
318
319
320
# File 'lib/openc3/models/reaction_model.rb', line 315

def deploy
  topics = ["#{@scope}__openc3_autonomic"]
  if MicroserviceModel.get_model(name: @microservice_name, scope: @scope).nil?
    create_microservice(topics: topics)
  end
end

#notify(kind:) ⇒ Object



290
291
292
293
294
295
296
297
# File 'lib/openc3/models/reaction_model.rb', line 290

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

#sleepObject



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

def sleep
  @snoozed_until = Time.now.to_i + @snooze
  @updated_at = Time.now.to_nsec_from_epoch
  Store.hset(@primary_key, @name, JSON.generate(as_json(:allow_nan => true)))
  notify(kind: 'sleep')
end

#to_sString



259
260
261
# File 'lib/openc3/models/reaction_model.rb', line 259

def to_s
  return "(ReactionModel :: #{@name} :: #{@active} :: #{@review} :: #{@description} :: #{@snooze} :: #{@snoozed_until})"
end

#undeployObject



322
323
324
325
326
327
# File 'lib/openc3/models/reaction_model.rb', line 322

def undeploy
  if ReactionModel.names(scope: @scope).empty?
    model = MicroserviceModel.get_model(name: @microservice_name, scope: @scope)
    model.destroy if model
  end
end

#updateObject



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

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

#validate_actions(actions:) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/openc3/models/reaction_model.rb', line 141

def validate_actions(actions:)
  unless actions.is_a?(Array)
    raise ReactionInputError.new "invalid actions object: #{actions}"
  end
  actions.each do | action |
    unless action.is_a?(Hash)
      raise ReactionInputError.new "invalid action object: #{action}"
    end
    action_type = action['type']
    if action_type.nil?
      raise ReactionInputError.new "reaction action must contain type: #{action_type}"
    elsif action['value'].nil?
      raise ReactionInputError.new "reaction action: #{action} does not contain 'value'"
    end
    unless [COMMAND_REACTION, SCRIPT_REACTION].include?(action_type)
      raise ReactionInputError.new "reaction action contains invalid type: #{action_type}"
    end
  end
  return actions
end

#validate_snooze(snooze:) ⇒ Object



107
108
109
110
111
112
113
114
115
# File 'lib/openc3/models/reaction_model.rb', line 107

def validate_snooze(snooze:)
  unless snooze.is_a?(Integer)
    raise ReactionInputError.new "invalid snooze value: #{snooze}"
  end
  if snooze < 30
    raise ReactionInputError.new "invalid snooze: '#{snooze}' must be greater than 30"
  end
  return snooze
end

#validate_triggers(triggers:) ⇒ Object



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

def validate_triggers(triggers:)
  unless triggers.is_a?(Array)
    raise ReactionInputError.new "invalid operator: #{operator}"
  end
  trigger_hash = Hash.new()
  triggers.each do | trigger |
    unless trigger.is_a?(Hash)
      raise ReactionInputError.new "invalid trigger object: #{trigger}"
    end
    if trigger['name'].nil? || trigger['group'].nil?
      raise ReactionInputError.new "allowed: #{triggers}"
    end
    trigger_name = trigger['name']
    unless trigger_hash[trigger_name].nil?
      raise ReactionInputError.new "no duplicate triggers allowed: #{triggers}"
    else
      trigger_hash[trigger_name] = 1
    end
  end
  return triggers
end

#verify_triggersObject



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/openc3/models/reaction_model.rb', line 194

def verify_triggers
  trigger_models = []
  @triggers.each do | trigger |
    model = TriggerModel.get(name: trigger['name'], group: trigger['group'], scope: @scope)
    if model.nil?
      raise ReactionInputError.new "failed to find trigger: #{trigger}"
    end
    trigger_models << model
  end
  if trigger_models.empty?
    raise ReactionInputError.new "reaction must contain at least one valid trigger: #{@triggers}"
  end
  trigger_models.each do | trigger_model |
    trigger_model.update_dependents(dependent: @name)
    trigger_model.update()
  end
end