Finger演化:使用Perspective Broker对Twisted客户端进行支持

The Evolution of Finger: Twisted client support using Perspective Broker -- dreamingk [2004-08-09 02:13:28]

1. 介绍(Introduction)

这是Twisted教程(Twisted入门 - Finger演化)的第七部分。

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

在这一部分,我们会向finger应用增加一个Perspective Broker服务,以便Twisted客户端可以访问finger服务器。

In this part, we add a Perspective Broker service to the finger application so that Twisted clients can access the finger server.

2. 使用Perspectivev Broker(Use Perspective Broker)

我们增加对perspective broker的支持,它是Twisted的本地远程对象协议。现在,Twisted客户端不再需要通过象XML-RPC化的曲折的方法来得到用户的信息。

We add support for perspective broker, Twisted's native remote object protocol. Now, Twisted clients will not have to go through XML-RPCish contortions to get information about users.

   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 import cgi
  10 
  11 class IFingerService(components.Interface):
  12 
  13     def getUser(self, user):
  14         """Return a deferred returning a string"""
  15 
  16     def getUsers(self):
  17         """Return a deferred returning a list of strings"""
  18 
  19 class IFingerSetterService(components.Interface):
  20 
  21     def setUser(self, user, status):
  22         """Set the user's status to something"""
  23 
  24 def catchError(err):
  25     return "Internal error in server"
  26 
  27 class FingerProtocol(basic.LineReceiver):
  28 
  29     def lineReceived(self, user):
  30         d = self.factory.getUser(user)
  31         d.addErrback(catchError)
  32         def writeValue(value):
  33             self.transport.write(value+'\n')
  34             self.transport.loseConnection()
  35         d.addCallback(writeValue)
  36 
  37 
  38 class IFingerFactory(components.Interface):
  39 
  40     def getUser(self, user):
  41         """Return a deferred returning a string"""
  42 
  43     def buildProtocol(self, addr):
  44         """Return a protocol returning a string"""
  45 
  46 
  47 class FingerFactoryFromService(protocol.ServerFactory):
  48 
  49     __implements__ = IFingerFactory,
  50 
  51     protocol = FingerProtocol
  52 
  53     def __init__(self, service):
  54         self.service = service
  55 
  56     def getUser(self, user):
  57         return self.service.getUser(user)
  58 
  59 components.registerAdapter(FingerFactoryFromService,
  60                            IFingerService,
  61                            IFingerFactory)
  62 
  63 class FingerSetterProtocol(basic.LineReceiver):
  64 
  65     def connectionMade(self):
  66         self.lines = []
  67 
  68     def lineReceived(self, line):
  69         self.lines.append(line)
  70 
  71     def connectionLost(self, reason):
  72         if len(self.lines) == 2:
  73             self.factory.setUser(*self.lines)
  74 
  75 
  76 class IFingerSetterFactory(components.Interface):
  77 
  78     def setUser(self, user, status):
  79         """Return a deferred returning a string"""
  80 
  81     def buildProtocol(self, addr):
  82         """Return a protocol returning a string"""
  83 
  84 
  85 class FingerSetterFactoryFromService(protocol.ServerFactory):
  86 
  87     __implements__ = IFingerSetterFactory,
  88 
  89     protocol = FingerSetterProtocol
  90 
  91     def __init__(self, service):
  92         self.service = service
  93 
  94     def setUser(self, user, status):
  95         self.service.setUser(user, status)
  96 
  97 
  98 components.registerAdapter(FingerSetterFactoryFromService,
  99                            IFingerSetterService,
 100                            IFingerSetterFactory)
 101 
 102 class IRCReplyBot(irc.IRCClient):
 103 
 104     def connectionMade(self):
 105         self.nickname = self.factory.nickname
 106         irc.IRCClient.connectionMade(self)
 107 
 108     def privmsg(self, user, channel, msg):
 109         user = user.split('!')[0]
 110         if self.nickname.lower() == channel.lower():
 111             d = self.factory.getUser(msg)
 112             d.addErrback(catchError)
 113             d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
 114             d.addCallback(lambda m: self.msg(user, m))
 115 
 116 
 117 class IIRCClientFactory(components.Interface):
 118 
 119     """
 120     @ivar nickname
 121     """
 122 
 123     def getUser(self, user):
 124         """Return a deferred returning a string"""
 125 
 126     def buildProtocol(self, addr):
 127         """Return a protocol"""
 128 
 129 
 130 class IRCClientFactoryFromService(protocol.ClientFactory):
 131 
 132     __implements__ = IIRCClientFactory,
 133 
 134     protocol = IRCReplyBot
 135     nickname = None
 136 
 137     def __init__(self, service):
 138         self.service = service
 139 
 140     def getUser(self, user):
 141         return self.service.getUser(user)
 142 
 143 components.registerAdapter(IRCClientFactoryFromService,
 144                            IFingerService,
 145                            IIRCClientFactory)
 146 
 147 class UsersModel(model.MethodModel):
 148 
 149     def initialize(self, *args, **kwargs):
 150         self.service=args[0]
 151 
 152     def wmfactory_users(self, request):
 153         return self.service.getUsers()
 154 
 155 components.registerAdapter(UsersModel, IFingerService, interfaces.IModel)
 156 
 157 class UserStatusTree(page.Page):
 158 
 159     template = """<html><head><title>Users</title></head><body>
 160     <h1>Users</h1>
 161     <ul model="users" view="List">
 162     <li pattern="listItem"><a view="Anchor" /></li>
 163     </ul></body></html>"""
 164 
 165     def initialize(self, *args, **kwargs):
 166         self.service=args[0]
 167 
 168     def getDynamicChild(self, path, request):
 169         return UserStatus(user=path, service=self.service)
 170 
 171     def wchild_RPC2 (self, request):
 172         return UserStatusXR(self.service)
 173 
 174 components.registerAdapter(UserStatusTree, IFingerService, resource.IResource)
 175 
 176 
 177 class UserStatus(page.Page):
 178 
 179     template='''<html><head><title view="Text" model="user"/></head>
 180     <body><h1 view="Text" model="user"/>
 181     <p model="status" view="Text" />
 182     </body></html>'''
 183 
 184     def initialize(self, **kwargs):
 185         self.user = kwargs['user']
 186         self.service = kwargs['service']
 187 
 188     def wmfactory_user(self, request):
 189         return self.user
 190 
 191     def wmfactory_status(self, request):
 192         return self.service.getUser(self.user)
 193 
 194 
 195 class UserStatusXR(xmlrpc.XMLRPC):
 196 
 197     def __init__(self, service):
 198         xmlrpc.XMLRPC.__init__(self)
 199         self.service = service
 200 
 201     def xmlrpc_getUser(self, user):
 202         return self.service.getUser(user)
 203 
 204     def xmlrpc_getUsers(self):
 205         return self.service.getUsers()
 206 
 207 
 208 class IPerspectiveFinger(components.Interface):
 209 
 210     def remote_getUser(self, username):
 211         """return a user's status"""
 212 
 213     def remote_getUsers(self):
 214         """return a user's status"""
 215 
 216 class PerspectiveFingerFromService(pb.Root):
 217 
 218     __implements__ = pb.Root.__implements__, IPerspectiveFinger
 219 
 220     def __init__(self, service):
 221         self.service = service
 222 
 223     def remote_getUser(self, username):
 224         return self.service.getUser(username)
 225 
 226     def remote_getUsers(self):
 227         return self.service.getUsers()
 228 
 229 components.registerAdapter(PerspectiveFingerFromService,
 230                            IFingerService,
 231                            IPerspectiveFinger)
 232 
 233 
 234 class FingerService(service.Service):
 235 
 236     __implements__ = IFingerService,
 237 
 238     def __init__(self, filename):
 239         self.filename = filename
 240         self._read()
 241 
 242     def _read(self):
 243         self.users = {}
 244         for line in file(self.filename):
 245             user, status = line.split(':', 1)
 246             user = user.strip()
 247             status = status.strip()
 248             self.users[user] = status
 249         self.call = reactor.callLater(30, self._read)
 250 
 251     def getUser(self, user):
 252         return defer.succeed(self.users.get(user, "No such user"))
 253 
 254     def getUsers(self):
 255         return defer.succeed(self.users.keys())
 256 
 257 
 258 application = service.Application('finger', uid=1, gid=1)
 259 f = FingerService('/etc/users')
 260 serviceCollection = service.IServiceCollection(application)
 261 internet.TCPServer(79, IFingerFactory(f)
 262                    ).setServiceParent(serviceCollection)
 263 internet.TCPServer(8000, server.Site(resource.IResource(f))
 264                    ).setServiceParent(serviceCollection)
 265 i = IIRCClientFactory(f)
 266 i.nickname = 'fingerbot'
 267 internet.TCPClient('irc.freenode.org', 6667, i
 268                    ).setServiceParent(serviceCollection)
 269 internet.TCPServer(8889, pb.PBServerFactory(IPerspectiveFinger(f))
 270                    ).setServiceParent(serviceCollection)
 271 
 272 Source listing - listings/finger/finger21.py
 273 A simple client to test the perspective broker finger:
 274 
 275 # test the PB finger on port 8889
 276 # this code is essentially the same as
 277 # the first example in howto/pb-usage
 278 
 279 from twisted.spread import pb
 280 from twisted.internet import reactor
 281 
 282 def gotObject(object):
 283     print "got object:", object
 284     object.callRemote("getUser","moshez").addCallback(gotData)
 285 # or
 286 #   object.callRemote("getUsers").addCallback(gotData)
 287 
 288 def gotData(data):
 289     print 'server sent:', data
 290     reactor.stop()
 291 
 292 def gotNoObject(reason):
 293     print "no object:",reason
 294     reactor.stop()
 295 
 296 factory = pb.PBClientFactory()
 297 reactor.connectTCP("127.0.0.1",8889, factory)
 298 factory.getRootObject().addCallbacks(gotObject,gotNoObject)
 299 reactor.run()

Source listing - listings/finger/fingerPBclient.py

return index-->TwistedTUT

Version: 1.3.0