Class: OpenC3::CommandTopic

Inherits:
Topic show all
Defined in:
lib/openc3/topics/command_topic.rb

Constant Summary collapse

COMMAND_ACK_TIMEOUT_S =

TODO: This is in several places, should maybe be a parameter in settings?

30

Class Method Summary collapse

Methods inherited from Topic

all_same_db_shard?, clear_topics, del, get_cnt, get_last_offset, get_newest_message, get_oldest_message, group_topics_by_db_shard, method_missing, read_topics, trim_topic, update_topic_offsets, write_ack, write_topic

Class Method Details

.raise_critical_cmd_error(msg_hash, command) ⇒ Object



102
103
104
105
106
107
108
109
110
# File 'lib/openc3/topics/command_topic.rb', line 102

def self.raise_critical_cmd_error(msg_hash, command)
  _, uuid = msg_hash["result"].split("\n")
  # Create and populate a new CriticalCmdError and raise it up
  # The _cmd method in script/commands.rb rescues this and calls prompt_for_critical_cmd
  error = CriticalCmdError.new
  error.uuid = uuid
  error.command = command
  raise error
end

.raise_hazardous_error(msg_hash, command) ⇒ Object

PRIVATE implementation details



87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/openc3/topics/command_topic.rb', line 87

def self.raise_hazardous_error(msg_hash, command)
  _, description, formatted = msg_hash["result"].split("\n")
  # Create and populate a new HazardousError and raise it up
  # The _cmd method in script/commands.rb rescues this and calls prompt_for_hazardous
  error = HazardousError.new
  error.target_name = command["target_name"]
  error.cmd_name = command["cmd_name"]
  error.cmd_params = command["cmd_params"]
  error.hazardous_description = description
  error.formatted = formatted

  # No Logger.info because the error is already logged by the Logger.info "Ack Received ...
  raise error
end

.send_command(command, timeout: COMMAND_ACK_TIMEOUT_S, scope:, obfuscated_items: []) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/openc3/topics/command_topic.rb', line 43

def self.send_command(command, timeout: COMMAND_ACK_TIMEOUT_S, scope:, obfuscated_items: [])
  timeout = COMMAND_ACK_TIMEOUT_S unless timeout
  # Save the existing cmd_params Hash and JSON generate before writing to the topic
  cmd_params = command['cmd_params']
  command['cmd_params'] = JSON.generate(command['cmd_params'].as_json, allow_nan: true)
  OpenC3.inject_context(command)

  db_shard = Store.db_shard_for_target(command['target_name'], scope: scope)

  # Fire-and-forget mode: skip ACK waiting when timeout <= 0
  if timeout <= 0
    Topic.write_topic("{#{scope}__CMD}TARGET__#{command['target_name']}", command, '*', 100, db_shard: db_shard)
    command["cmd_params"] = cmd_params # Restore the original cmd_params Hash
    return command
  end

  ack_topic = "{#{scope}__ACKCMD}TARGET__#{command['target_name']}"
  Topic.update_topic_offsets([ack_topic], db_shard: db_shard)
  cmd_id = Topic.write_topic("{#{scope}__CMD}TARGET__#{command['target_name']}", command, '*', 100, db_shard: db_shard)
  command["cmd_params"] = cmd_params # Restore the original cmd_params Hash
  time = Time.now
  while (Time.now - time) < timeout
    Topic.read_topics([ack_topic], db_shard: db_shard) do |_topic, _msg_id, msg_hash, _redis|
      if msg_hash["id"] == cmd_id
        if msg_hash["result"] == "SUCCESS"
          return command
        # Check for HazardousError which is a special case
        elsif msg_hash["result"].include?("HazardousError")
          raise_hazardous_error(msg_hash, command)
        elsif msg_hash["result"].include?("CriticalCmdError")
          raise_critical_cmd_error(msg_hash, command)
        else
          raise msg_hash["result"]
        end
      end
    end
  end
  raise "Timeout of #{timeout}s waiting for cmd ack"
end

.write_packet(packet, scope:) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/openc3/topics/command_topic.rb', line 27

def self.write_packet(packet, scope:)
  topic = "#{scope}__COMMAND__{#{packet.target_name}}__#{packet.packet_name}"
  msg_hash = { time: packet.packet_time.to_nsec_from_epoch,
               received_time: packet.received_time.to_nsec_from_epoch,
               target_name: packet.target_name,
               packet_name: packet.packet_name,
               received_count: packet.received_count,
               stored: packet.stored.to_s,
               buffer: packet.buffer(false) }
  msg_hash[:extra] = JSON.generate(packet.extra.as_json, allow_nan: true) if packet.extra
  db_shard = Store.db_shard_for_target(packet.target_name, scope: scope)
  EphemeralStoreQueued.instance(db_shard: db_shard).write_topic(topic, msg_hash)
end