Finger演化:使用单一factory支持多种协议 The Evolution of Finger: using a single factory for multiple protocols
1. 介绍(Introduction)
这是Twisted教程《Twisted入门 - Finger演化》的第八部分。
This is the eighth part of the Twisted tutorial Twisted from Scratch, or The Evolution of Finger.
在这部分中,我们向web前端增加 HTTPS 支持,用于展示如何让单一factory在多个端口上监听(listen)。
In this part, we add HTTPS support to our web frontend, showing how to have a single factory listen on multiple ports.
2. HTTPS支持(Support HTTPS)
编写一个 HTTPS 站点我们只需要编写一个上下文(context) factory(在本例中,它会从一个特定的文件中装入证书),接着使用twisted.application.internet.SSLServer方法。请注意一个facotry(在本例中是一个站点)可以使用多种协议在多个端口上进行监听。
All we need to do to code an HTTPS site is just write a context factory (in this case, which loads the certificate from a certain file) and then use the twisted.application.internet.SSLServer method. Note that one factory (in this case, a site) can listen on multiple ports with multiple protocols.
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 from twisted.spread import pb
9 from OpenSSL import SSL
10 import cgi
11
12 class IFingerService(components.Interface):
13
14 def getUser(self, user):
15 """Return a deferred returning a string"""
16
17 def getUsers(self):
18 """Return a deferred returning a list of strings"""
19
20 class IFingerSetterService(components.Interface):
21
22 def setUser(self, user, status):
23 """Set the user's status to something"""
24
25 def catchError(err):
26 return "Internal error in server"
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+'\n')
35 self.transport.loseConnection()
36 d.addCallback(writeValue)
37
38
39 class IFingerFactory(components.Interface):
40
41 def getUser(self, user):
42 """Return a deferred returning a string"""
43
44 def buildProtocol(self, addr):
45 """Return a protocol returning a string"""
46
47
48 class FingerFactoryFromService(protocol.ServerFactory):
49
50 __implements__ = IFingerFactory,
51
52 protocol = FingerProtocol
53
54 def __init__(self, service):
55 self.service = service
56
57 def getUser(self, user):
58 return self.service.getUser(user)
59
60 components.registerAdapter(FingerFactoryFromService,
61 IFingerService,
62 IFingerFactory)
63
64 class FingerSetterProtocol(basic.LineReceiver):
65
66 def connectionMade(self):
67 self.lines = []
68
69 def lineReceived(self, line):
70 self.lines.append(line)
71
72 def connectionLost(self, reason):
73 if len(self.lines) == 2:
74 self.factory.setUser(*self.lines)
75
76
77 class IFingerSetterFactory(components.Interface):
78
79 def setUser(self, user, status):
80 """Return a deferred returning a string"""
81
82 def buildProtocol(self, addr):
83 """Return a protocol returning a string"""
84
85
86 class FingerSetterFactoryFromService(protocol.ServerFactory):
87
88 __implements__ = IFingerSetterFactory,
89
90 protocol = FingerSetterProtocol
91
92 def __init__(self, service):
93 self.service = service
94
95 def setUser(self, user, status):
96 self.service.setUser(user, status)
97
98
99 components.registerAdapter(FingerSetterFactoryFromService,
100 IFingerSetterService,
101 IFingerSetterFactory)
102
103 class IRCReplyBot(irc.IRCClient):
104
105 def connectionMade(self):
106 self.nickname = self.factory.nickname
107 irc.IRCClient.connectionMade(self)
108
109 def privmsg(self, user, channel, msg):
110 user = user.split('!')[0]
111 if self.nickname.lower() == channel.lower():
112 d = self.factory.getUser(msg)
113 d.addErrback(catchError)
114 d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
115 d.addCallback(lambda m: self.msg(user, m))
116
117
118 class IIRCClientFactory(components.Interface):
119
120 """
121 @ivar nickname
122 """
123
124 def getUser(self, user):
125 """Return a deferred returning a string"""
126
127 def buildProtocol(self, addr):
128 """Return a protocol"""
129
130
131 class IRCClientFactoryFromService(protocol.ClientFactory):
132
133 __implements__ = IIRCClientFactory,
134
135 protocol = IRCReplyBot
136 nickname = None
137
138 def __init__(self, service):
139 self.service = service
140
141 def getUser(self, user):
142 return self.service.getUser(user)
143
144 components.registerAdapter(IRCClientFactoryFromService,
145 IFingerService,
146 IIRCClientFactory)
147
148 class UsersModel(model.MethodModel):
149
150 def initialize(self, *args, **kwargs):
151 self.service=args[0]
152
153 def wmfactory_users(self, request):
154 return self.service.getUsers()
155
156 components.registerAdapter(UsersModel, IFingerService, interfaces.IModel)
157
158 class UserStatusTree(page.Page):
159
160 template = """<html><head><title>Users</title></head><body>
161 <h1>Users</h1>
162 <ul model="users" view="List">
163 <li pattern="listItem"><a view="Anchor" /></li>
164 </ul></body></html>"""
165
166 def initialize(self, *args, **kwargs):
167 self.service=args[0]
168
169 def getDynamicChild(self, path, request):
170 return UserStatus(user=path, service=self.service)
171
172 def wchild_RPC2 (self, request):
173 return UserStatusXR(self.service)
174
175 components.registerAdapter(UserStatusTree, IFingerService, resource.IResource)
176
177
178 class UserStatus(page.Page):
179
180 template='''<html><head><title view="Text" model="user"/></head>
181 <body><h1 view="Text" model="user"/>
182 <p model="status" view="Text" />
183 </body></html>'''
184
185 def initialize(self, **kwargs):
186 self.user = kwargs['user']
187 self.service = kwargs['service']
188
189 def wmfactory_user(self, request):
190 return self.user
191
192 def wmfactory_status(self, request):
193 return self.service.getUser(self.user)
194
195
196 class UserStatusXR(xmlrpc.XMLRPC):
197
198 def __init__(self, service):
199 xmlrpc.XMLRPC.__init__(self)
200 self.service = service
201
202 def xmlrpc_getUser(self, user):
203 return self.service.getUser(user)
204
205 def xmlrpc_getUsers(self):
206 return self.service.getUsers()
207
208
209 class IPerspectiveFinger(components.Interface):
210
211 def remote_getUser(self, username):
212 """return a user's status"""
213
214 def remote_getUsers(self):
215 """return a user's status"""
216
217 class PerspectiveFingerFromService(pb.Root):
218
219 __implements__ = pb.Root.__implements__, IPerspectiveFinger
220
221 def __init__(self, service):
222 self.service = service
223
224 def remote_getUser(self, username):
225 return self.service.getUser(username)
226
227 def remote_getUsers(self):
228 return self.service.getUsers()
229
230 components.registerAdapter(PerspectiveFingerFromService,
231 IFingerService,
232 IPerspectiveFinger)
233
234
235 class FingerService(service.Service):
236
237 __implements__ = IFingerService,
238
239 def __init__(self, filename):
240 self.filename = filename
241 self._read()
242
243 def _read(self):
244 self.users = {}
245 for line in file(self.filename):
246 user, status = line.split(':', 1)
247 user = user.strip()
248 status = status.strip()
249 self.users[user] = status
250 self.call = reactor.callLater(30, self._read)
251
252 def getUser(self, user):
253 return defer.succeed(self.users.get(user, "No such user"))
254
255 def getUsers(self):
256 return defer.succeed(self.users.keys())
257
258
259 class ServerContextFactory:
260
261 def getContext(self):
262 """Create an SSL context.
263
264 This is a sample implementation that loads a certificate from a file
265 called 'server.pem'."""
266 ctx = SSL.Context(SSL.SSLv23_METHOD)
267 ctx.use_certificate_file('server.pem')
268 ctx.use_privatekey_file('server.pem')
269 return ctx
270
271
272 application = service.Application('finger', uid=1, gid=1)
273 f = FingerService('/etc/users')
274 serviceCollection = service.IServiceCollection(application)
275 internet.TCPServer(79, IFingerFactory(f)
276 ).setServiceParent(serviceCollection)
277 site = server.Site(resource.IResource(f))
278 internet.TCPServer(8000, site
279 ).setServiceParent(serviceCollection)
280 internet.SSLServer(443, site, ServerContextFactory()
281 ).setServiceParent(serviceCollection)
282 i = IIRCClientFactory(f)
283 i.nickname = 'fingerbot'
284 internet.TCPClient('irc.freenode.org', 6667, i
285 ).setServiceParent(serviceCollection)
286 internet.TCPServer(8889, pb.PBServerFactory(IPerspectiveFinger(f))
287 ).setServiceParent(serviceCollection)
Source listing - listings/finger/finger22.py
return index-->TwistedTUT
Version: 1.3.0