##language:zh ''' Finger演化:整理finger代码 The Evolution of Finger: cleaning up the finger code ''' -- dreamingk [<>] <> == 介绍(Introduction) == 这是Twisted教程《Twisted入门 - Finger演化》的第三部分。 This is the third part of the Twisted tutorial Twisted from Scratch, or The Evolution of Finger. 在本节教程中,我们将整理代码,以便让它更接近可读和可扩展的风格。 In this section of the tutorial, we'll clean up our code so that it is closer to a readable and extendable style. === 编写可读代码(Write Readable Code) === Application的上一个版本有许多的伎俩。我们避开了子类化,不支持在web上的用户列表之类的事情,和去掉所有的空行 -- 所有这些是为了让程序更短。这里我们将后退一步,子类化(更自然地说是一个子类)可以做一些接受多行的工作来处理它们,等等此类事情。这里显示了一种开发Twisted应用的更好的风格,尽管在前一阶段中的伎俩有时可以用在被丢弃的原型中。 The last version of the application had a lot of hacks. We avoided sub-classing, didn't support things like user listings over the web, and removed all blank lines -- all in the interest of code which is shorter. Here we take a step back, subclass what is more naturally a subclass, make things which should take multiple lines take them, etc. This shows a much better style of developing Twisted applications, though the hacks in the previous stages are sometimes used in throw-away prototypes. {{{ #!python # Do everything properly from twisted.application import internet, service from twisted.internet import protocol, reactor, defer from twisted.protocols import basic, irc from twisted.web import resource, server, static, xmlrpc import cgi def catchError(err): return "Internal error in server" class FingerProtocol(basic.LineReceiver): def lineReceived(self, user): d = self.factory.getUser(user) d.addErrback(catchError) def writeValue(value): self.transport.write(value+'\n') self.transport.loseConnection() d.addCallback(writeValue) class FingerSetterProtocol(basic.LineReceiver): def connectionMade(self): self.lines = [] def lineReceived(self, line): self.lines.append(line) def connectionLost(self, reason): self.factory.setUser(*self.lines[:2]) class IRCReplyBot(irc.IRCClient): def connectionMade(self): self.nickname = self.factory.nickname irc.IRCClient.connectionMade(self) def privmsg(self, user, channel, msg): user = user.split('!')[0] if self.nickname.lower() == channel.lower(): d = self.factory.getUser(msg) d.addErrback(catchError) d.addCallback(lambda m: "Status of %s: %s" % (msg, m)) d.addCallback(lambda m: self.msg(user, m)) class UserStatusTree(resource.Resource): def __init__(self, service): resource.Resource.__init__(self) self.service = service def render_GET(self, request): d = self.service.getUsers() def formatUsers(users): l = ['
  • %s
  • ' % (user, user) for user in users] return '' d.addCallback(formatUsers) d.addCallback(request.write) d.addCallback(lambda _: request.finish()) return server.NOT_DONE_YET def getChild(self, path, request): if path=="": return UserStatusTree(self.service) else: return UserStatus(path, self.service) class UserStatus(resource.Resource): def __init__(self, user, service): resource.Resource.__init__(self) self.user = user self.service = service def render_GET(self, request): d = self.service.getUser(self.user) d.addCallback(cgi.escape) d.addCallback(lambda m: '

    %s

    '%self.user+'

    %s

    '%m) d.addCallback(request.write) d.addCallback(lambda _: request.finish()) return server.NOT_DONE_YET class UserStatusXR(xmlrpc.XMLRPC): def __init__(self, service): xmlrpc.XMLRPC.__init__(self) self.service = service def xmlrpc_getUser(self, user): return self.service.getUser(user) class FingerService(service.Service): def __init__(self, filename): self.filename = filename self._read() def _read(self): self.users = {} for line in file(self.filename): user, status = line.split(':', 1) user = user.strip() status = status.strip() self.users[user] = status self.call = reactor.callLater(30, self._read) def getUser(self, user): return defer.succeed(self.users.get(user, "No such user")) def getUsers(self): return defer.succeed(self.users.keys()) def getFingerFactory(self): f = protocol.ServerFactory() f.protocol = FingerProtocol f.getUser = self.getUser return f def getResource(self): r = UserStatusTree(self) x = UserStatusXR(self) r.putChild('RPC2', x) return r def getIRCBot(self, nickname): f = protocol.ReconnectingClientFactory() f.protocol = IRCReplyBot f.nickname = nickname f.getUser = self.getUser return f application = service.Application('finger', uid=1, gid=1) f = FingerService('/etc/users') serviceCollection = service.IServiceCollection(application) internet.TCPServer(79, f.getFingerFactory() ).setServiceParent(serviceCollection) internet.TCPServer(8000, server.Site(f.getResource()) ).setServiceParent(serviceCollection) internet.TCPClient('irc.freenode.org', 6667, f.getIRCBot('fingerbot') ).setServiceParent(serviceCollection) }}} Source listing - listings/finger/finger18.py return index-->[[TwistedTUT]]