source: wokkel/disco.py @ 40:2bcb10fb4da4

Last change on this file since 40:2bcb10fb4da4 was 31:45f3d59431c2, checked in by Ralph Meijer <ralphm@…>, 14 years ago

Release Wokkel 0.4.0.

File size: 4.2 KB
RevLine 
[1]1# -*- test-case-name: wokkel.test.test_disco -*-
2#
[31]3# Copyright (c) 2003-2008 Ralph Meijer
[1]4# See LICENSE for details.
5
6"""
7XMPP Service Discovery.
8
9The XMPP service discovery protocol is documented in
10U{XEP-0030<http://www.xmpp.org/extensions/xep-0030.html>}.
11"""
12
13from twisted.internet import defer
14from twisted.words.protocols.jabber import error, jid
15from twisted.words.xish import domish
16
17from wokkel.iwokkel import IDisco
18from wokkel.subprotocols import IQHandlerMixin, XMPPHandler
19
20NS = 'http://jabber.org/protocol/disco'
21NS_INFO = NS + '#info'
22NS_ITEMS = NS + '#items'
23
24IQ_GET = '/iq[@type="get"]'
25DISCO_INFO = IQ_GET + '/query[@xmlns="' + NS_INFO + '"]'
26DISCO_ITEMS = IQ_GET + '/query[@xmlns="' + NS_ITEMS + '"]'
27
28class DiscoFeature(domish.Element):
29    """
30    Element representing an XMPP service discovery feature.
31    """
32
33    def __init__(self, feature):
34        domish.Element.__init__(self, (NS_INFO, 'feature'),
35                                attribs={'var': feature})
36
37
38class DiscoIdentity(domish.Element):
39    """
40    Element representing an XMPP service discovery identity.
41    """
42
43    def __init__(self, category, type, name = None):
44        domish.Element.__init__(self, (NS_INFO, 'identity'),
45                                attribs={'category': category,
46                                         'type': type})
47        if name:
48            self['name'] = name
49
50
51class DiscoItem(domish.Element):
52    """
53    Element representing an XMPP service discovery item.
54    """
55
[30]56    def __init__(self, jid, node='', name=None):
[1]57        domish.Element.__init__(self, (NS_ITEMS, 'item'),
58                                attribs={'jid': jid.full()})
59        if node:
60            self['node'] = node
61
62        if name:
63            self['name'] = name
64
65
66class DiscoHandler(XMPPHandler, IQHandlerMixin):
67    """
68    Protocol implementation for XMPP Service Discovery.
69
70    This handler will listen to XMPP service discovery requests and
[5]71    query the other handlers in L{parent} (see L{XMPPHandlerContainer}) for
[1]72    their identities, features and items according to L{IDisco}.
73    """
74
75    iqHandlers = {DISCO_INFO: '_onDiscoInfo',
76                  DISCO_ITEMS: '_onDiscoItems'}
77
78    def connectionInitialized(self):
79        self.xmlstream.addObserver(DISCO_INFO, self.handleRequest)
80        self.xmlstream.addObserver(DISCO_ITEMS, self.handleRequest)
81
82    def _error(self, failure):
83        failure.trap(defer.FirstError)
84        return failure.value.subFailure
85
86    def _onDiscoInfo(self, iq):
[6]87        requestor = jid.internJID(iq["from"])
[1]88        target = jid.internJID(iq["to"])
[30]89        nodeIdentifier = iq.query.getAttribute("node", '')
[1]90
91        def toResponse(results):
92            info = []
93            for i in results:
94                info.extend(i[1])
95
96            if nodeIdentifier and not info:
97                raise error.StanzaError('item-not-found')
98            else:
99                response = domish.Element((NS_INFO, 'query'))
100
101                for item in info:
102                    response.addChild(item)
103
104            return response
105
106        dl = []
[5]107        for handler in self.parent:
[1]108            if IDisco.providedBy(handler):
[6]109                dl.append(handler.getDiscoInfo(requestor, target,
[1]110                                               nodeIdentifier))
111
112        d = defer.DeferredList(dl, fireOnOneErrback=1, consumeErrors=1)
113        d.addCallbacks(toResponse, self._error)
114        return d
115
116    def _onDiscoItems(self, iq):
[6]117        requestor = jid.internJID(iq["from"])
[1]118        target = jid.internJID(iq["to"])
[30]119        nodeIdentifier = iq.query.getAttribute("node", '')
[1]120
121        def toResponse(results):
122            items = []
123            for i in results:
124                items.extend(i[1])
125
126            response = domish.Element((NS_ITEMS, 'query'))
127
128            for item in items:
129                response.addChild(item)
130
131            return response
132
133        dl = []
[5]134        for handler in self.parent:
[1]135            if IDisco.providedBy(handler):
[6]136                dl.append(handler.getDiscoItems(requestor, target,
[1]137                                                nodeIdentifier))
138
139        d = defer.DeferredList(dl, fireOnOneErrback=1, consumeErrors=1)
140        d.addCallbacks(toResponse, self._error)
141        return d
Note: See TracBrowser for help on using the repository browser.