Skip to content
This repository was archived by the owner on Jan 14, 2024. It is now read-only.

Commit 4de61e3

Browse files
committed
presence: support actual emission of directed presences
1 parent e1ed15e commit 4de61e3

File tree

2 files changed

+440
-16
lines changed

2 files changed

+440
-16
lines changed

aioxmpp/presence/service.py

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,18 @@ class DirectedPresenceHandle:
269269
.. automethod:: send_presence
270270
"""
271271

272-
def __init__(self, service: "PresenceServer", peer: aioxmpp.JID):
272+
def __init__(self, service: "PresenceServer", peer: aioxmpp.JID,
273+
muted: bool = False):
273274
super().__init__()
274275
self._address = peer
275276
self._service = service
277+
self._muted = muted
278+
self._presence_filter = None
279+
self._unsubscribed = False
280+
281+
def _require_subscribed(self):
282+
if self._unsubscribed:
283+
raise RuntimeError("directed presence relationship is unsubscribed")
276284

277285
@property
278286
def address(self) -> aioxmpp.JID:
@@ -302,6 +310,7 @@ def muted(self) -> bool:
302310
This attribute is read-only. It must be modified through
303311
:meth:`set_muted`.
304312
"""
313+
return self._muted
305314

306315
@property
307316
def presence_filter(self):
@@ -322,12 +331,13 @@ def presence_filter(self):
322331
modifications from leaking into other presence relationships; making a
323332
copy inside the callback is not required or recommended.
324333
"""
334+
return self._presence_filter
325335

326336
@presence_filter.setter
327337
def presence_filter(self, new_callback):
328-
pass
338+
self._presence_filter = new_callback
329339

330-
def set_muted(self, muted, *, send_update_now=True):
340+
def set_muted(self, muted: bool, *, send_update_now: bool = True):
331341
"""
332342
Change the :attr:`muted` state of the relationship.
333343
@@ -351,6 +361,14 @@ def set_muted(self, muted, *, send_update_now=True):
351361
If `send_update_now` is :data:`True`, the current presence is sent to
352362
the peer immediately.
353363
"""
364+
self._require_subscribed()
365+
366+
muted = bool(muted)
367+
if muted == self._muted:
368+
return
369+
370+
self._muted = muted
371+
self._service._emit_presence_directed(self)
354372

355373
def unsubscribe(self):
356374
"""
@@ -375,25 +393,24 @@ def unsubscribe(self):
375393
376394
This operation is idempotent.
377395
"""
396+
if self._unsubscribed:
397+
return
398+
378399
self._service._unsubscribe_peer_directed(self)
400+
self._unsubscribed = True
379401

380-
def send_presence(self, stanza: aioxmpp.Presence):
402+
def resend_presence(self):
381403
"""
382-
Send a presence stanza to the peer.
404+
Resend the current presence to the directed peer.
383405
384-
:param stanza: The stanza to send.
385-
:type stanza: :class:`aioxmpp.Presence`
386406
:raises RuntimeError: if the presence relationship has been destroyed
387407
with :meth:`unsubscribe`
388408
389-
The type of the presence `stanza` must be either
390-
:attr:`aioxmpp.PresenceType.AVAILABLE` or
391-
:attr:`aioxmpp.PresenceType.UNAVAILABLE`.
392-
393-
The :meth:`presence_filter` is not invoked on this `stanza`; it is
394-
assumed that the owner of the relationship takes care of setting the
395-
`stanza` up in the way it is needed.
409+
This forces a presence send, even if the relationship is muted. The
410+
:attr:`presence_filter` is invoked as normal.
396411
"""
412+
self._require_subscribed()
413+
self._service._emit_presence_directed(self)
397414

398415

399416
class PresenceServer(aioxmpp.service.Service):
@@ -583,6 +600,15 @@ def set_presence(self, state, status={}, priority=0):
583600
self.on_presence_changed()
584601
return self.resend_presence()
585602

603+
def _emit_presence_directed(self, session):
604+
st = self.make_stanza()
605+
st.to = session.address
606+
if session.presence_filter is not None:
607+
st = session.presence_filter(st)
608+
if st is None:
609+
return
610+
self.client.enqueue(st)
611+
586612
def resend_presence(self):
587613
"""
588614
Re-send the currently configured presence.
@@ -599,8 +625,18 @@ def resend_presence(self):
599625
any of the parameters changed.
600626
"""
601627

602-
if self.client.established:
603-
return self.client.enqueue(self.make_stanza())
628+
if not self.client.established:
629+
return
630+
631+
main_token = self.client.enqueue(self.make_stanza())
632+
633+
for sessions in self._directed_sessions.values():
634+
for session in sessions.values():
635+
if session.muted:
636+
continue
637+
self._emit_presence_directed(session)
638+
639+
return main_token
604640

605641
def subscribe_peer_directed(self,
606642
peer: aioxmpp.JID,
@@ -658,8 +694,12 @@ def subscribe_peer_directed(self,
658694
result = sessions[peer.resource] = DirectedPresenceHandle(
659695
self,
660696
peer,
697+
muted=muted,
661698
)
662699

700+
if not muted:
701+
self._emit_presence_directed(result)
702+
663703
return result
664704

665705
def _unsubscribe_peer_directed(self, handle: DirectedPresenceHandle):

0 commit comments

Comments
 (0)