Files
prosody-podman/tests/venv2/lib/python3.11/site-packages/aioxmpp/im/dispatcher.py
T
2026-08-02 18:57:40 +02:00

150 lines
5.0 KiB
Python

########################################################################
# File name: dispatcher.py
# This file is part of: aioxmpp
#
# LICENSE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#
########################################################################
import asyncio
import enum
import aioxmpp.callbacks
import aioxmpp.carbons
import aioxmpp.service
import aioxmpp.stream
class MessageSource(enum.Enum):
STREAM = 0
CARBONS = 1
class IMDispatcher(aioxmpp.service.Service):
"""
Dispatches messages, taking into account carbons.
.. function:: message_filter(message, peer, sent, source)
A message was received or sent.
:param message: Message stanza
:type message: :class:`aioxmpp.Message`
:param peer: The peer from/to which the stanza was received/sent
:type peer: :class:`aioxmpp.JID`
:param sent: Whether the mesasge was sent or received.
:type sent: :class:`bool`
:param source: The source of the message.
:type source: :class:`MessageSource`
`message` is the message stanza which was sent or received.
`peer` is the JID of the peer involved in the message. If the message
was sent, this is the :attr:`~.StanzaBase.to` and otherwise it is the
:attr:`~.StanzaBase.from_` attribute of the stanza.
If `sent` is true, the message was sent from this resource *or* another
resource of the same account, if Message Carbons are enabled.
`source` indicates how the message was sent or received. It may be one
of the values of the :class:`MessageSource` enumeration.
"""
ORDER_AFTER = [
# we want to be loaded after the SimplePresenceDispatcher to ensure
# that PresenceClient has updated its data structures before the
# dispatch_presence handler runs.
# this helps one-to-one conversations a lot, because they can simply
# re-use the PresenceClient state
aioxmpp.dispatcher.SimplePresenceDispatcher,
aioxmpp.carbons.CarbonsClient,
]
def __init__(self, client, **kwargs):
super().__init__(client, **kwargs)
self.message_filter = aioxmpp.callbacks.Filter()
self.presence_filter = aioxmpp.callbacks.Filter()
@aioxmpp.service.depsignal(
aioxmpp.node.Client,
"before_stream_established")
async def enable_carbons(self, *args):
carbons = self.dependencies[aioxmpp.carbons.CarbonsClient]
try:
await carbons.enable()
except (RuntimeError, aioxmpp.errors.XMPPError):
self.logger.info(
"remote server does not support message carbons"
)
else:
self.logger.info(
"message carbons enabled successfully"
)
return True
@aioxmpp.service.depsignal(
aioxmpp.stream.StanzaStream,
"on_message_received")
def dispatch_message(self, message, *,
sent=False,
source=MessageSource.STREAM):
if message.xep0280_received is not None:
if (message.from_ is not None and
message.from_ != self.client.local_jid.bare()):
return
message = message.xep0280_received.stanza
source = MessageSource.CARBONS
elif message.xep0280_sent is not None:
if (message.from_ is not None and
message.from_ != self.client.local_jid.bare()):
return
message = message.xep0280_sent.stanza
sent = True
source = MessageSource.CARBONS
peer = message.to if sent else message.from_
filtered = self.message_filter.filter(
message,
peer,
sent,
source,
)
if filtered is not None:
self.logger.debug(
"message was not processed by any IM handler: %s",
filtered,
)
@aioxmpp.service.depsignal(
aioxmpp.stream.StanzaStream,
"on_presence_received")
def dispatch_presence(self, presence, *, sent=False):
filtered = self.presence_filter.filter(
presence,
presence.from_,
sent,
)
if filtered is not None:
self.logger.debug(
"presence was not processed by any IM handler: %s",
filtered,
)