Ravn::BDE::Bolt::
ReadReceipts
module
Automated read receipts Bolt
component
Emits: - direct.bolt.read.$bolt_id
Consumes: - direct.bolt.read.$bolt_id - bolt.read.$bolt_id
- expires_at RW
The Monotonic time at which the extended bolt will finish even if it hasn’t seen all required receipts
apply( bolt_class, from: :default )
Add some response-specific configuration to bolts that have receipts.
def self::apply( bolt_class, from: :default )
super
bolt_class.stateful_variable :expected_receipts, default: {}
self.log.debug "Applying read receipts from %p to %p" % [ self, bolt_class ]
from_segment = bolt_class.segment_for_config( from )
bolt_class.singleton_attr_accessor( :receipts_from )
bolt_class.receipts_from = from_segment
end
all_receipts_receieved?()
Returns true
if all expected receipts have been received.
def all_receipts_receieved?
times = self.expected_receipts&.values or return false
return times.all?
end
convert_read_event( event )
Convert bolt.read.* events into direct.bolt.read.* events.
def convert_read_event( event )
if self.is_target_of?( event )
data = {
instance_id: event.data[:instance_id]
}
fields = { to: event.data[:callsign], data: data }
self.send_message( 'direct.bolt.read.${bolt_id}', fields )
end
end
event_payload_for( phase, originating_event )
Return the ‘data’ section for the bolt message emitted during the given phase
.
def event_payload_for( phase, originating_event )
payload = super
case phase
when :send
payload[ :expected_receipts ] = self.expected_receipts
when :summarize
if originating_event.type.start_with?( 'direct.bolt.read' )
callsign = originating_event.callsign
payload[ :expected_receipts ] = { callsign => self.expected_receipts[ callsign ] }
end
end
return payload
end
Returns true
if the bolt should be terminated and saved to history.
def ready_to_be_finished?
return super && self.all_receipts_receieved?
end
recipient_segment_members()
Fetch the map of who receipts are expected from at the current moment as a Hash keyed by callsign.
def recipient_segment_members
segment_members = self.class.receipts_from.to_h
segment_members.delete( Ravn::BDE.callsign )
return segment_members
end
Overloaded to set up the expected responses table.
def send_phase( event )
self.expected_receipts = self.recipient_segment_members
self.log.debug "Expecting receipts from %d recipients" % [ self.expected_receipts.size ]
super
end
Overloaded to record read receipt events. This may finish the bolt (via super
) if it was the last expected response.
def summarize_phase( event )
if self.is_target_of?( event )
if event.type.start_with?( 'direct.bolt.read' )
callsign = event.callsign
self.log.info "Got receipt for %s [%s] from %s" % [ self.class.name, self.id, callsign ]
self.expected_receipts = self.expected_receipts.merge( callsign => Ravn.time )
end
else
self.log.warn "Ignoring event from another instance! %p" % [ event ]
end
super
end