Ticket #203: 0001-Migrated-Listener-to-Twisted-endpoints.patch

File 0001-Migrated-Listener-to-Twisted-endpoints.patch, 6.0 KB (added by str4d, 11 years ago)
  • foolscap/pb.py

    From ba0cb1e7844a91105d27c2088944c1fcf45dabde Mon Sep 17 00:00:00 2001
    From: str4d <str4d@mail.i2p>
    Date: Fri, 4 Oct 2013 05:05:52 -0500
    Subject: [PATCH] Migrated Listener to Twisted endpoints
    
    ---
     foolscap/pb.py | 84 ++++++++++++++++++++++++++++++----------------------------
     1 file changed, 43 insertions(+), 41 deletions(-)
    
    diff --git a/foolscap/pb.py b/foolscap/pb.py
    index 473d853..6735e88 100644
    a b  
    33import os.path, weakref, binascii, re
    44from zope.interface import implements
    55from twisted.internet import defer, protocol, error
    6 from twisted.application import service, internet
     6from twisted.internet.endpoints import serverFromString
     7from twisted.application import service
    78from twisted.python.failure import Failure
    89
    910from foolscap import ipb, base32, negotiate, broker, observer, eventual, storage
    except ImportError: 
    2526    pass
    2627
    2728
     29# TODO: Only used by foolscap.logging.web, remove when
     30# that has been migrated to use Twisted endpoints.
    2831def parse_strport(port):
    2932    if port.startswith("unix:"):
    3033        raise ValueError("UNIX sockets are not supported for Listeners")
    class Listener(protocol.ServerFactory): 
    5053
    5154    # this also serves as the ServerFactory
    5255
    53     def __init__(self, port, options={},
     56    def __init__(self, desc, options={},
    5457                 negotiationClass=negotiate.Negotiation):
    5558        """
    56         @type port: string
    57         @param port: a L{twisted.application.strports} -style description,
    58         specifying a TCP server
     59        @type desc: string
     60        @param desc: a L{twisted.internet.endpoints.serverFromString} -style
     61        description, specifying the endpoint to use
    5962        """
    60         # parse the following 'port' strings:
    61         #  80
    62         #  tcp:80
    63         #  tcp:80:interface=127.0.0.1
    64         # we reject UNIX sockets.. I don't know if they ever worked.
    65 
    66         portnum, interface = parse_strport(port)
    67         self.port = port
     63        self.desc = desc
    6864        self.options = options
    6965        self.negotiationClass = negotiationClass
    70         self.parentTub = None
    7166        self.tubs = {}
    7267        self.redirects = {}
    73         self.s = internet.TCPServer(portnum, self, interface=interface)
     68        # TODO: Is there a better place to get the reactor?
     69        from twisted.internet import reactor
     70        self.e = serverFromString(reactor, desc)
     71        self.port = None
    7472        Listeners.append(self)
    7573
     74    def setPort(self, port):
     75        self.port = port
     76
    7677    def getPortnum(self):
    7778        """When this Listener was created with a port string of '0' or
    7879        'tcp:0' (meaning 'please allocate me something'), and if the Listener
    class Listener(protocol.ServerFactory): 
    8586            t.setLocation('localhost:%d' % l.getPortnum())
    8687        """
    8788
    88         assert self.s.running
    89         return self.s._port.getHost().port
     89        # The IListeningPort is started when we get it.
     90        assert self.port
     91        # TODO: Not all endpoints will necessarily have a port?
     92        return self.port.getHost().port
     93
     94    def getHost(self):
     95        """
     96        Returns the IAddress provider for the endpoint.
     97        """
     98        # The IListeningPort is started when we get it.
     99        assert self.port
     100        return self.port.getHost()
    90101
    91102    def __repr__(self):
    92103        if self.tubs:
    93104            return "<Listener at 0x%x on %s with tubs %s>" % (
    94105                abs(id(self)),
    95                 self.port,
     106                self.desc,
    96107                ",".join([str(k) for k in self.tubs.keys()]))
    97108        return "<Listener at 0x%x on %s with no tubs>" % (abs(id(self)),
    98                                                           self.port)
     109                                                          self.desc)
    99110
    100111    def addTub(self, tub):
    101112        if tub.tubID in self.tubs:
    102113            if tub.tubID is None:
    103114                raise RuntimeError("This Listener (on %s) already has an "
    104115                                   "unauthenticated Tub, you cannot add a "
    105                                    "second one" % self.port)
     116                                   "second one" % self.desc)
    106117            raise RuntimeError("This Listener (on %s) is already connected "
    107                                "to TubID '%s'" % (self.port, tub.tubID))
     118                               "to TubID '%s'" % (self.desc, tub.tubID))
    108119        self.tubs[tub.tubID] = tub
    109         if self.parentTub is None:
    110             self.parentTub = tub
    111             self.s.setServiceParent(self.parentTub)
     120        if self.port is None:
     121            d = self.e.listen(self)
     122            d.addCallback(self.setPort)
    112123
    113124    def removeTub(self, tub):
    114125        # this might return a Deferred, since the removal might cause the
    115126        # Listener to shut down. It might also return None.
    116127        del self.tubs[tub.tubID]
    117         if self.parentTub is tub:
    118             # we need to switch to a new one
    119             tubs = self.tubs.values()
    120             if tubs:
    121                 self.parentTub = tubs[0]
    122                 # TODO: I want to do this without first doing
    123                 # disownServiceParent, so the port remains listening. Can we
    124                 # do this? It looks like setServiceParent does
    125                 # disownServiceParent first, so it may glitch.
    126                 self.s.setServiceParent(self.parentTub)
    127             else:
    128                 # no more tubs, this Listener will go away now
    129                 d = self.s.disownServiceParent()
    130                 Listeners.remove(self)
    131                 return d
     128        if not self.tubs:
     129            # no more tubs, this Listener will go away now
     130            d = self.port.stopListening()
     131            Listeners.remove(self)
     132            return d
    132133        return None
    133134
    134     def getService(self):
    135         return self.s
     135    def getEndpoint(self):
     136        # TODO: Is this needed?
     137        return self.e
    136138
    137139    def addRedirect(self, tubID, location):
    138140        assert tubID is not None # unauthenticated Tubs don't get redirects