Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Branch: master
156 lines (99 sloc) 3.86 KB
# This is the Twisted Poetry Proxy, version 3.0
import optparse
from twisted.internet.defer import Deferred, succeed
from twisted.internet.protocol import ClientFactory, ServerFactory, Protocol
def parse_args():
usage = """usage: %prog [options] [hostname]:port
This is the Poetry Proxy, version 3.0.
python [hostname]:port
If you are in the base directory of the twisted-intro package,
you could run it like this:
python twisted-server-4/ 10000
to proxy the poem for the server running on port 10000.
parser = optparse.OptionParser(usage)
help = "The port to listen on. Default to a random available port."
parser.add_option('--port', type='int', help=help)
help = "The interface to listen on. Default is localhost."
parser.add_option('--iface', help=help, default='localhost')
options, args = parser.parse_args()
if len(args) != 1:
parser.error('Provide exactly one server address.')
def parse_address(addr):
if ':' not in addr:
host = ''
port = addr
host, port = addr.split(':', 1)
if not port.isdigit():
parser.error('Ports must be integers.')
return host, int(port)
return options, parse_address(args[0])
class PoetryProxyProtocol(Protocol):
def connectionMade(self):
self.deferred = self.factory.service.get_poem()
self.deferred.addBoth(lambda r: self.transport.loseConnection())
def connectionLost(self, reason):
if self.deferred is not None:
deferred, self.deferred = self.deferred, None
deferred.cancel() # cancel the deferred if it hasn't fired
class PoetryProxyFactory(ServerFactory):
protocol = PoetryProxyProtocol
def __init__(self, service):
self.service = service
class PoetryClientProtocol(Protocol):
poem = ''
def dataReceived(self, data):
self.poem += data
def connectionLost(self, reason):
def poemReceived(self, poem):
class PoetryClientFactory(ClientFactory):
protocol = PoetryClientProtocol
def __init__(self, deferred):
self.deferred = deferred
def poem_finished(self, poem):
if self.deferred is not None:
d, self.deferred = self.deferred, None
def clientConnectionFailed(self, connector, reason):
if self.deferred is not None:
d, self.deferred = self.deferred, None
class ProxyService(object):
poem = None # the cached poem
def __init__(self, host, port): = host
self.port = port
def get_poem(self):
if self.poem is not None:
print 'Using cached poem.'
# return an already-fired deferred
return succeed(self.poem)
def canceler(d):
print 'Canceling poem download.'
factory.deferred = None
print 'Fetching poem from server.'
deferred = Deferred(canceler)
factory = PoetryClientFactory(deferred)
from twisted.internet import reactor
connector = reactor.connectTCP(, self.port, factory)
return factory.deferred
def set_poem(self, poem):
self.poem = poem
return poem
def main():
options, server_addr = parse_args()
service = ProxyService(*server_addr)
factory = PoetryProxyFactory(service)
from twisted.internet import reactor
port = reactor.listenTCP(options.port or 0, factory,
print 'Proxying %s on %s.' % (server_addr, port.getHost())
if __name__ == '__main__':
Jump to Line
Something went wrong with that request. Please try again.