Mercurial > libervia-backend
diff src/plugins/plugin_xep_0059.py @ 1219:16484ebb695b
plugin XEP-0059: first draft, pubsub and jabber search do not exploit it yet
author | souliane <souliane@mailoo.org> |
---|---|
date | Mon, 22 Sep 2014 22:25:44 +0200 |
parents | |
children | ea692d51a0ee |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/plugin_xep_0059.py Mon Sep 22 22:25:44 2014 +0200 @@ -0,0 +1,149 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# SAT plugin for Result Set Management (XEP-0059) +# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org) +# Copyright (C) 2013, 2014 Adrien Cossa (souliane@mailoo.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from sat.core.i18n import _ +from sat.core.log import getLogger +log = getLogger(__name__) + +from twisted.words.xish import domish +from wokkel import disco, iwokkel +try: + from twisted.words.protocols.xmlstream import XMPPHandler +except ImportError: + from wokkel.subprotocols import XMPPHandler +from zope.interface import implements + + +NS_RSM = 'http://jabber.org/protocol/rsm' + +PLUGIN_INFO = { + "name": "Result Set Management", + "import_name": "XEP-0059", + "type": "XEP", + "protocols": ["XEP-0059"], + "main": "XEP_0059", + "handler": "no", + "description": _("""Implementation of Result Set Management""") +} + + +class XEP_0059(object): + + def __init__(self, host): + log.info(_("Result Set Management plugin initialization")) + self.host = host + + def requestPage(self, stanza, limit=10, index=None, after=None, before=None): + """Embed a RSM page request in the given stanza. + + @param stanza (domish.Element): any stanza to which RSM applies + @param limit (int): the maximum number of items in the page + @param index (int): the starting index of the requested page + @param after (str, int): the element immediately preceding the page + @param before (str, int): the element immediately following the page + """ + main_elt = None + try: + main_elt = domish.generateElementsNamed(stanza.elements(), name="query").next() + except StopIteration: + try: + main_elt = domish.generateElementsNamed(stanza.elements(), name="pubsub").next() + except StopIteration: + log.warning("Injection of a RSM element only applies to query or pubsub stanzas") + return + limit = str(int(limit)) + + # in case the service doesn't support RSM, do this at least + main_elt.items.attributes['max_items'] = limit + + set_elt = main_elt.addElement('set', NS_RSM) + set_elt.addElement('max').addContent(limit) + if index: + assert(after is None and before is None) + set_elt.addElement('index').addContent(str(int(index))) + if after: + assert(before is None) # could not specify both at the same time + set_elt.addElement('after').addContent(str(after)) + if before is not None: + if before == '': # request the last page, according to http://xmpp.org/extensions/xep-0059.html#last + set_elt.addElement('before') + else: + set_elt.addElement('before').addContent(str(before)) + + def countItems(self, stanza): + """Count the items without retrieving any of them. + + @param stanza (domish.Element): any stanza to which RSM applies + """ + self.requestPage(stanza, limit=0) + + def extractMetadata(self, stanza): + """Extract the RSM metadata from the given stanza. + + @param stanza (domish.Element, wokkel.pubsub.PubSubRequest): + any stanza to which RSM applies. When used by XEP-0060, + wokkel's PubSubRequest instance is also accepted. + @return: dict containing the page metadata + """ + try: + main_elt = domish.generateElementsNamed(stanza.elements(), name="query").next() + except StopIteration: + try: + main_elt = domish.generateElementsNamed(stanza.elements(), name="pubsub").next() + except StopIteration: + log.warning("Extracting data from a RSM element only applies to query or pubsub stanzas") + return {} + try: + set_elt = domish.generateElementsQNamed(main_elt.elements(), name="set", uri=NS_RSM).next() + except StopIteration: + log.debug("There's no RSM element in the stanza") + return {} + + data = {} + elts = set_elt.elements() + try: + elt = elts.next() + if elt.name == "first": + data["first"] = "".join(elt.children) + data["first_index"] = int(elt.getAttribute("index")) + elif elt.name == "last": + data["last"] = "".join(elt.children) + elif elt.name == "count": + data["count"] = int("".join(elt.children)) + except StopIteration: + pass + if "count" not in data: + log.warning("There's no 'count' element in the RSM element!") + return data + + +class XEP_0059_handler(XMPPHandler): + implements(iwokkel.IDisco) + + def __init__(self, plugin_parent, profile): + self.plugin_parent = plugin_parent + self.host = plugin_parent.host + self.profile = profile + + def getDiscoInfo(self, requestor, target, nodeIdentifier=''): + return [disco.DiscoFeature(NS_RSM)] + + def getDiscoItems(self, requestor, target, nodeIdentifier=''): + return []