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@…>, 12 years ago | |
---|---|
File size: 4.9 KB |
-
wokkel/client.py
diff -r 67a42d8a1c73 wokkel/client.py
a b 18 18 from twisted.python import log 19 19 from twisted.words.protocols.jabber import client, error, sasl, xmlstream 20 20 from twisted.words.protocols.jabber.jid import internJID as JID 21 from twisted.words.xish import domish 21 from twisted.words.xish import domish, utility 22 22 23 23 from wokkel import generic 24 from wokkel.subprotocols import StreamManager 24 from wokkel.compat import XmlStreamServerFactory 25 from wokkel.subprotocols import StreamManager, XMPPHandlerContainer 25 26 26 27 NS_CLIENT = 'jabber:client' 27 28 … … 350 351 reply['id'] = iq['id'] 351 352 reply.addElement((client.NS_XMPP_SESSION, 'session')) 352 353 self.xmlstream.send(reply) 354 355 356 357 class 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 378 class 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.