[Twisted-Python] Arbitrary Port/Connector objects

Jp Calderone exarkun at intarweb.us
Thu Jan 23 12:19:03 MST 2003


  So far there are a couple use-cases for listening and connecting with
IListeningPort/IConnector implementers that aren't in twisted.internet. 
Tv's SRV connector is one, IPv6 sockets is another.  Currently it is
cumbersome to use these, both because there are no convenience methods in
reactor, and because if you want them to serialize properly you have to
handle storing and restarting them yourself.

  Attached patch adds two methods to Application and two methods to
the default reactor (they'll need to be put in an interface somewhere, too -
I wasn't sure what the best place for them would be): listenWith and
connectWith.  These take a type object that implements IListeningPort and
IConnector respectively, and then perform similar operations to the other
listen and connect methods, including serialization and rebinding the ports
on application startup.  Also added to Application is unlistenWith, an
awkwardly named function that causes a listening Port to stop listening.

  Jp

-- 
Lowery's Law:
        If it jams -- force it.  If it breaks, it needed replacing anyway.
-- 
 up 38 days, 23:48, 5 users, load average: 1.88, 1.70, 1.66
-------------- next part --------------
? app.ann
? socket.diff
? with.diff
Index: app.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/app.py,v
retrieving revision 1.73
diff -u -r1.73 app.py
--- app.py	23 Jan 2003 16:28:07 -0000	1.73
+++ app.py	23 Jan 2003 19:05:43 -0000
@@ -259,11 +259,14 @@
         self.tcpPorts = []              # check
         self.udpPorts = []
         self.sslPorts = []
+        self.extraPorts = []
         self._listenerDict = {}
+        self._extraListeners = {}
         # a list of (tcp, ssl, udp) Connectors
         self.tcpConnectors = []
         self.sslConnectors = []
         self.unixConnectors = []
+        self.extraConnectors = []
         # a list of twisted.python.delay.Delayeds
         self.delayeds = []              # check
         # a list of twisted.internet.cred.service.Services
@@ -277,7 +280,7 @@
             self.uid = uid or os.getuid()
             self.gid = gid or os.getgid()
 
-    persistenceVersion = 10
+    persistenceVersion = 11
 
     _authorizer = None
 
@@ -289,6 +292,16 @@
             self._authorizer.setApplication(self)
         return self._authorizer
 
+    def upgradeToVersion11(self):
+        self._extraListeners = {}
+        self.extraPorts = []
+        self.extraConnectors = []
+
+    def upgradeToVersion10(self):
+        # persistenceVersion was 10, but this method did not exist
+        # I do not know why.
+        pass
+
     def upgradeToVersion9(self):
         self._authorizer = self.authorizer
         del self.authorizer
@@ -366,6 +379,36 @@
             del dict['_listenerDict']
         return dict
 
+    def listenWith(self, portType, *args, **kw):
+        """
+        Start an instance of the given C{portType} listening.
+
+        @type portType: type which implements C{IListeningPort}
+        """
+        self.extraPorts.append((portType, args, kw))
+        if self.running:
+            from twisted.internet import reactor
+            p = reactor.listenWith(portType, *args, **kw)
+            self._extraListeners[(portType, args, kw)] = p
+            return p
+
+    def unlistenWith(self, portType, *args, **kw):
+        toRemove = []
+        for t in self.extraPorts:
+            _portType, _args, _kw = t
+            if portType == _portType:
+                if args == _args[:len(args)]:
+                    for (k, v) in kw.items():
+                        if _kw.has_key(k) and _kw[k] != v:
+                            break
+                    else:
+                        toRemove.append(t)
+        for t in toRemove:
+            self.extraPorts.remove(t)
+            if self._extraListeners.has_key(t):
+                self._extraListeners[t].stopListening()
+                del self._extraListeners[t]
+
     def listenTCP(self, port, factory, backlog=5, interface=''):
         """
         Connects a given protocol factory to the given numeric TCP/IP port.
@@ -409,6 +452,17 @@
             from twisted.internet import reactor
             return reactor.listenSSL(port, factory, ctxFactory, backlog, interface)
 
+    def connectWith(self, connectorType, *args, **kw):
+        """
+        Start an instance of the given C{connectorType} connecting.
+        
+        @type connectorType: type which implements C{IConnector}
+        """
+        self.extraConnectors.append((connectorType, args, kw))
+        if self.running:
+            from twisted.internet import reactor
+            return reactor.connectWith(connectorType, *args, **kw)
+
     def connectTCP(self, host, port, factory, timeout=30, bindAddress=None):
         """Connect a given client protocol factory to a specific TCP server."""
         self.tcpConnectors.append((host, port, factory, timeout, bindAddress))
@@ -582,12 +636,17 @@
                 except error.CannotListenError, msg:
                     log.msg('error on SSL port %s: %s' % (port, msg))
                     return
+            for portType, args, kw in self.extraPorts:
+                reactor.listenWith(portType, *args, **kw)
+
             for host, port, factory, ctxFactory, timeout, bindAddress in self.sslConnectors:
                 reactor.connectSSL(host, port, factory, ctxFactory, timeout, bindAddress)
             for host, port, factory, timeout, bindAddress in self.tcpConnectors:
                 reactor.connectTCP(host, port, factory, timeout, bindAddress)
             for address, factory, timeout in self.unixConnectors:
                 reactor.connectUNIX(address, factory, timeout)
+            for connectorType, args, kw in self.extraConnectors:
+                reactor.connectWith(connectorType, *args, **kw)
 
             for service in self.services.values():
                 service.startService()
Index: default.py
===================================================================
RCS file: /cvs/Twisted/twisted/internet/default.py,v
retrieving revision 1.59
diff -u -r1.59 default.py
--- default.py	9 Jan 2003 08:03:11 -0000	1.59
+++ default.py	23 Jan 2003 19:05:43 -0000
@@ -380,7 +380,16 @@
         p.startListening()
         return p
 
+    # IReactorSomething else
+    def listenWith(self, portType, *args, **kw):
+        p = portType(*args, **kw)
+        p.startListening()
+        return p
 
+    def connectWith(self, connectorType, *args, **kw):
+        c = connectorType(*args, **kw)
+        c.connect()
+        return c
 
 class _Win32Waker(log.Logger, styles.Ephemeral):
     """I am a workaround for the lack of pipes on win32.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: </pipermail/twisted-python/attachments/20030123/6617556f/attachment.sig>


More information about the Twisted-Python mailing list