Finger演化:一个Twisted finger客户端

The Evolution of Finger: a Twisted finger client -- dreamingk [2004-08-09 02:15:36]

1. 介绍(Introduction)

这是Twisted教程《Twisted入门 - Finger演化》的第九部分。

This is the ninth part of the Twisted tutorial Twisted from Scratch, or The Evolution of Finger.

在这一部分中,我们为finger服务器开发了一个客户端:一个finger代理服务器,它可以向另一个finger服务器转发请求。

In this part, we develop a client for the finger server: a proxy finger server which forwards requests to another finger server.

2. Finger代理服务器(Finger Proxy)

用Twisted编写新的客户端很象编写新的服务器。我们实现了这样的协议,它只是收集所有的数据,并将它们发给factory。此factory维持着一个deferred,无论是连接失败或是成功,这个deferred都将被触发。当我们使用这个客户端时,首先要确保这个deferred永远不会失败,在例子中是通过产生一个消息来实现的。对只返回deferred的客户端实现一个包装器(wrapper)是通常的模式。尽管与直接使用factory相比缺少灵活性,但它要方便得多。

Writing new clients with Twisted is much like writing new servers. We implement the protocol, which just gathers up all the data, and give it to the factory. The factory keeps a deferred which is triggered if the connection either fails or succeeds. When we use the client, we first make sure the deferred will never fail, by producing a message in that case. Implementing a wrapper around client which just returns the deferred is a common pattern. While less flexible than using the factory directly, it's also more convenient.

   1 # finger proxy
   2 from twisted.application import internet, service
   3 from twisted.internet import defer, protocol, reactor
   4 from twisted.protocols import basic
   5 from twisted.python import components
   6 
   7 
   8 def catchError(err):
   9     return "Internal error in server"
  10 
  11 class IFingerService(components.Interface):
  12 
  13     def getUser(self, user):
  14         """Return a deferred returning a string"""
  15 
  16     def getUsers(self):
  17         """Return a deferred returning a list of strings"""
  18 
  19 
  20 class IFingerFactory(components.Interface):
  21 
  22     def getUser(self, user):
  23         """Return a deferred returning a string"""
  24 
  25     def buildProtocol(self, addr):
  26         """Return a protocol returning a string"""
  27 
  28 class FingerProtocol(basic.LineReceiver):
  29 
  30     def lineReceived(self, user):
  31         d = self.factory.getUser(user)
  32         d.addErrback(catchError)
  33         def writeValue(value):
  34             self.transport.write(value)
  35             self.transport.loseConnection()
  36         d.addCallback(writeValue)
  37 
  38 
  39 
  40 class FingerFactoryFromService(protocol.ClientFactory):
  41 
  42     __implements__ = IFingerFactory,
  43 
  44     protocol = FingerProtocol
  45 
  46     def __init__(self, service):
  47         self.service = service
  48 
  49     def getUser(self, user):
  50         return self.service.getUser(user)
  51 
  52 
  53 components.registerAdapter(FingerFactoryFromService,
  54                            IFingerService,
  55                            IFingerFactory)
  56 
  57 class FingerClient(protocol.Protocol):
  58 
  59     def connectionMade(self):
  60         self.transport.write(self.factory.user+"\r\n")
  61         self.buf = []
  62 
  63     def dataReceived(self, data):
  64         self.buf.append(data)
  65 
  66     def connectionLost(self):
  67         self.factory.gotData(''.join(self.buf))
  68 
  69 class FingerClientFactory(protocol.ClientFactory):
  70 
  71     protocol = FingerClient
  72 
  73     def __init__(self, user):
  74         self.user = user
  75         self.d = defer.Deferred()
  76 
  77     def clientConnectionFailed(self, _, reason):
  78         self.d.errback(reason)
  79 
  80     def gotData(self, data):
  81         self.d.callback(data)
  82 
  83 
  84 def finger(user, host, port=79):
  85     f = FingerClientFactory(user)
  86     reactor.connectTCP(host, port, f)
  87     return f.d
  88 
  89 
  90 class ProxyFingerService(service.Service):
  91     __implements__ = IFingerService
  92 
  93     def getUser(self, user):
  94         try:
  95             user, host = user.split('@', 1)
  96         except:
  97             user = user.strip()
  98             host = '127.0.0.1'
  99         ret = finger(user, host)
 100         ret.addErrback(lambda _: "Could not connect to remote host")
 101         return ret
 102 
 103     def getUsers(self):
 104         return defer.succeed([])
 105 
 106 application = service.Application('finger', uid=1, gid=1)
 107 f = ProxyFingerService()
 108 internet.TCPServer(7779, IFingerFactory(f)).setServiceParent(
 109     service.IServiceCollection(application))

Source listing - listings/finger/fingerproxy.py

return index-->TwistedTUT

Version: 1.3.0