[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