File: ping.py

package info (click to toggle)
python-tx-xmpp 0.10.1.post1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,468 kB
  • sloc: python: 12,915; makefile: 3
file content (114 lines) | stat: -rw-r--r-- 3,054 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# -*- test-case-name: tx_xmpp.test.test.test_ping -*-
#
# Copyright (c) Ralph Meijer.
# See LICENSE for details.

"""
XMPP Ping.

The XMPP Ping protocol is documented in
U{XEP-0199<http://xmpp.org/extensions/xep-0199.html>}.
"""

from __future__ import division, absolute_import

from zope.interface import implementer

from twisted.words.protocols.jabber.error import StanzaError
from twisted.words.protocols.jabber.xmlstream import IQ, toResponse
from twisted.words.protocols.jabber.xmlstream import XMPPHandler

from . import disco, itx_xmpp

NS_PING = "urn:xmpp:ping"
PING_REQUEST = "/iq[@type='get']/ping[@xmlns='%s']" % NS_PING


class PingClientProtocol(XMPPHandler):
    """
    Ping client.

    This handler implements the protocol for sending out XMPP Ping requests.
    """

    def ping(self, entity, sender=None):
        """
        Send out a ping request and wait for a response.

        @param entity: Entity to be pinged.
        @type entity: L{JID<twisted.words.protocols.jabber.jid.JID>}

        @return: A deferred that fires upon receiving a response.
        @rtype: L{Deferred<twisted.internet.defer.Deferred>}

        @param sender: Optional sender address.
        @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}
        """

        def cb(response):
            return None

        def eb(failure):
            failure.trap(StanzaError)
            exc = failure.value
            if exc.condition == "service-unavailable":
                return None
            else:
                return failure

        request = IQ(self.xmlstream, "get")
        request.addElement((NS_PING, "ping"))

        if sender is not None:
            request["from"] = sender.full()

        d = request.send(entity.full())
        d.addCallbacks(cb, eb)
        return d


@implementer(itx_xmpp.IDisco)
class PingHandler(XMPPHandler):
    """
    Ping responder.

    This handler waits for XMPP Ping requests and sends a response.
    """

    def connectionInitialized(self):
        """
        Called when the XML stream has been initialized.

        This sets up an observer for incoming ping requests.
        """
        self.xmlstream.addObserver(PING_REQUEST, self.onPing)

    def onPing(self, iq):
        """
        Called when a ping request has been received.

        This immediately replies with a result response.
        """
        response = toResponse(iq, "result")
        self.xmlstream.send(response)
        iq.handled = True

    def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
        """
        Get identity and features from this entity, node.

        This handler supports XMPP Ping, but only without a nodeIdentifier
        specified.
        """
        if not nodeIdentifier:
            return [disco.DiscoFeature(NS_PING)]
        else:
            return []

    def getDiscoItems(self, requestor, target, nodeIdentifier=""):
        """
        Get contained items for this entity, node.

        This handler does not support items.
        """
        return []