plugin XEP-0060: MAM integration:
- removed useless XEP-0059 recommendation
- added XEP-0313 as a recommended plugin
- parseExtra now manage mam_* keys (mam_filter_[name] to use a filter)
- if a mam request is in 'mam' key of extra parameted in getItems, a MAM request is done, but the result is returned in the same way as for normal getItems, making like more easy for other plugins and for frontends
This commit is contained in:
parent
c5320bb949
commit
b3428838cc
1 changed files with 83 additions and 14 deletions
|
|
@ -28,15 +28,16 @@ from sat.tools import sat_defer
|
|||
from twisted.words.protocols.jabber import jid, error
|
||||
from twisted.internet import defer
|
||||
from wokkel import disco
|
||||
# XXX: tmp.pubsub is actually use instead of wokkel version
|
||||
# same thing for rsm
|
||||
from wokkel import pubsub
|
||||
from wokkel import rsm
|
||||
from wokkel import data_form
|
||||
from zope.interface import implements
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
UNSPECIFIED = "unspecified error"
|
||||
import datetime
|
||||
from dateutil import tz
|
||||
# XXX: tmp.wokkel.pubsub is actually use instead of wokkel version
|
||||
# mam and rsm come from tmp.wokkel too
|
||||
from wokkel import pubsub
|
||||
from wokkel import rsm
|
||||
from wokkel import mam
|
||||
|
||||
|
||||
PLUGIN_INFO = {
|
||||
|
|
@ -45,12 +46,15 @@ PLUGIN_INFO = {
|
|||
"type": "XEP",
|
||||
"protocols": ["XEP-0060"],
|
||||
"dependencies": [],
|
||||
"recommendations": ["XEP-0059"],
|
||||
"recommendations": ["XEP-0313"],
|
||||
"main": "XEP_0060",
|
||||
"handler": "yes",
|
||||
"description": _("""Implementation of PubSub Protocol""")
|
||||
}
|
||||
|
||||
UNSPECIFIED = "unspecified error"
|
||||
MAM_FILTER = "mam_filter_"
|
||||
|
||||
|
||||
Extra = namedtuple('Extra', ('rsm_request', 'extra'))
|
||||
# rsm_request is the rsm.RSMRequest build with rsm_ prefixed keys, or None
|
||||
|
|
@ -77,6 +81,7 @@ class XEP_0060(object):
|
|||
def __init__(self, host):
|
||||
log.info(_(u"PubSub plugin initialization"))
|
||||
self.host = host
|
||||
self._mam = host.plugins.get('XEP-0313')
|
||||
self._node_cb = {} # dictionnary of callbacks for node (key: node, value: list of callbacks)
|
||||
self.rt_sessions = sat_defer.RTDeferredSessions()
|
||||
host.bridge.addMethod("psDeleteNode", ".plugin", in_sign='sss', out_sign='', method=self._deleteNode, async=True)
|
||||
|
|
@ -125,15 +130,46 @@ class XEP_0060(object):
|
|||
@return(Extra): filled Extra instance
|
||||
"""
|
||||
if extra is not None:
|
||||
rsm_dict = { key[4:]: value for key, value in extra.iteritems() if key.startswith('rsm_') }
|
||||
if rsm_dict:
|
||||
# rsm
|
||||
rsm_args = {}
|
||||
for arg in ('max', 'after', 'before', 'index'):
|
||||
try:
|
||||
rsm_dict['max_'] = rsm_dict.pop('max')
|
||||
argname = "max_" if arg == 'max' else arg
|
||||
rsm_args[argname] = extra.pop('rsm_{}'.format(arg))
|
||||
except KeyError:
|
||||
pass
|
||||
rsm_request = rsm.RSMRequest(**rsm_dict)
|
||||
continue
|
||||
|
||||
if rsm_args:
|
||||
rsm_request = rsm.RSMRequest(**rsm_args)
|
||||
else:
|
||||
rsm_request = None
|
||||
|
||||
# mam
|
||||
mam_args = {}
|
||||
for arg in ('start', 'end'):
|
||||
try:
|
||||
mam_args[arg] = datetime.datetime.fromtimestamp(int(extra.pop('{}{}'.format(MAM_FILTER, arg))), tz.tzutc())
|
||||
except (TypeError, ValueError):
|
||||
log.warning(u"Bad value for {} filter".format(arg))
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
try:
|
||||
mam_args['with_jid'] = jid.JID(extra.pop('{}jid'.format(MAM_FILTER)))
|
||||
except (jid.InvalidFormat):
|
||||
log.warning(u"Bad value for jid filter")
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
for name, value in extra:
|
||||
if name.startswith(MAM_FILTER):
|
||||
var = name[len[MAM_FILTER]:]
|
||||
extra_fields = mam_args.setdefault('extra_fields', [])
|
||||
extra_fields.append(data_form.Field(var=var, value=value))
|
||||
|
||||
if mam_args:
|
||||
assert 'mam' not in extra
|
||||
extra['mam'] = mam.MAMRequest(mam.buildForm(**mam_args))
|
||||
else:
|
||||
rsm_request = None
|
||||
extra = {}
|
||||
|
|
@ -218,6 +254,18 @@ class XEP_0060(object):
|
|||
client = self.host.getClient(profile_key)
|
||||
return client.pubsub_client.publish(service, nodeIdentifier, items, client.pubsub_client.parent.jid)
|
||||
|
||||
def _unwrapMAMMessage(self, message_elt):
|
||||
try:
|
||||
item_elt = (message_elt.elements(mam.NS_MAM, 'result').next()
|
||||
.elements(C.NS_FORWARD, 'forwarded').next()
|
||||
.elements(C.NS_CLIENT, 'message').next()
|
||||
.elements('http://jabber.org/protocol/pubsub#event', 'event').next()
|
||||
.elements('http://jabber.org/protocol/pubsub#event', 'items').next()
|
||||
.elements('http://jabber.org/protocol/pubsub#event', 'item').next())
|
||||
except StopIteration:
|
||||
raise exceptions.DataError(u"Can't find Item in MAM message element")
|
||||
return item_elt
|
||||
|
||||
def getItems(self, service, node, max_items=None, item_ids=None, sub_id=None, rsm_request=None, extra=None, profile_key=C.PROF_KEY_NONE):
|
||||
"""Retrieve pubsub items from a node.
|
||||
|
||||
|
|
@ -238,7 +286,28 @@ class XEP_0060(object):
|
|||
if extra is None:
|
||||
extra = {}
|
||||
client = self.host.getClient(profile_key)
|
||||
d = client.pubsub_client.items(service, node, max_items, item_ids, sub_id, client.pubsub_client.parent.jid, rsm_request)
|
||||
try:
|
||||
mam_query = extra['mam']
|
||||
except KeyError:
|
||||
d = client.pubsub_client.items(service, node, max_items, item_ids, sub_id, None, rsm_request)
|
||||
else:
|
||||
# if mam is requested, we have to do a totally different query
|
||||
if self._mam is None:
|
||||
raise exceptions.NotFound(u"MAM (XEP-0313) plugin is not available")
|
||||
if max_items is not None:
|
||||
raise exceptions.DataError(u"max_items parameter can't be used with MAM")
|
||||
if item_ids:
|
||||
raise exceptions.DataError(u"items_ids parameter can't be used with MAM")
|
||||
if mam_query.node is None:
|
||||
mam_query.node = node
|
||||
elif mam_query.node != node:
|
||||
raise exceptions.DataError(u"MAM query node is incoherent with getItems's node")
|
||||
if mam_query.rsm is None:
|
||||
mam_query.rsm = rsm_request
|
||||
else:
|
||||
if mam_query.rsm != rsm_request:
|
||||
raise exceptions.DataError(u"Conflict between RSM request and MAM's RSM request")
|
||||
d = self._mam.getArchives(client, mam_query, service, self._unwrapMAMMessage)
|
||||
|
||||
try:
|
||||
subscribe = C.bool(extra['subscribe'])
|
||||
|
|
|
|||
Loading…
Reference in a new issue