source: ralphm-patches/c2s_server_factory.patch @ 68:14b59e18ecb6

Last change on this file since 68:14b59e18ecb6 was 68:14b59e18ecb6, checked in by Ralph Meijer <ralphm@…>, 7 years ago

Checkpoint

File size: 6.2 KB
  • wokkel/client.py

    # HG changeset patch
    # Parent f164cc75b8337933cc6dd9c7f43424f3dbd74dee
    Add factory for accepting client connections.
    
    The new XMPPC2SServerFactory is a server factory for accepting client
    connections. It uses `XMPPClientListenAuthenticator` to perform the
    steps for authentication and binding of a resource, and keeps a list
    of all streams.
    
    Upon loss of the connection, the service is called with `unbindResource`.
    Received stanzas cause the service's `onElement` to be called.
    
    The factory has a `deliverStanza` method to deliver stanzas to a particular
    recipient. This is used for stanzas that have different recipient addressing
    than the actual recipient (for presence and messages from a different (or no)
    resource).
    
    TODO:
    
     * Add docstrings.
     * Add tests.
    
    diff --git a/wokkel/client.py b/wokkel/client.py
    a b  
    2121from twisted.words.xish import domish
    2222
    2323from wokkel import generic
     24from wokkel.compat import XmlStreamServerFactory
    2425from wokkel.iwokkel import IUserSession
     26from wokkel.subprotocols import ServerStreamManager
    2527from wokkel.subprotocols import StreamManager
    2628
    2729NS_CLIENT = 'jabber:client'
     
    442444            self.portal = self.portals[self.xmlstream.thisEntity]
    443445        except KeyError:
    444446            raise error.StreamError('host-unknown')
     447
     448
     449
     450class XMPPC2SServerFactory(XmlStreamServerFactory):
     451
     452    def __init__(self, portals):
     453        def authenticatorFactory():
     454            return XMPPClientListenAuthenticator(portals)
     455
     456        XmlStreamServerFactory.__init__(self, authenticatorFactory)
     457        self.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
     458                          self.onConnectionMade)
     459
     460
     461    def onConnectionMade(self, xs):
     462        """
     463        Called when a connection is made.
     464
     465        This creates a stream manager, calls L{setupHandlers} to attach
     466        subprotocol handlers and then signals the stream manager that
     467        the connection was made.
     468        """
     469        sm = ServerStreamManager()
     470        sm.logTraffic = self.logTraffic
     471
     472        for handler in self.setupHandlers():
     473            handler.setHandlerParent(sm)
     474
     475        sm.makeConnection(xs)
     476
     477
     478    def setupHandlers(self):
     479        """
     480        Set up XMPP subprotocol handlers.
     481        """
     482        return [
     483            generic.StanzaForwarder()
     484        ]
  • wokkel/generic.py

    diff --git a/wokkel/generic.py b/wokkel/generic.py
    a b  
    615615
    616616        self._initializers = self.getInitializers()
    617617        self._initializeStream()
     618
     619
     620
     621class StanzaForwarder(XMPPHandler):
     622    """
     623    XMPP protocol for passing incoming stanzas to the stream avatar.
     624
     625    This handler adds an observer for all XML Stanzas to forward to the C{send}
     626    method on the cred avatar set on the XML Stream, unless it has been handled
     627    by other observers.
     628
     629    Stream errors are logged.
     630    """
     631
     632    def connectionMade(self):
     633        """
     634        Called when a connection is made.
     635        """
     636        self.xmlstream.addObserver(xmlstream.STREAM_ERROR_EVENT, self.onError)
     637
     638
     639    def connectionInitialized(self):
     640        """
     641        Called when the stream has been initialized.
     642        """
     643        self.xmlstream.addObserver(
     644            '/*[@xmlns="%s"]' % self.xmlstream.namespace,
     645            self.onStanza, priority=-1)
     646
     647
     648    def onStanza(self, element):
     649        """
     650        Called when a stanza element was received.
     651
     652        Unless a stanza has already been handled, or the name of the element is
     653        not one of C{'iq'}, C{'message'}, C{'presence'}, the stanza is passed
     654        on to the avatar's C{send} method.
     655        """
     656        if element.handled:
     657            return
     658
     659        if element.name not in ('iq', 'message', 'presence'):
     660            return
     661
     662        self.xmlstream.avatar.send(element)
     663
     664
     665    def onError(reason):
     666        """
     667        Log a stream error.
     668        """
     669        log.err(reason, "Stream error")
  • wokkel/subprotocols.py

    diff --git a/wokkel/subprotocols.py b/wokkel/subprotocols.py
    a b  
    142142    @type timeout: C{int}
    143143
    144144    @ivar _reactor: A provider of L{IReactorTime} to track timeouts.
     145
     146    @cvar __streamCount: Global stream count for distinguishing streams.
    145147    """
    146148
    147149    timeout = None
    148150    _reactor = None
     151    __streamCount = 0
    149152
    150153    logTraffic = False
    151154
     
    195198        and call each handler's C{makeConnection} method with the L{XmlStream}
    196199        instance.
    197200        """
    198         def logDataIn(buf):
    199             log.msg("RECV: %r" % buf)
     201        xs.serial = self.__streamCount
     202        BaseStreamManager.__streamCount += 1
    200203
    201         def logDataOut(buf):
    202             log.msg("SEND: %r" % buf)
    203204
    204205        if self.logTraffic:
    205             xs.rawDataInFn = logDataIn
    206             xs.rawDataOutFn = logDataOut
     206            def logData(direction, data):
     207                log.msg(format="%(direction)s (%(streamID)s): %(data)r",
     208                        direction=direction, streamID=xs.serial, data=data)
     209
     210            log.msg(format="Connection %(streamID) made", streamID=xs.serial)
     211            xs.rawDataInFn = lambda data: logData("RECV", data)
     212            xs.rawDataOutFn = lambda data: logData("SEND", data)
    207213
    208214        xs.addObserver(xmlstream.STREAM_AUTHD_EVENT,
    209215                       self.connectionInitialized)
    210216        xs.addObserver(xmlstream.STREAM_END_EVENT,
    211217                       self.connectionLost)
     218
    212219        self.xmlstream = xs
    213220
    214221        for e in list(self):
     
    222229        Send out cached stanzas and call each handler's
    223230        C{connectionInitialized} method.
    224231        """
     232        if self.logTraffic:
     233            log.msg(format="Connection %(streamID) initialized",
     234                    streamID=xs.serial)
    225235
    226236        xs.addObserver('/iq[@type="result"]', self._onIQResponse)
    227237        xs.addObserver('/iq[@type="error"]', self._onIQResponse)
     
    247257        L{XmlStream} anymore and notifies each handler that the connection
    248258        was lost by calling its C{connectionLost} method.
    249259        """
     260        if self.logTraffic:
     261            log.msg(format="Connection %(streamID) lost",
     262                    streamID=self.xmlstream.serial)
     263
    250264        self.xmlstream = None
    251265        self._initialized = False
    252266
Note: See TracBrowser for help on using the repository browser.