The Evolution of Finger: a clean web frontend -- dreamingk [2004-08-09 02:12:35]
Contents
介绍 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.
使用 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