source: ralphm-patches/xmpp_client_service.patch @ 34:e46c5701df9e

Last change on this file since 34:e46c5701df9e was 34:e46c5701df9e, checked in by Ralph Meijer <ralphm@…>, 11 years ago

Add a bunch of new patches.

File size: 4.9 KB
  • wokkel/client.py

    diff -r 67a42d8a1c73 wokkel/client.py
    a b  
    1818from twisted.python import log
    1919from twisted.words.protocols.jabber import client, error, sasl, xmlstream
    2020from twisted.words.protocols.jabber.jid import internJID as JID
    21 from twisted.words.xish import domish
     21from twisted.words.xish import domish, utility
    2222
    2323from wokkel import generic
    24 from wokkel.subprotocols import StreamManager
     24from wokkel.compat import XmlStreamServerFactory
     25from wokkel.subprotocols import StreamManager, XMPPHandlerContainer
    2526
    2627NS_CLIENT = 'jabber:client'
    2728
     
    350351            reply['id'] = iq['id']
    351352        reply.addElement((client.NS_XMPP_SESSION, 'session'))
    352353        self.xmlstream.send(reply)
     354
     355
     356
     357class DemuxedXmlStream(utility.EventDispatcher):
     358    """
     359    Fake XML stream for demultiplexing incoming streams.
     360
     361    Incoming traffic should have its C{from} attribute set to the JID of the
     362    sender and then L{dispatch<utility.EventDispatcher.dispatch>}ed. Outgoing
     363    traffic needs to have the C{to} attribute set. It is then passed on to
     364    the stream manager's C{send} method.
     365    """
     366
     367    def send(self, element):
     368        """
     369        Send element out over the wire.
     370
     371        This calls the stream manager to forward the element based on
     372        the embedded addressing information.
     373        """
     374        self.manager.send(element)
     375
     376
     377
     378class ClientService(XMPPHandlerContainer, service.Service):
     379    """
     380    Service for accepting XMPP client connections.
     381
     382    Incoming client connections are first authenticated using the
     383    L{XMPPClientListenAuthenticator}, and then kept in a dictionary that is
     384    keyed with the JID that was bound to that connection.
     385
     386    Where L{StreamManager} manages one connection at a time, this
     387    service demultiplexes incoming connections. For the subprotocol handlers
     388    (objects providing {ijabber.IXMPPHandler}), their stream is always
     389    connected and initialized, but they only have to deal with one stream. This
     390    makes it easier to create adapters.
     391
     392    As an L{xmlstream.XMPPHandlerContainer}, this service creates a fake XML
     393    stream that is passed to the XMPP subprotocol handlers. The received
     394    stanzas from the incoming client connections are passed on to the handlers
     395    using this fake XML, while having their C{from} attribute set to the JID of
     396    the client stream. Stanzas sent by the handlers are forwarded to the
     397    matching client stream, selected by the stanzas C{to} attribute.
     398    """
     399
     400    logTraffic = False
     401
     402    def __init__(self, domain, port=5222):
     403        self.domain = domain
     404        self.port = port
     405
     406        self.factory = XmlStreamServerFactory(XMPPClientListenAuthenticator,
     407                                              self.domain)
     408        self.factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
     409                                  self.makeConnection)
     410        self.factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT,
     411                                  self.connectionInitialized)
     412
     413        self.streams = {}
     414
     415        XMPPHandlerContainer.__init__(self)
     416
     417
     418    def startService(self):
     419
     420        self.xmlstream = DemuxedXmlStream()
     421        self.xmlstream.manager = self
     422        self._initialized = True
     423
     424        for handler in self:
     425            handler.makeConnection(self.xmlstream)
     426            handler.connectionInitialized()
     427
     428        service.Service.startService(self)
     429        reactor.listenTCP(self.port, self.factory)
     430
     431
     432    def makeConnection(self, xs):
     433        def logDataIn(buf):
     434            log.msg("RECV: %r" % buf)
     435
     436        def logDataOut(buf):
     437            log.msg("SEND: %r" % buf)
     438
     439        if self.logTraffic:
     440            xs.rawDataInFn = logDataIn
     441            xs.rawDataOutFn = logDataOut
     442
     443
     444    def connectionInitialized(self, xs):
     445        self.streams[xs.otherEntity.full()] = xs
     446        xs.addObserver(xmlstream.STREAM_END_EVENT,
     447                       lambda failure: self.connectionDisconnected(xs))
     448        xs.addObserver('/*', lambda element: self.onElement(element, xs))
     449
     450
     451    def connectionDisconnected(self, xs):
     452        del self.streams[xs.otherEntity.full()]
     453
     454
     455    def onElement(self, element, xs):
     456        """
     457        Called when an element was received from one of the connected streams.
     458
     459        """
     460        if element.handled:
     461            return
     462
     463        element["from"] = xs.otherEntity.full()
     464        self.xmlstream.dispatch(element)
     465
     466
     467    def send(self, element):
     468        """
     469        Send element to the proper XML Stream.
     470
     471        This uses addressing embedded in the element to find the correct
     472        stream to forward the element to.
     473        """
     474
     475        destination = JID(element["to"]).full()
     476
     477        if destination not in self.streams:
     478            raise Exception("Destination unreachable")
     479
     480        self.streams[destination].send(element)
Note: See TracBrowser for help on using the repository browser.