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

Attributes

expires_at RW

The Monotonic time at which the extended bolt will finish even if it hasn’t seen all required receipts

Public Class Methods

apply( bolt_class, from: :default )

Add some response-specific configuration to bolts that have receipts.

# File lib/ravn/bde/bolt/read_receipts.rb, line 29
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

Public Instance Methods

all_receipts_receieved?()

Returns true if all expected receipts have been received.

# File lib/ravn/bde/bolt/read_receipts.rb, line 111
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.

# File lib/ravn/bde/bolt/read_receipts.rb, line 57
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.

# File lib/ravn/bde/bolt/read_receipts.rb, line 87
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
ready_to_be_finished?()

Returns true if the bolt should be terminated and saved to history.

# File lib/ravn/bde/bolt/read_receipts.rb, line 105
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.

# File lib/ravn/bde/bolt/read_receipts.rb, line 119
def recipient_segment_members
        segment_members = self.class.receipts_from.to_h
        segment_members.delete( Ravn::BDE.callsign )
        return segment_members
end
send_phase( event )

Overloaded to set up the expected responses table.

# File lib/ravn/bde/bolt/read_receipts.rb, line 48
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
summarize_phase( event )

Overloaded to record read receipt events. This may finish the bolt (via super) if it was the last expected response.

# File lib/ravn/bde/bolt/read_receipts.rb, line 70
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