Ravn::BDE::
MissionController
class
Main loop and workflow manager for the BDE. This object has two main jobs:
-
it serves as the trunk of the supervision tree, starting each of the pieces of the BDE beneath it.
-
it reflects events coming up the tree back down to the branches other than the sender.
- CP_VERSION
The path to the hardware image’s version file.
- beacon_timer R
The object’s beacon timer
- bolt_runner R
The Actor managing startup and running of Bolts
- config R
The mission configuration
- device_manager R
The Actor managing the Ravn::HAL::Manager
- event_count RW
The number of events which have crossed the bus.
- event_logger R
The Actor responsible for logging events to disk.
- gateway_manager R
The Actor responsible for starting any configured gateways
- net_broker R
The Actor managing the Ravn::Net::Broker
for net-bound messages
- start_time R
The monotonic time of the BDE’s startup
- state_manager R
The Actor managing per-run state
Create a new BDE::MissionController for the mission contained in mission_file
.
def initialize
@start_time = Ravn.monotonic_time
@event_count = 0
@beacon_timer = self.get_beacon_timer
@config = nil
@state_manager = nil
@net_broker = nil
@device_manager = nil
@bolt_runner = nil
@event_logger = nil
@gateway_manager = nil
super
end
Return an information hash for beacon messages.
def beacon_info
return { uptime: self.uptime, event_count: self.event_count }
end
Issue an event with any static POIs that are preconfigured as part of the mission.
def emit_pois_event
pois = self.config[ :pois ] or return
payload = pois.each_with_object( {} ) do |poi, acc|
acc[ poi[:name] ] = poi.values_at( :latitude, :longitude )
end
msg = Ravn::BDE::Message.new( 'sys.pois', data: payload )
self.tell( msg )
end
Generate and issue an event indicating all controller components are instantiated and ready.
def emit_startup_event
startup_info = {
callsign: Ravn::BDE.callsign,
system_time: Ravn.time,
monotonic_time: Ravn.monotonic_time,
device_id: Ravn.device_id,
mission: Ravn::BDE.mission,
network: {
'interface' => Ravn::Net.interface,
'ip_address' => Zyre.interfaces[ Ravn::Net.interface ]&.dig( :address )
},
versions: {
'ravn' => Ravn::VERSION,
'ravn-bde' => Ravn::BDE::VERSION,
'ravn-hal' => Ravn::HAL::VERSION,
'ravn-net' => Ravn::Net::VERSION,
'ruby' => RbConfig::CONFIG[ 'ruby_version' ],
'concurrent' => Concurrent::VERSION,
'mdbx' => MDBX::VERSION,
'libmdbx' => MDBX::LIBRARY_VERSION,
'sqlite' => SQLite3::VERSION,
'zyre' => Zyre::VERSION,
'cp_image' => CP_VERSION.readable? ? CP_VERSION.read : 'v?.?.?'
},
}
Ravn::BDE::Beacon.send_message( type: 'startup', **startup_info )
msg = Ravn::BDE::Message.new( 'sys.startup', data: startup_info )
self.tell( msg )
end
Reflect messages coming up the tree back down.
def filter_up( message )
message.audit {}
self.event_count += 1
self.reflect_message( message )
end
Start a timer that will periodically send a status beacon
def get_beacon_timer
timer = Concurrent::TimerTask.new do
self.tell( send_status_beacon: true )
end
timer.execution_interval = Ravn::BDE::Beacon.status_interval
self.log.info "Created beacon timer: %p" % [ timer ]
return timer
end
handle_send_status_beacon( * )
Send a periodic beacon with the BDE’s status.
def handle_send_status_beacon( * )
self.log.debug "Sending a status beacon: %p" % [ self ]
info = self.beacon_info
info[ :peers ] = self.net_broker.ask!( peer_map: true )
Ravn::BDE::Beacon.send_message( type: 'status', **info )
rescue => err
self.log.error "%p while building status beacon: %s" % [ err.class, err.message ]
self.log.debug( err.full_message(order: :bottom) )
end
Provide the details section of the inspect output.
def inspect_details
return " [%s] %d events, started: %0.3f" %
[ Ravn::BDE.callsign, self.event_count || 0, self.start_time || 0.0 ]
end
Actor lifecycle callback — handle some lifecycle +event+s.
def on_event( message )
event, _ = *message
self.log.info "Got event: %p" % [ event ]
case event
when Exception
info = self.beacon_info
Ravn::BDE::Beacon.send_exception( event, type: 'shutdown', **info )
when :terminated
info = self.beacon_info
Ravn::BDE::Beacon.send_message( type: 'shutdown', cause: "Terminated.", **info )
else
end
super
end
Handle mesh.stop events explicitly.
def on_message( message )
if self.net_broker && message.respond_to?( :type ) && message.type == 'mesh.stop'
self.net_broker&.ask!( :pause! )
self.log.warn "Zyre shut down; restarting!"
self.net_broker&.tell( :restart! )
end
super
end
Start the mission controller.
def start
self.log.warn "Starting %p" % [ self ]
@config = Ravn::BDE.load_mission_config
@state_manager = Ravn::BDE::StateManager.spawn!( :state_manager )
@net_broker = Ravn::BDE::NetBroker.spawn!( :net_broker, Ravn::BDE.callsign )
@device_manager = Ravn::BDE::DeviceManager.spawn!( :device_manager )
@bolt_runner = Ravn::BDE::BoltRunner.spawn!( :bolt_runner, @config )
@event_logger = Ravn::BDE::EventLogger.spawn!( :event_logger )
@gateway_manager = Ravn::BDE::GatewayManager.spawn!( :gateway_manager )
self.emit_startup_event
self.emit_pois_event
self.beacon_timer.execute
end
Return the number of seconds since the MissionController
started.
def uptime
self.log.debug "Start time is: %p" % [ self.start_time ]
return 0 unless self.start_time
return Ravn.monotonic_time - self.start_time
end