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, microdom
8
from zope.interface import Interface, implements
11
class IFingerService(Interface):
14
"""Return a deferred returning a string"""
17
"""Return a deferred returning a list of strings"""
19
class IFingerSetterService(Interface):
21
def setUser(user, status):
22
"""Set the user's status to something"""
25
return "Internal error in server"
27
class FingerProtocol(basic.LineReceiver):
29
def lineReceived(self, user):
30
d = self.factory.getUser(user)
31
d.addErrback(catchError)
32
def writeValue(value):
33
self.transport.write(value+'\r\n')
34
self.transport.loseConnection()
35
d.addCallback(writeValue)
38
class IFingerFactory(Interface):
41
"""Return a deferred returning a string"""
43
def buildProtocol(addr):
44
"""Return a protocol returning a string"""
47
class FingerFactoryFromService(protocol.ServerFactory):
49
implements(IFingerFactory)
51
protocol = FingerProtocol
53
def __init__(self, service):
54
self.service = service
56
def getUser(self, user):
57
return self.service.getUser(user)
59
components.registerAdapter(FingerFactoryFromService,
63
class FingerSetterProtocol(basic.LineReceiver):
65
def connectionMade(self):
68
def lineReceived(self, line):
69
self.lines.append(line)
71
def connectionLost(self, reason):
72
if len(self.lines) == 2:
73
self.factory.setUser(*self.lines)
76
class IFingerSetterFactory(Interface):
78
def setUser(user, status):
79
"""Return a deferred returning a string"""
81
def buildProtocol(addr):
82
"""Return a protocol returning a string"""
85
class FingerSetterFactoryFromService(protocol.ServerFactory):
87
implements(IFingerSetterFactory)
89
protocol = FingerSetterProtocol
91
def __init__(self, service):
92
self.service = service
94
def setUser(self, user, status):
95
self.service.setUser(user, status)
98
components.registerAdapter(FingerSetterFactoryFromService,
100
IFingerSetterFactory)
102
class IRCReplyBot(irc.IRCClient):
104
def connectionMade(self):
105
self.nickname = self.factory.nickname
106
irc.IRCClient.connectionMade(self)
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))
117
class IIRCClientFactory(Interface):
124
"""Return a deferred returning a string"""
126
def buildProtocol(addr):
127
"""Return a protocol"""
130
class IRCClientFactoryFromService(protocol.ClientFactory):
132
implements(IIRCClientFactory)
134
protocol = IRCReplyBot
137
def __init__(self, service):
138
self.service = service
140
def getUser(self, user):
141
return self.service.getUser(user)
143
components.registerAdapter(IRCClientFactoryFromService,
147
class UserStatusTree(resource.Resource):
149
def __init__(self, service):
150
resource.Resource.__init__(self)
153
# add a specific child for the path "RPC2"
154
self.putChild("RPC2", UserStatusXR(self.service))
156
# need to do this for resources at the root of the site
157
self.putChild("", self)
159
def _cb_render_GET(self, users, request):
160
userOutput = ''.join(["<li><a href=\"%s\">%s</a></li>" % (user, user)
163
<html><head><title>Users</title></head><body>
167
</ul></body></html>""" % userOutput)
170
def render_GET(self, request):
171
d = self.service.getUsers()
172
d.addCallback(self._cb_render_GET, request)
174
# signal that the rendering is not complete
175
return server.NOT_DONE_YET
177
def getChild(self, path, request):
178
return UserStatus(user=path, service=self.service)
180
components.registerAdapter(UserStatusTree, IFingerService, resource.IResource)
182
class UserStatus(resource.Resource):
184
def __init__(self, user, service):
185
resource.Resource.__init__(self)
187
self.service = service
189
def _cb_render_GET(self, status, request):
190
request.write("""<html><head><title>%s</title></head>
193
</body></html>""" % (self.user, self.user, status))
196
def render_GET(self, request):
197
d = self.service.getUser(self.user)
198
d.addCallback(self._cb_render_GET, request)
200
# signal that the rendering is not complete
201
return server.NOT_DONE_YET
203
class UserStatusXR(xmlrpc.XMLRPC):
205
def __init__(self, service):
206
xmlrpc.XMLRPC.__init__(self)
207
self.service = service
209
def xmlrpc_getUser(self, user):
210
return self.service.getUser(user)
212
def xmlrpc_getUsers(self):
213
return self.service.getUsers()
216
class FingerService(service.Service):
218
implements(IFingerService)
220
def __init__(self, filename):
221
self.filename = filename
227
for line in file(self.filename):
228
user, status = line.split(':', 1)
230
status = status.strip()
231
self.users[user] = status
232
self.call = reactor.callLater(30, self._read)
234
def getUser(self, user):
235
return defer.succeed(self.users.get(user, "No such user"))
238
return defer.succeed(self.users.keys())
241
application = service.Application('finger', uid=1, gid=1)
242
f = FingerService('/etc/users')
243
serviceCollection = service.IServiceCollection(application)
244
internet.TCPServer(79, IFingerFactory(f)
245
).setServiceParent(serviceCollection)
246
internet.TCPServer(8000, server.Site(resource.IResource(f))
247
).setServiceParent(serviceCollection)
248
i = IIRCClientFactory(f)
249
i.nickname = 'fingerbot'
250
internet.TCPClient('irc.freenode.org', 6667, i
251
).setServiceParent(serviceCollection)