Imported Upstream version 12.1.0
[contrib/python-twisted.git] / doc / core / howto / tutorial / listings / finger / finger19.tac
1 # Do everything properly, and componentize
2 from twisted.application import internet, service
3 from twisted.internet import protocol, reactor, defer
4 from twisted.words.protocols import irc
5 from twisted.protocols import basic
6 from twisted.python import components
7 from twisted.web import resource, server, static, xmlrpc
8 from zope.interface import Interface, implements
9 import cgi
10
11 class IFingerService(Interface):
12
13     def getUser(user):
14         """
15         Return a deferred returning a string.
16         """
17
18     def getUsers():
19         """
20         Return a deferred returning a list of strings.
21         """
22
23
24 class IFingerSetterService(Interface):
25
26     def setUser(user, status):
27         """
28         Set the user's status to something.
29         """
30
31
32 def catchError(err):
33     return "Internal error in server"
34
35
36 class FingerProtocol(basic.LineReceiver):
37
38     def lineReceived(self, user):
39         d = self.factory.getUser(user)
40         d.addErrback(catchError)
41         def writeValue(value):
42             self.transport.write(value+'\r\n')
43             self.transport.loseConnection()
44         d.addCallback(writeValue)
45
46
47 class IFingerFactory(Interface):
48
49     def getUser(user):
50         """
51         Return a deferred returning a string.
52         """
53
54     def buildProtocol(addr):
55         """
56         Return a protocol returning a string.
57         """
58
59
60 class FingerFactoryFromService(protocol.ServerFactory):
61
62     implements(IFingerFactory)
63
64     protocol = FingerProtocol
65
66     def __init__(self, service):
67         self.service = service
68
69     def getUser(self, user):
70         return self.service.getUser(user)
71
72 components.registerAdapter(FingerFactoryFromService,
73                            IFingerService,
74                            IFingerFactory)
75
76
77 class FingerSetterProtocol(basic.LineReceiver):
78
79     def connectionMade(self):
80         self.lines = []
81
82     def lineReceived(self, line):
83         self.lines.append(line)
84
85     def connectionLost(self, reason):
86         if len(self.lines) == 2:
87             self.factory.setUser(*self.lines)
88
89
90 class IFingerSetterFactory(Interface):
91
92     def setUser(user, status):
93         """
94         Return a deferred returning a string.
95         """
96
97     def buildProtocol(addr):
98         """
99         Return a protocol returning a string.
100         """
101
102
103 class FingerSetterFactoryFromService(protocol.ServerFactory):
104
105     implements(IFingerSetterFactory)
106
107     protocol = FingerSetterProtocol
108
109     def __init__(self, service):
110         self.service = service
111
112     def setUser(self, user, status):
113         self.service.setUser(user, status)
114
115
116 components.registerAdapter(FingerSetterFactoryFromService,
117                            IFingerSetterService,
118                            IFingerSetterFactory)
119
120
121 class IRCReplyBot(irc.IRCClient):
122
123     def connectionMade(self):
124         self.nickname = self.factory.nickname
125         irc.IRCClient.connectionMade(self)
126
127     def privmsg(self, user, channel, msg):
128         user = user.split('!')[0]
129         if self.nickname.lower() == channel.lower():
130             d = self.factory.getUser(msg)
131             d.addErrback(catchError)
132             d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
133             d.addCallback(lambda m: self.msg(user, m))
134
135
136 class IIRCClientFactory(Interface):
137     """
138     @ivar nickname
139     """
140
141     def getUser(user):
142         """
143         Return a deferred returning a string.
144         """
145
146     def buildProtocol(addr):
147         """
148         Return a protocol.
149         """
150
151
152 class IRCClientFactoryFromService(protocol.ClientFactory):
153
154     implements(IIRCClientFactory)
155
156     protocol = IRCReplyBot
157     nickname = None
158
159     def __init__(self, service):
160         self.service = service
161
162     def getUser(self, user):
163         return self.service.getUser(user)
164
165 components.registerAdapter(IRCClientFactoryFromService,
166                            IFingerService,
167                            IIRCClientFactory)
168
169
170 class UserStatusTree(resource.Resource):
171
172     implements(resource.IResource)
173
174     def __init__(self, service):
175         resource.Resource.__init__(self)
176         self.service = service
177         self.putChild('RPC2', UserStatusXR(self.service))
178
179     def render_GET(self, request):
180         d = self.service.getUsers()
181         def formatUsers(users):
182             l = ['<li><a href="%s">%s</a></li>' % (user, user)
183                  for user in users]
184             return '<ul>'+''.join(l)+'</ul>'
185         d.addCallback(formatUsers)
186         d.addCallback(request.write)
187         d.addCallback(lambda _: request.finish())
188         return server.NOT_DONE_YET
189
190     def getChild(self, path, request):
191         if path=="":
192             return UserStatusTree(self.service)
193         else:
194             return UserStatus(path, self.service)
195
196 components.registerAdapter(UserStatusTree, IFingerService,
197                            resource.IResource)
198
199
200 class UserStatus(resource.Resource):
201
202     def __init__(self, user, service):
203         resource.Resource.__init__(self)
204         self.user = user
205         self.service = service
206
207     def render_GET(self, request):
208         d = self.service.getUser(self.user)
209         d.addCallback(cgi.escape)
210         d.addCallback(lambda m:
211                       '<h1>%s</h1>'%self.user+'<p>%s</p>'%m)
212         d.addCallback(request.write)
213         d.addCallback(lambda _: request.finish())
214         return server.NOT_DONE_YET
215
216
217 class UserStatusXR(xmlrpc.XMLRPC):
218
219     def __init__(self, service):
220         xmlrpc.XMLRPC.__init__(self)
221         self.service = service
222
223     def xmlrpc_getUser(self, user):
224         return self.service.getUser(user)
225
226
227 class FingerService(service.Service):
228
229     implements(IFingerService)
230
231     def __init__(self, filename):
232         self.filename = filename
233         self.users = {}
234
235     def _read(self):
236         self.users.clear()
237         for line in file(self.filename):
238             user, status = line.split(':', 1)
239             user = user.strip()
240             status = status.strip()
241             self.users[user] = status
242         self.call = reactor.callLater(30, self._read)
243
244     def getUser(self, user):
245         return defer.succeed(self.users.get(user, "No such user"))
246
247     def getUsers(self):
248         return defer.succeed(self.users.keys())
249
250     def startService(self):
251         self._read()
252         service.Service.startService(self)
253
254     def stopService(self):
255         service.Service.stopService(self)
256         self.call.cancel()
257
258
259 application = service.Application('finger', uid=1, gid=1)
260 f = FingerService('/etc/users')
261 serviceCollection = service.IServiceCollection(application)
262 f.setServiceParent(serviceCollection)
263 internet.TCPServer(79, IFingerFactory(f)
264                    ).setServiceParent(serviceCollection)
265 internet.TCPServer(8000, server.Site(resource.IResource(f))
266                    ).setServiceParent(serviceCollection)
267 i = IIRCClientFactory(f)
268 i.nickname = 'fingerbot'
269 internet.TCPClient('irc.freenode.org', 6667, i
270                    ).setServiceParent(serviceCollection)