Finger演化:使用单一factory支持多种协议

The Evolution of Finger: using a single factory for multiple protocols -- dreamingk [2004-08-09 02:14:44]

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