[Pkg-privacy-commits] [pyptlib] 84/136: refactor write and decision logic into a separate TransportPlugin class - deprecate old API that created a new config for each method call

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 13:25:13 UTC 2015


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository pyptlib.

commit 3fd0b32fc9d24a72c385de14fc3578b7b190059c
Author: Ximin Luo <infinity0 at gmx.com>
Date:   Thu Aug 15 14:45:45 2013 +0100

    refactor write and decision logic into a separate TransportPlugin class
    - deprecate old API that created a new config for each method call
---
 pyptlib/__init__.py      |   1 +
 pyptlib/client.py        |  97 ++++++++++++++++---------------------
 pyptlib/client_config.py |  49 +++----------------
 pyptlib/config.py        |  72 ++++-----------------------
 pyptlib/core.py          | 123 +++++++++++++++++++++++++++++++++++++++++++++++
 pyptlib/server.py        |  86 ++++++++++++++-------------------
 pyptlib/server_config.py |  59 +++++------------------
 7 files changed, 229 insertions(+), 258 deletions(-)

diff --git a/pyptlib/__init__.py b/pyptlib/__init__.py
index e69de29..8b13789 100644
--- a/pyptlib/__init__.py
+++ b/pyptlib/__init__.py
@@ -0,0 +1 @@
+
diff --git a/pyptlib/client.py b/pyptlib/client.py
index 1e57f34..5b93627 100644
--- a/pyptlib/client.py
+++ b/pyptlib/client.py
@@ -5,75 +5,60 @@
 Public client-side pyptlib API.
 """
 
-from pyptlib.config import EnvError
+from pyptlib.core import TransportPlugin
 from pyptlib.client_config import ClientConfig
 
 
-def init(supported_transports):
+class ClientTransportPlugin(TransportPlugin):
     """
-    Bootstrap client-side managed-proxy mode.
-
-    *Call in the beginning of your application.*
-
-    :param list supported_transports: Names of the transports that the application supports.
-
-    :returns: dictionary that contains information for the application.
+    Runtime process for a client TransportPlugin.
+    """
+    configType = ClientConfig
+    methodName = 'CMETHOD'
+
+    def reportMethodSuccess(self, name, socksVersion, addrport, args=None, optArgs=None):
+        """
+        Write a message to stdout announcing that a transport was
+        successfully launched.
+
+        :param str name: Name of transport.
+        :param int socksVersion: The SOCKS protocol version.
+        :param tuple addrport: (addr,port) where this transport is listening for connections.
+        :param str args: ARGS field for this transport.
+        :param str optArgs: OPT-ARGS field for this transport.
+        """
+
+        methodLine = 'CMETHOD %s socks%s %s:%s' % (name, socksVersion,
+                addrport[0], addrport[1])
+        if args and len(args) > 0:
+            methodLine = methodLine + ' ARGS=' + args.join(',')
+        if optArgs and len(optArgs) > 0:
+            methodLine = methodLine + ' OPT-ARGS=' + args.join(',')
+        self.emit(methodLine)
 
-	    ==========  ========== ==========
-	    Key         Type       Value
-	    ==========  ========== ==========
-	    state_loc   string     Directory where the managed proxy should dump its state files (if needed).
-	    transports  list       Strings of the names of the transports that should be launched. The list can be empty.
-	    ==========  ========== ==========
 
-    :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
-    """
-    config = ClientConfig.fromEnv()
+def init(supported_transports):
+    """DEPRECATED. Use ClientTransportPlugin().init() instead."""
+    client = ClientTransportPlugin()
 
-    wanted = config.declareSupports(supported_transports)
+    client.init(supported_transports)
     retval = {}
-    retval['state_loc'] = config.getStateLocation()
-    retval['transports'] = wanted['transports']
+    retval['state_loc'] = client.config.getStateLocation()
+    retval['transports'] = client.served_transports
 
     return retval
 
 def reportSuccess(name, socksVersion, addrport, args=None, optArgs=None):
-    """
-    Report that a client transport was launched succesfully.
-
-    *Always call after successfully launching a transport.*
-
-    :param str name: Name of transport.
-    :param int socksVersion: The SOCKS protocol version.
-    :param tuple addrport: (addr,port) where this transport is listening for connections.
-    :param str args: ARGS field for this transport.
-    :param str args: OPT-ARGS field for this transport.
-    """
-
-    config = ClientConfig.fromEnv()
-    config.writeMethod(name, socksVersion, addrport, args, optArgs)
-
+    """DEPRECATED. Use ClientTransportPlugin().reportMethodSuccess() instead."""
+    config = ClientTransportPlugin()
+    config.reportMethodSuccess(name, socksVersion, addrport, args, optArgs)
 
 def reportFailure(name, message):
-    """
-    Report that a client transport failed to launch.
-
-    *Always call after failing to launch a transport.*
-
-    :param str name: Name of transport.
-    :param str message: Error message.
-    """
-
-    config = ClientConfig.fromEnv()
-    config.writeMethodError(name, message)
-
+    """DEPRECATED. Use ClientTransportPlugin().reportMethodError() instead."""
+    config = ClientTransportPlugin()
+    config.reportMethodError(name, message)
 
 def reportEnd():
-    """
-    Report that we are done launching transports.
-
-    *Call after you have launched all the transports you could launch.*
-    """
-
-    config = ClientConfig.fromEnv()
-    config.writeMethodEnd()
+    """DEPRECATED. Use ClientTransportPlugin().reportMethodsEnd() instead."""
+    config = ClientTransportPlugin()
+    config.reportMethodsEnd()
diff --git a/pyptlib/client_config.py b/pyptlib/client_config.py
index a84ccc6..dcc0636 100644
--- a/pyptlib/client_config.py
+++ b/pyptlib/client_config.py
@@ -12,52 +12,17 @@ from pyptlib.config import Config
 class ClientConfig(Config):
     """
     A client-side pyptlib configuration.
-
-    :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
     """
+
     @classmethod
-    def fromEnv(cls, stdout=sys.stdout):
+    def fromEnv(cls):
+        """
+        Build a ClientConfig from environment variables.
+
+        :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
+        """
         return cls(
             stateLocation = cls.getEnv('TOR_PT_STATE_LOCATION'),
             managedTransportVer = cls.getEnv('TOR_PT_MANAGED_TRANSPORT_VER').split(','),
             transports = cls.getEnv('TOR_PT_CLIENT_TRANSPORTS').split(','),
-            stdout = stdout
             )
-
-    def writeMethod(self, name, socksVersion, addrport, args=None, optArgs=None):
-        """
-        Write a message to stdout announcing that a transport was
-        successfully launched.
-
-        :param str name: Name of transport.
-        :param int socksVersion: The SOCKS protocol version.
-        :param tuple addrport: (addr,port) where this transport is listening for connections.
-        :param str args: ARGS field for this transport.
-        :param str optArgs: OPT-ARGS field for this transport.
-        """
-
-        methodLine = 'CMETHOD %s socks%s %s:%s' % (name, socksVersion,
-                addrport[0], addrport[1])
-        if args and len(args) > 0:
-            methodLine = methodLine + ' ARGS=' + args.join(',')
-        if optArgs and len(optArgs) > 0:
-            methodLine = methodLine + ' OPT-ARGS=' + args.join(',')
-        self.emit(methodLine)
-
-    def writeMethodError(self, name, message):
-        """
-        Write a message to stdout announcing that we failed to launch a transport.
-
-        :param str name: Name of transport.
-        :param str message: Error message.
-        """
-
-        self.emit('CMETHOD-ERROR %s %s' % (name, message))
-
-    def writeMethodEnd(self):
-        """
-        Write a message to stdout announcing that we finished launching transports..
-        """
-
-        self.emit('CMETHODS DONE')
-
diff --git a/pyptlib/config.py b/pyptlib/config.py
index 17c9f49..65dca68 100644
--- a/pyptlib/config.py
+++ b/pyptlib/config.py
@@ -7,7 +7,6 @@ Parts of pyptlib that are useful both to clients and servers.
 
 import os, sys
 
-SUPPORTED_TRANSPORT_VERSIONS = ['1']
 
 def env_has_k(k, v):
     """
@@ -32,12 +31,9 @@ class Config(object):
     :var list managedTransportVer: List of managed-proxy protocol versions that Tor supports.
     :var list transports: Strings of pluggable transport names that Tor wants us to handle.
     :var bool allTransportsEnabled: True if Tor wants us to spawn all the transports.
-
-    :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
     """
 
-    def __init__(self, stateLocation, managedTransportVer, transports,
-                 stdout=sys.stdout):
+    def __init__(self, stateLocation, managedTransportVer, transports):
         self.stateLocation = stateLocation
         self.managedTransportVer = managedTransportVer
         self.allTransportsEnabled = False
@@ -45,7 +41,6 @@ class Config(object):
             self.allTransportsEnabled = True
             transports.remove('*')
         self.transports = transports
-        self.stdout = stdout
 
     def getStateLocation(self):
         """
@@ -70,54 +65,6 @@ class Config(object):
 
         return self.allTransportsEnabled
 
-    def declareSupports(self, transports):
-        """
-        Declare to Tor the versions and transports that this PT supports.
-
-        :param list transports: List of transport methods this PT supports.
-
-        :returns: {"transports": wanted_transports} -- The subset of the
-            declared inputs that were actually wanted by Tor.
-        """
-        versions = SUPPORTED_TRANSPORT_VERSIONS
-        if type(transports) == str:
-            transports = [transports]
-
-        wanted_versions = [v for v in versions if v in self.managedTransportVer]
-        if not wanted_versions:
-            self.emit('VERSION-ERROR no-version')
-            raise EnvError("Unsupported managed proxy protocol version (%s)" %
-                           self.managedTransportVer)
-        else:
-            self.emit('VERSION %s' % wanted_versions[0])
-
-        if self.allTransportsEnabled:
-            wanted_transports = transports.keys()
-            unwanted_transports = []
-        else:
-            # return able in priority-order determined by plugin
-            wanted_transports = [t for t in transports if t in self.transports]
-            # return unable in priority-order as requested by Tor
-            unwanted_transports = [t for t in self.transports if t not in transports]
-
-        for t in unwanted_transports:
-            self.writeMethodError(t, 'unsupported transport')
-
-        return { 'transports': wanted_transports }
-
-    def writeMethodError(self, transportName, message):
-        raise NotImplementedError
-
-    def emit(self, msg):
-        """
-        Announce a message.
-
-        :param str msg: A message.
-        """
-
-        print >>self.stdout, msg
-        self.stdout.flush()
-
     @classmethod
     def getEnv(cls, key, validate=env_has_k):
         """
@@ -132,23 +79,24 @@ class Config(object):
 
         :returns: str -- The value of the envrionment variable.
 
-        :raises: :class:`pyptlib.config.EnvError` if environment
-        variable could not be found.
+        :raises: :class:`pyptlib.config.EnvError` if environment variable could not be
+                found, or if it did not pass validation.
         """
         try:
             return validate(key, os.getenv(key))
         except Exception, e:
-            message = 'ENV-ERROR %s' % e.message
-            print message
-            sys.stdout.flush()
-            raise EnvError(message)
-
+            raise EnvError(cause=e)
 
 class EnvError(Exception):
     """
     Thrown when the environment is incomplete or corrupted.
     """
-    pass
+    def __init__(self, message=None, cause=None):
+        self.message = message
+        self.cause = cause
+
+    def __str__(self):
+        return self.message or self.cause.message
 
 def checkClientMode():
     """
diff --git a/pyptlib/core.py b/pyptlib/core.py
new file mode 100644
index 0000000..440d89d
--- /dev/null
+++ b/pyptlib/core.py
@@ -0,0 +1,123 @@
+import sys
+
+from pyptlib.config import EnvError
+
+SUPPORTED_TRANSPORT_VERSIONS = ['1']
+
+
+class TransportPlugin(object):
+    """
+    Runtime process for a base TransportPlugin.
+
+    Note: you cannot initialise this directly; either use
+    ClientTransportPlugin() or ServerTransportPlugin().
+
+    :var pyptlib.config.Config config: Configuration passed from Tor.
+    :var file stdout: Output file descriptor to send status messages to.
+    :var list served_transports: List of transports served by the plugin,
+            populated by init().
+    """
+    def __init__(self, config=None, stdout=sys.stdout):
+        self.config = config
+        self.stdout = stdout
+        self.served_transports = None # set by _declareSupports
+
+    def init(self, supported_transports):
+        """
+        Initialise this transport plugin.
+
+        If no explicit config was given, we read it from the standard TOR_PT_*
+        environment variables.
+
+        Then, we declare to Tor the transports that this plugin supports.
+
+        After this is complete, you should initialise each transport method and
+        call (this).reportMethodSuccess() or reportMethodError() as appropriate.
+        When this is complete, you should then call reportMethodsEnd().
+
+        :param list transports: List of transport methods this PT supports.
+
+        :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
+                This also causes an ENV-ERROR line to be output, to inform Tor.
+        """
+        if not self.config:
+            self.config = self._loadConfigFromEnv()
+        self._declareSupports(supported_transports)
+
+    def _loadConfigFromEnv(self):
+        """
+        Load the plugin config from the standard TOR_PT_* envvars.
+
+        :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
+                This also causes an ENV-ERROR line to be output, to inform Tor.
+        """
+        try:
+            return self.configType.fromEnv()
+        except EnvError, e:
+            print >>self.stdout, 'ENV-ERROR %s' % str(e)
+            self.stdout.flush()
+            raise e
+
+    def _declareSupports(self, transports):
+        """
+        Declare to Tor the versions and transports that this PT supports.
+
+        :returns: {"transports": wanted_transports} -- The subset of the
+            declared inputs that were actually wanted by Tor.
+        """
+        versions = SUPPORTED_TRANSPORT_VERSIONS
+        if type(transports) == str:
+            transports = [transports]
+
+        cfg = self.config
+
+        wanted_versions = [v for v in versions if v in cfg.managedTransportVer]
+        if not wanted_versions:
+            self.emit('VERSION-ERROR no-version')
+            raise EnvError("Unsupported managed proxy protocol version (%s)" %
+                           cfg.managedTransportVer)
+        else:
+            self.emit('VERSION %s' % wanted_versions[0])
+
+        if cfg.allTransportsEnabled:
+            wanted_transports = transports.keys()
+            unwanted_transports = []
+        else:
+            # return able in priority-order determined by plugin
+            wanted_transports = [t for t in transports if t in cfg.transports]
+            # return unable in priority-order as requested by Tor
+            unwanted_transports = [t for t in cfg.transports if t not in transports]
+
+        for t in unwanted_transports:
+            self.reportMethodError(t, 'unsupported transport')
+
+        self.served_transports = wanted_transports
+        return { 'transports': wanted_transports }
+
+    def reportMethodError(self, name, message):
+        """
+        Write a message to stdout announcing that we failed to launch a transport.
+
+        :param str name: Name of transport.
+        :param str message: Error message.
+        """
+
+        self.emit('%s-ERROR %s %s' % (self.methodName, name, message))
+
+    def reportMethodsEnd(self):
+        """
+        Write a message to stdout announcing that we finished launching transports..
+        """
+
+        self.emit('%sS DONE' % self.methodName)
+
+    def emit(self, msg):
+        """
+        Announce a message.
+
+        :param str msg: A message.
+        """
+
+        print >>self.stdout, msg
+        self.stdout.flush()
+
diff --git a/pyptlib/server.py b/pyptlib/server.py
index 3972a10..6f38b7d 100644
--- a/pyptlib/server.py
+++ b/pyptlib/server.py
@@ -5,36 +5,42 @@
 Public server-side pyptlib API.
 """
 
-from pyptlib.config import EnvError
+from pyptlib.core import TransportPlugin
 from pyptlib.server_config import ServerConfig
 
 
-def init(supported_transports):
+class ServerTransportPlugin(TransportPlugin):
+    """
+    Runtime process for a server TransportPlugin.
     """
-    Bootstrap server-side managed-proxy mode.
+    configType = ServerConfig
+    methodName = 'SMETHOD'
 
-    *Call in the beginning of your application.*
+    def reportMethodSuccess(self, name, addrport, options):
+        """
+        Write a message to stdout announcing that a server transport was
+        successfully launched.
 
-    :param list supported_transports: Names of the transports that the application supports.
+        :param str name: Name of transport.
+        :param tuple addrport: (addr,port) where this transport is listening for connections.
+        :param str options: Transport options.
+        """
 
-    :returns: dictionary that contains information for the application:
+        if options:
+            self.emit('SMETHOD %s %s:%s %s' % (name, addrport[0],
+                      addrport[1], options))
+        else:
+            self.emit('SMETHOD %s %s:%s' % (name, addrport[0],
+                      addrport[1]))
 
-	    ===============   ========== ==========
-	    Key               Type       Value
-	    ================  ========== ==========
-	    state_loc         string     Directory where the managed proxy should dump its state files (if needed).
-	    orport            tuple      (ip,port) tuple pointing to Tor's ORPort.
-	    ext_orport        tuple      (ip,port) tuple pointing to Tor's Extended ORPort. None if Extended ORPort is not supported.
-	    transports        dict       A dictionary 'transport => (ip,port)' where 'transport' is the name of the transport that should be spawned, and '(ip,port)' is the location where the transport should bind. The dictionary can be empty.
-            auth_cookie_file  string     Directory where the managed proxy should find the Extended ORPort authentication cookie.
-	    ================  ========== ==========
 
-    :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
-    """
-    config = ServerConfig.fromEnv()
-    wanted = config.declareSupports(supported_transports)
+def init(supported_transports):
+    """DEPRECATED. Use ServerTransportPlugin().init() instead."""
+    server = ServerTransportPlugin()
+    server.init(supported_transports)
+    config = server.config
     transports = dict(((k, v) for k, v in config.getServerBindAddresses().items()
-                              if k in wanted['transports']))
+                              if k in server.served_transports))
     retval = {}
     retval['state_loc'] = config.getStateLocation()
     retval['orport'] = config.getORPort()
@@ -45,40 +51,18 @@ def init(supported_transports):
     return retval
 
 def reportSuccess(name, addrport, options):
-    """
-    Report that a server transport was launched succesfully.
-
-    *Always call after successfully launching a transport.*
-
-    :param str name: Name of transport.
-    :param tuple addrport: (addr,port) where this transport is listening for connections.
-    :param str options: Transport options.
-    """
-
-    config = ServerConfig.fromEnv()
-    config.writeMethod(name, addrport, options)
+    """DEPRECATED. Use ClientTransportPlugin().reportMethodSuccess() instead."""
+    config = ServerTransportPlugin()
+    config.reportMethodSuccess(name, addrport, options)
 
 
 def reportFailure(name, message):
-    """
-    Report that a server transport failed to launch.
-
-    *Always call after failing to launch a transport.*
-
-    :param str name: Name of transport.
-    :param str message: Error message.
-    """
-
-    config = ServerConfig.fromEnv()
-    config.writeMethodError(name, message)
+    """DEPRECATED. Use ClientTransportPlugin().reportMethodError() instead."""
+    config = ServerTransportPlugin()
+    config.reportMethodError(name, message)
 
 
 def reportEnd():
-    """
-    Report that we are done launching transports.
-
-    *Call after you have launched all the transports you could launch.*
-    """
-
-    config = ServerConfig.fromEnv()
-    config.writeMethodEnd()
+    """DEPRECATED. Use ClientTransportPlugin().reportMethodsEnd() instead."""
+    config = ServerTransportPlugin()
+    config.reportMethodsEnd()
diff --git a/pyptlib/server_config.py b/pyptlib/server_config.py
index 9fd8130..88ffeda 100644
--- a/pyptlib/server_config.py
+++ b/pyptlib/server_config.py
@@ -19,16 +19,19 @@ class ServerConfig(config.Config):
     :var tuple extendedORPort: (ip,port) pointing to Tor's Extended ORPort. None if Extended ORPort is not supported.
     :var dict serverBindAddr: A dictionary {<transport> : [<addr>, <port>]}, where <transport> is the name of the transport that must be spawned, and [<addr>, <port>] is a list containing the location where that transport should bind. The dictionary can be empty.
     :var string authCookieFile: String representing the filesystem path where the Extended ORPort Authentication cookie is stored. None if Extended ORPort authentication is not supported.
-
-    :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
     """
+
     @classmethod
-    def fromEnv(cls, stdout=sys.stdout):
+    def fromEnv(cls):
         """
-        TOR_PT_EXTENDED_SERVER_PORT is optional; tor uses the empty
-        string as its value if it does not support the Extended
-        ORPort.
+        Build a ServerConfig from environment variables.
+
+        :raises: :class:`pyptlib.config.EnvError` if environment was incomplete or corrupted.
         """
+
+        # TOR_PT_EXTENDED_SERVER_PORT is optional; tor uses the empty
+        # string as its value if it does not support the Extended
+        # ORPort.
         def empty_or_valid_addr(k, v):
             v = env_has_k(k, v)
             if v == '': return None
@@ -79,15 +82,13 @@ class ServerConfig(config.Config):
             serverBindAddr = serverBindAddr,
             ORPort = ORPort,
             extendedORPort = extendedORPort,
-            authCookieFile = authCookieFile,
-            stdout = stdout
+            authCookieFile = authCookieFile
             )
 
     def __init__(self, stateLocation, managedTransportVer, transports,
-                 serverBindAddr, ORPort, extendedORPort, authCookieFile,
-                 stdout=sys.stdout):
+                 serverBindAddr, ORPort, extendedORPort, authCookieFile):
         config.Config.__init__(self,
-            stateLocation, managedTransportVer, transports, stdout)
+            stateLocation, managedTransportVer, transports)
         self.serverBindAddr = serverBindAddr
         self.ORPort = ORPort
         self.extendedORPort = extendedORPort
@@ -122,39 +123,3 @@ class ServerConfig(config.Config):
         :returns: :attr:`pyptlib.server_config.ServerConfig.authCookieFile`
         """
         return self.authCookieFile
-
-    def writeMethod(self, name, addrport, options):
-        """
-        Write a message to stdout announcing that a server transport was
-        successfully launched.
-
-        :param str name: Name of transport.
-        :param tuple addrport: (addr,port) where this transport is listening for connections.
-        :param str options: Transport options.
-        """
-
-        if options:
-            self.emit('SMETHOD %s %s:%s %s' % (name, addrport[0],
-                      addrport[1], options))
-        else:
-            self.emit('SMETHOD %s %s:%s' % (name, addrport[0],
-                      addrport[1]))
-
-    def writeMethodError(self, name, message):  # SMETHOD-ERROR
-        """
-        Write a message to stdout announcing that we failed to launch
-        a transport.
-
-        :param str name: Name of transport.
-        :param str message: Error message.
-        """
-
-        self.emit('SMETHOD-ERROR %s %s' % (name, message))
-
-    def writeMethodEnd(self):  # SMETHODS DONE
-        """
-        Write a message to stdout announcing that we finished
-        launching transports..
-        """
-
-        self.emit('SMETHODS DONE')

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/pyptlib.git



More information about the Pkg-privacy-commits mailing list