Source code for aioxmpp.tracking
"""
:mod:`~aioxmpp.tracking` --- Interfaces for high-level message tracking
#######################################################################
This submodule provides interfaces for tracking messages to the recipient. The
actual tracking is not implemented here.
.. versionadded:: 0.5
This module was added in version 0.5.
.. seealso::
Method :meth:`~.muc.Room.send_tracked_message`
implements tracking for messages sent through a MUC.
Interfaces
==========
.. autoclass:: MessageTracker
.. autoclass:: MessageState
"""
from enum import Enum
import aioxmpp.callbacks
import aioxmpp.statemachine
import aioxmpp.stream as stream
[docs]class MessageState(Enum):
"""
Enumeration of possible states for :class:`MessageTracker`. These states
are used to inform using code about the delivery state of a message. See
:class:`MessageTracker` for details.
.. attribute:: ABORTED
The message has been aborted or dropped in the :class:`~.StanzaStream`
queues. See :class:`~.StanzaToken` and :attr:`MessageTracker.token`.
This is a final state.
.. attribute:: TIMED_OUT
The tracking has timed out. Whether a timeout exists and how it is
handled depends on the tracking implementation.
This is a final state.
.. attribute:: UNKNOWN
The tracking itself got aborted and cannot make a statement about the
delivery of the stanza.
This is a final state.
.. attribute:: IN_TRANSIT
The message is still queued for sending or has been sent to the peer
server without stream management.
.. attribute:: DELIVERED_TO_SERVER
The message has been delivered to the server and the server acked the
delivery using stream management.
Depending on the tracking implementation, this may be a final state.
.. attribute:: DELIVERED_TO_RECIPIENT
The message has been delivered to the recipient. Depending on the
tracking implementation, this may be a final state.
.. attribute:: SEEN_BY_RECIPIENT
The recipient has marked the message as seen or read. This is a final
state.
"""
def __lt__(self, other):
if ((other == MessageState.ABORTED or
other == MessageState.UNKNOWN)
and self != MessageState.IN_TRANSIT):
return True
if (other == MessageState.TIMED_OUT and
self != MessageState.IN_TRANSIT and
self != MessageState.DELIVERED_TO_SERVER):
return True
return self.value < other.value
IN_TRANSIT = 0
ABORTED = 1
UNKNOWN = 2
DELIVERED_TO_SERVER = 3
TIMED_OUT = 4
DELIVERED_TO_RECIPIENT = 5
SEEN_BY_RECIPIENT = 6
[docs]class MessageTracker(aioxmpp.statemachine.OrderedStateMachine):
"""
This is the high-level equivalent of the :class:`~.StanzaToken`. This
structure is used by different tracking implementations.
.. attribute:: state
The current :class:`MessageState` of the :class:`MessageTracker`. Do
**not** write to this attribute from user code. Writing to this
attribute is intended only for the tracking implementation.
.. attribute:: token
The :class:`~.StanzaToken` of the message. This is usually set by the
tracking implementation right when the tracker is initialised.
.. signal:: on_state_change(state)
The signal is emitted with the new state as its only argument when the
state of the message tracker changes
"""
on_state_change = aioxmpp.callbacks.Signal()
def __init__(self, token=None):
super().__init__(MessageState.IN_TRANSIT)
self.token = token
def on_stanza_state_change(self, token, stanza_state):
new_state = self.state
if stanza_state == stream.StanzaState.ABORTED:
new_state = MessageState.ABORTED
elif stanza_state == stream.StanzaState.DROPPED:
new_state = MessageState.ABORTED
elif stanza_state == stream.StanzaState.ACKED:
new_state = MessageState.DELIVERED_TO_SERVER
if new_state != self.state and not new_state < self.state:
self.state = new_state
@aioxmpp.statemachine.OrderedStateMachine.state.setter
[docs] def state(self, new_state):
aioxmpp.statemachine.OrderedStateMachine.state.fset(self, new_state)
self.on_state_change(new_state)