Finger演化:使用Perspective Broker对Twisted客户端进行支持 The Evolution of Finger: Twisted client support using Perspective Broker
介绍(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.
使用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