The Evolution of Finger: a clean web frontend -- dreamingk [2004-08-09 02:12:35]

1. 介绍 Introduction

此为 Twisted 教程的第6部分 我们示范使用 Woven 模板系统来添加一个 网络前端 web frontend

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

In this part, we demonstrate adding a web frontend using the Woven templating system.

2. 使用 Woven

现在我们不再编辑HTML代码了,而是使用Woven, Woven是一个历史悠久的web模板系统。 它的主要特征是不在HTML中嵌入任何代码,而且可以和deferred对象的返回结果透明的整合在一起。

Here we convert to using Woven, instead of manually constructing HTML snippets. Woven is a sophisticated web templating system. Its main features are to disallow any code inside the HTML, and transparent integration with deferred results.

   1 # Do everything properly, and componentize
   2 from twisted.application import internet, service
   3 from twisted.internet import protocol, reactor, defer
   4 from twisted.protocols import basic, irc
   5 from twisted.python import components
   6 from twisted.web import resource, server, static, xmlrpc, microdom
   7 from twisted.web.woven import page, model, interfaces
   8 import cgi
   9 
  10 class IFingerService(components.Interface):
  11 
  12     def getUser(self, user):
  13         """Return a deferred returning a string"""
  14 
  15     def getUsers(self):
  16         """Return a deferred returning a list of strings"""
  17 
  18 class IFingerSetterService(components.Interface):
  19 
  20     def setUser(self, user, status):
  21         """Set the user's status to something"""
  22 
  23 def catchError(err):
  24     return "Internal error in server"
  25 
  26 class FingerProtocol(basic.LineReceiver):
  27 
  28     def lineReceived(self, user):
  29         d = self.factory.getUser(user)
  30         d.addErrback(catchError)
  31         def writeValue(value):
  32             self.transport.write(value+'\n')
  33             self.transport.loseConnection()
  34         d.addCallback(writeValue)
  35 
  36 
  37 class IFingerFactory(components.Interface):
  38 
  39     def getUser(self, user):
  40         """Return a deferred returning a string"""
  41 
  42     def buildProtocol(self, addr):
  43         """Return a protocol returning a string"""
  44 
  45 
  46 class FingerFactoryFromService(protocol.ServerFactory):
  47 
  48     __implements__ = IFingerFactory,
  49 
  50     protocol = FingerProtocol
  51 
  52     def __init__(self, service):
  53         self.service = service
  54 
  55     def getUser(self, user):
  56         return self.service.getUser(user)
  57 
  58 components.registerAdapter(FingerFactoryFromService,
  59                            IFingerService,
  60                            IFingerFactory)
  61 
  62 class FingerSetterProtocol(basic.LineReceiver):
  63 
  64     def connectionMade(self):
  65         self.lines = []
  66 
  67     def lineReceived(self, line):
  68         self.lines.append(line)
  69 
  70     def connectionLost(self, reason):
  71         if len(self.lines) == 2:
  72             self.factory.setUser(*self.lines)
  73 
  74 
  75 class IFingerSetterFactory(components.Interface):
  76 
  77     def setUser(self, user, status):
  78         """Return a deferred returning a string"""
  79 
  80     def buildProtocol(self, addr):
  81         """Return a protocol returning a string"""
  82 
  83 
  84 class FingerSetterFactoryFromService(protocol.ServerFactory):
  85 
  86     __implements__ = IFingerSetterFactory,
  87 
  88     protocol = FingerSetterProtocol
  89 
  90     def __init__(self, service):
  91         self.service = service
  92 
  93     def setUser(self, user, status):
  94         self.service.setUser(user, status)
  95 
  96 
  97 components.registerAdapter(FingerSetterFactoryFromService,
  98                            IFingerSetterService,
  99                            IFingerSetterFactory)
 100 
 101 class IRCReplyBot(irc.IRCClient):
 102 
 103     def connectionMade(self):
 104         self.nickname = self.factory.nickname
 105         irc.IRCClient.connectionMade(self)
 106 
 107     def privmsg(self, user, channel, msg):
 108         user = user.split('!')[0]
 109         if self.nickname.lower() == channel.lower():
 110             d = self.factory.getUser(msg)
 111             d.addErrback(catchError)
 112             d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
 113             d.addCallback(lambda m: self.msg(user, m))
 114 
 115 
 116 class IIRCClientFactory(components.Interface):
 117 
 118     """
 119     @ivar nickname
 120     """
 121 
 122     def getUser(self, user):
 123         """Return a deferred returning a string"""
 124 
 125     def buildProtocol(self, addr):
 126         """Return a protocol"""
 127 
 128 
 129 class IRCClientFactoryFromService(protocol.ClientFactory):
 130 
 131     __implements__ = IIRCClientFactory,
 132 
 133     protocol = IRCReplyBot
 134     nickname = None
 135 
 136     def __init__(self, service):
 137         self.service = service
 138 
 139     def getUser(self, user):
 140         return self.service.getUser(user)
 141 
 142 components.registerAdapter(IRCClientFactoryFromService,
 143                            IFingerService,
 144                            IIRCClientFactory)
 145 
 146 class UsersModel(model.MethodModel):
 147 
 148     def initialize(self, *args, **kwargs):
 149         self.service=args[0]
 150 
 151     def wmfactory_users(self, request):
 152         return self.service.getUsers()
 153 
 154 components.registerAdapter(UsersModel, IFingerService, interfaces.IModel)
 155 
 156 class UserStatusTree(page.Page):
 157 
 158     template = """<html><head><title>Users</title></head><body>
 159     <h1>Users</h1>
 160     <ul model="users" view="List">
 161     <li pattern="listItem"><a view="Anchor" /></li>
 162     </ul></body></html>"""
 163 
 164     def initialize(self, *args, **kwargs):
 165         self.service=args[0]
 166 
 167     def getDynamicChild(self, path, request):
 168         return UserStatus(user=path, service=self.service)
 169 
 170     def wchild_RPC2 (self, request):
 171         return UserStatusXR(self.service)
 172 
 173 components.registerAdapter(UserStatusTree, IFingerService, resource.IResource)
 174 
 175 
 176 class UserStatus(page.Page):
 177 
 178     template='''<html><head><title view="Text" model="user"/></head>
 179     <body><h1 view="Text" model="user"/>
 180     <p model="status" view="Text" />
 181     </body></html>'''
 182 
 183     def initialize(self, **kwargs):
 184         self.user = kwargs['user']
 185         self.service = kwargs['service']
 186 
 187     def wmfactory_user(self, request):
 188         return self.user
 189 
 190     def wmfactory_status(self, request):
 191         return self.service.getUser(self.user)
 192 
 193 
 194 class UserStatusXR(xmlrpc.XMLRPC):
 195 
 196     def __init__(self, service):
 197         xmlrpc.XMLRPC.__init__(self)
 198         self.service = service
 199 
 200     def xmlrpc_getUser(self, user):
 201         return self.service.getUser(user)
 202 
 203     def xmlrpc_getUsers(self):
 204         return self.service.getUsers()
 205 
 206 
 207 class FingerService(service.Service):
 208 
 209     __implements__ = IFingerService,
 210 
 211     def __init__(self, filename):
 212         self.filename = filename
 213         self._read()
 214 
 215     def _read(self):
 216         self.users = {}
 217         for line in file(self.filename):
 218             user, status = line.split(':', 1)
 219             user = user.strip()
 220             status = status.strip()
 221             self.users[user] = status
 222         self.call = reactor.callLater(30, self._read)
 223 
 224     def getUser(self, user):
 225         return defer.succeed(self.users.get(user, "No such user"))
 226 
 227     def getUsers(self):
 228         return defer.succeed(self.users.keys())
 229 
 230 
 231 application = service.Application('finger', uid=1, gid=1)
 232 f = FingerService('/etc/users')
 233 serviceCollection = service.IServiceCollection(application)
 234 internet.TCPServer(79, IFingerFactory(f)
 235                    ).setServiceParent(serviceCollection)
 236 internet.TCPServer(8000, server.Site(resource.IResource(f))
 237                    ).setServiceParent(serviceCollection)
 238 i = IIRCClientFactory(f)
 239 i.nickname = 'fingerbot'
 240 internet.TCPClient('irc.freenode.org', 6667, i
 241                    ).setServiceParent(serviceCollection)
 242 
 243 Source listing - listings/finger/finger20.py

return index-->TwistedTUT