[8] | 1 | # -*- test-case-name: wokkel.test.test_compat -*- |
---|
| 2 | # |
---|
[96] | 3 | # Copyright (c) Twisted Matrix Laboratories. |
---|
[8] | 4 | # See LICENSE for details. |
---|
| 5 | |
---|
[34] | 6 | from twisted.internet import protocol |
---|
| 7 | from twisted.words.protocols.jabber import xmlstream |
---|
[8] | 8 | |
---|
[34] | 9 | class BootstrapMixin(object): |
---|
[8] | 10 | """ |
---|
[34] | 11 | XmlStream factory mixin to install bootstrap event observers. |
---|
[8] | 12 | |
---|
[34] | 13 | This mixin is for factories providing |
---|
| 14 | L{IProtocolFactory<twisted.internet.interfaces.IProtocolFactory>} to make |
---|
| 15 | sure bootstrap event observers are set up on protocols, before incoming |
---|
| 16 | data is processed. Such protocols typically derive from |
---|
| 17 | L{utility.EventDispatcher}, like L{XmlStream}. |
---|
[8] | 18 | |
---|
[34] | 19 | You can set up bootstrap event observers using C{addBootstrap}. The |
---|
| 20 | C{event} and C{fn} parameters correspond with the C{event} and |
---|
[8] | 21 | C{observerfn} arguments to L{utility.EventDispatcher.addObserver}. |
---|
[34] | 22 | |
---|
[44] | 23 | @since: 8.2. |
---|
[34] | 24 | @ivar bootstraps: The list of registered bootstrap event observers. |
---|
| 25 | @type bootstrap: C{list} |
---|
[8] | 26 | """ |
---|
| 27 | |
---|
[34] | 28 | def __init__(self): |
---|
[8] | 29 | self.bootstraps = [] |
---|
| 30 | |
---|
[34] | 31 | |
---|
| 32 | def installBootstraps(self, dispatcher): |
---|
[8] | 33 | """ |
---|
[34] | 34 | Install registered bootstrap observers. |
---|
[8] | 35 | |
---|
[34] | 36 | @param dispatcher: Event dispatcher to add the observers to. |
---|
| 37 | @type dispatcher: L{utility.EventDispatcher} |
---|
[8] | 38 | """ |
---|
| 39 | for event, fn in self.bootstraps: |
---|
[34] | 40 | dispatcher.addObserver(event, fn) |
---|
| 41 | |
---|
[8] | 42 | |
---|
| 43 | def addBootstrap(self, event, fn): |
---|
| 44 | """ |
---|
| 45 | Add a bootstrap event handler. |
---|
[44] | 46 | |
---|
| 47 | @param event: The event to register an observer for. |
---|
| 48 | @type event: C{str} or L{xpath.XPathQuery} |
---|
| 49 | @param fn: The observer callable to be registered. |
---|
[8] | 50 | """ |
---|
| 51 | self.bootstraps.append((event, fn)) |
---|
| 52 | |
---|
[34] | 53 | |
---|
[8] | 54 | def removeBootstrap(self, event, fn): |
---|
| 55 | """ |
---|
| 56 | Remove a bootstrap event handler. |
---|
[44] | 57 | |
---|
| 58 | @param event: The event the observer is registered for. |
---|
| 59 | @type event: C{str} or L{xpath.XPathQuery} |
---|
| 60 | @param fn: The registered observer callable. |
---|
[8] | 61 | """ |
---|
| 62 | self.bootstraps.remove((event, fn)) |
---|
[34] | 63 | |
---|
| 64 | |
---|
| 65 | |
---|
| 66 | class XmlStreamServerFactory(BootstrapMixin, |
---|
| 67 | protocol.ServerFactory): |
---|
| 68 | """ |
---|
| 69 | Factory for Jabber XmlStream objects as a server. |
---|
| 70 | |
---|
| 71 | @since: 8.2. |
---|
| 72 | @ivar authenticatorFactory: Factory callable that takes no arguments, to |
---|
| 73 | create a fresh authenticator to be associated |
---|
| 74 | with the XmlStream. |
---|
| 75 | """ |
---|
| 76 | |
---|
| 77 | protocol = xmlstream.XmlStream |
---|
| 78 | |
---|
| 79 | def __init__(self, authenticatorFactory): |
---|
[38] | 80 | BootstrapMixin.__init__(self) |
---|
[34] | 81 | self.authenticatorFactory = authenticatorFactory |
---|
| 82 | |
---|
| 83 | |
---|
| 84 | def buildProtocol(self, addr): |
---|
| 85 | """ |
---|
| 86 | Create an instance of XmlStream. |
---|
| 87 | |
---|
| 88 | A new authenticator instance will be created and passed to the new |
---|
| 89 | XmlStream. Registered bootstrap event observers are installed as well. |
---|
| 90 | """ |
---|
| 91 | authenticator = self.authenticatorFactory() |
---|
| 92 | xs = self.protocol(authenticator) |
---|
| 93 | xs.factory = self |
---|
| 94 | self.installBootstraps(xs) |
---|
| 95 | return xs |
---|
[63] | 96 | |
---|
| 97 | |
---|
| 98 | |
---|
| 99 | class IQ(xmlstream.IQ): |
---|
| 100 | def __init__(self, *args, **kwargs): |
---|
| 101 | # Make sure we have a reactor parameter |
---|
| 102 | try: |
---|
| 103 | reactor = kwargs['reactor'] |
---|
| 104 | except KeyError: |
---|
| 105 | from twisted.internet import reactor |
---|
| 106 | kwargs['reactor'] = reactor |
---|
| 107 | |
---|
| 108 | # Check if IQ's init accepts the reactor parameter |
---|
| 109 | try: |
---|
| 110 | xmlstream.IQ.__init__(self, *args, **kwargs) |
---|
| 111 | except TypeError: |
---|
| 112 | # Guess not. Remove the reactor parameter and try again. |
---|
| 113 | del kwargs['reactor'] |
---|
| 114 | xmlstream.IQ.__init__(self, *args, **kwargs) |
---|
| 115 | |
---|
| 116 | # Patch the XmlStream instance so that it has a _callLater |
---|
| 117 | self._xmlstream._callLater = reactor.callLater |
---|