XEP-0231: API changes

- ``get_bob`` and ``set_bob`` are now coroutines.
- ``del_bob`` returns a Future.
This commit is contained in:
mathieui 2021-02-14 12:02:13 +01:00
parent ab87b25030
commit 9947d3db85
3 changed files with 64 additions and 22 deletions

View file

@ -9,6 +9,40 @@ XEP-0231: Bits of Binary
:exclude-members: session_bind, plugin_init, plugin_end
Internal API methods
--------------------
The default API handlers for this plugin manage an in-memory cache of
bits of binary by content-id.
.. glossary::
set_bob
- **jid**: :class:`~.JID` sending the bob
- **node**: unused
- **ifrom**: :class:`~JID` receiving the bob
- **args**: :class:`~.BitsOfBinary` element.
Set a BoB in the cache.
get_bob
- **jid**: :class:`~.JID` receiving the bob
- **node**: unused
- **ifrom**: :class:`~JID` sending the bob
- **args**: ``str`` content-id of the bob
- **returns**: :class:`~.BitsOfBinary` element.
Get a BoB from the cache.
del_bob
- **jid**: unused
- **node**: unused
- **ifrom**: :class:`~JID` sending the bob
- **args**: ``str`` content-id of the bob
Delete a BoB from the cache.
Stanza elements
---------------

View file

@ -20,7 +20,7 @@ class TestBOB(SlixIntegration):
async def test_bob(self):
"""Check we can send and receive a BOB."""
cid = self.clients[0]['xep_0231'].set_bob(
cid = await self.clients[0]['xep_0231'].set_bob(
self.data,
'image/jpeg',
)

View file

@ -12,7 +12,7 @@ from typing import Optional
from slixmpp import future_wrapper, JID
from slixmpp.stanza import Iq, Message, Presence
from slixmpp.exceptions import XMPPError
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.handler import CoroutineCallback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.plugins.base import BasePlugin
@ -40,17 +40,17 @@ class XEP_0231(BasePlugin):
register_stanza_plugin(Presence, BitsOfBinary)
self.xmpp.register_handler(
Callback('Bits of Binary - Iq',
CoroutineCallback('Bits of Binary - Iq',
StanzaPath('iq/bob'),
self._handle_bob_iq))
self.xmpp.register_handler(
Callback('Bits of Binary - Message',
CoroutineCallback('Bits of Binary - Message',
StanzaPath('message/bob'),
self._handle_bob))
self.xmpp.register_handler(
Callback('Bits of Binary - Presence',
CoroutineCallback('Bits of Binary - Presence',
StanzaPath('presence/bob'),
self._handle_bob))
@ -67,13 +67,14 @@ class XEP_0231(BasePlugin):
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('urn:xmpp:bob')
def set_bob(self, data: bytes, mtype: str, cid: Optional[str] = None,
max_age: Optional[int] = None) -> str:
async def set_bob(self, data: bytes, mtype: str, cid: Optional[str] = None,
max_age: Optional[int] = None) -> str:
"""Register a blob of binary data as a BOB.
.. versionchanged:: 1.8.0
If ``max_age`` is specified, the registered data will be destroyed
after that time.
This function is now a coroutine.
:param data: Data to register.
:param mtype: Mime Type of the data (e.g. ``image/jpeg``).
@ -90,27 +91,27 @@ class XEP_0231(BasePlugin):
bob['cid'] = cid
bob['max_age'] = max_age
self.api['set_bob'](args=bob)
await self.api['set_bob'](args=bob)
# Schedule destruction of the data
if max_age is not None and max_age > 0:
self.xmpp.loop.call_later(max_age, self.del_bob, cid)
return cid
@future_wrapper
def get_bob(self, jid: Optional[JID] = None, cid: Optional[str] = None,
cached: bool = True, ifrom: Optional[JID] = None,
**iqkwargs) -> Future:
async def get_bob(self, jid: Optional[JID] = None, cid: Optional[str] = None,
cached: bool = True, ifrom: Optional[JID] = None,
**iqkwargs) -> Iq:
"""Get a BOB.
.. versionchanged:: 1.8.0
Results not in cache do not raise an error when ``cached`` is True.
This function is now a coroutine.
:param jid: JID to fetch the BOB from.
:param cid: Content ID (actually required).
:param cached: To fetch the BOB from the local cache first (from CID only)
"""
if cached:
data = self.api['get_bob'](None, None, ifrom, args=cid)
data = await self.api['get_bob'](None, None, ifrom, args=cid)
if data is not None:
if not isinstance(data, Iq):
iq = self.xmpp.Iq()
@ -120,19 +121,24 @@ class XEP_0231(BasePlugin):
iq = self.xmpp.make_iq_get(ito=jid, ifrom=ifrom)
iq['bob']['cid'] = cid
return iq.send(**iqkwargs)
return await iq.send(**iqkwargs)
def del_bob(self, cid: str):
self.api['del_bob'](args=cid)
def del_bob(self, cid: str) -> Future:
"""Delete a stored BoB.
def _handle_bob_iq(self, iq: Iq):
.. versionchanged:: 1.8.0
This function now returns a Future.
"""
return self.api['del_bob'](args=cid)
async def _handle_bob_iq(self, iq: Iq):
cid = iq['bob']['cid']
if iq['type'] == 'result':
self.api['set_bob'](iq['from'], None, iq['to'], args=iq['bob'])
await self.api['set_bob'](iq['from'], None, iq['to'], args=iq['bob'])
self.xmpp.event('bob', iq)
elif iq['type'] == 'get':
data = self.api['get_bob'](iq['to'], None, iq['from'], args=cid)
data = await self.api['get_bob'](iq['to'], None, iq['from'], args=cid)
if isinstance(data, Iq):
data['id'] = iq['id']
data.send()
@ -142,9 +148,11 @@ class XEP_0231(BasePlugin):
iq.append(data)
iq.send()
def _handle_bob(self, stanza):
self.api['set_bob'](stanza['from'], None,
stanza['to'], args=stanza['bob'])
async def _handle_bob(self, stanza):
await self.api['set_bob'](
stanza['from'], None,
stanza['to'], args=stanza['bob']
)
self.xmpp.event('bob', stanza)
# =================================================================