source: ralphm-patches/c2s_server_factory.patch @ 57:0d8b6cf41728

Last change on this file since 57:0d8b6cf41728 was 57:0d8b6cf41728, checked in by Ralph Meijer <ralphm@…>, 9 years ago

Wokkel 0.7.0 release, clean up various patches.

File size: 4.0 KB
  • wokkel/client.py

    # HG changeset patch
    # Parent d76497171af8f3acf1efd2c8433fbdc3c4a55f92
    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 -r d76497171af8 wokkel/client.py
    a b  
    2020from twisted.words.xish import domish
    2121
    2222from wokkel import generic
     23from wokkel.compat import XmlStreamServerFactory
    2324from wokkel.subprotocols import StreamManager
    2425
    2526NS_CLIENT = 'jabber:client'
     
    347348
    348349
    349350
     351class RecipientUnavailable(Exception):
     352    """
     353    The addressed entity is not, or no longer, available.
     354    """
     355
     356
     357
     358class XMPPC2SServerFactory(XmlStreamServerFactory):
     359
     360    def __init__(self, service):
     361        self.service = service
     362
     363        def authenticatorFactory():
     364            return XMPPClientListenAuthenticator(service)
     365
     366        XmlStreamServerFactory.__init__(self, authenticatorFactory)
     367        self.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT,
     368                          self.onConnectionMade)
     369        self.addBootstrap(xmlstream.STREAM_AUTHD_EVENT,
     370                          self.onAuthenticated)
     371
     372        self.serial = 0
     373        self.streams = {}
     374
     375
     376    def onConnectionMade(self, xs):
     377        """
     378        Called when a client-to-server connection was made.
     379
     380        This enables traffic debugging on incoming streams.
     381        """
     382        xs.serial = self.serial
     383        self.serial += 1
     384
     385        log.msg("Client connection %d made" % xs.serial)
     386
     387        def logDataIn(buf):
     388            log.msg("RECV (%d): %r" % (xs.serial, buf))
     389
     390        def logDataOut(buf):
     391            log.msg("SEND (%d): %r" % (xs.serial, buf))
     392
     393        if self.logTraffic:
     394            xs.rawDataInFn = logDataIn
     395            xs.rawDataOutFn = logDataOut
     396
     397        xs.addObserver(xmlstream.STREAM_ERROR_EVENT, self.onError)
     398
     399
     400    def onAuthenticated(self, xs):
     401        log.msg("Client connection %d authenticated" % xs.serial)
     402
     403        xs.addObserver(xmlstream.STREAM_END_EVENT, self.onConnectionLost,
     404                                                   0, xs)
     405        xs.addObserver('/*', self.onElement, 0, xs)
     406
     407        # Record this stream as bound to the authenticated JID
     408        self.streams[xs.otherEntity] = xs
     409
     410
     411    def onConnectionLost(self, xs, reason):
     412        log.msg("Client connection %d disconnected" % xs.serial)
     413
     414        entity = xs.otherEntity
     415        self.service.unbindResource(entity.user,
     416                                    entity.host,
     417                                    entity.resource,
     418                                    reason)
     419
     420        # If the lost connections had been bound, remove the reference
     421        if xs.otherEntity in self.streams:
     422            del self.streams[xs.otherEntity]
     423
     424
     425    def onError(self, reason):
     426        log.err(reason, "Stream Error")
     427
     428
     429    def onElement(self, xs, stanza):
     430        """
     431        Called when an element was received from one of the connected streams.
     432
     433        """
     434        if stanza.handled:
     435            return
     436        else:
     437            self.service.onElement(stanza, xs.otherEntity)
     438
     439
     440    def deliverStanza(self, element, recipient):
     441        if recipient in self.streams:
     442            self.streams[recipient].send(element)
     443        else:
     444            raise RecipientUnavailable(u"There is no connection for %s" %
     445                                       recipient.full())
Note: See TracBrowser for help on using the repository browser.