1
# Do everything properly, and componentize
2
from twisted.application import internet, service
3
from twisted.internet import protocol, reactor, defer, utils
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
12
class IFingerService(Interface):
15
"""Return a deferred returning a string"""
18
"""Return a deferred returning a list of strings"""
20
class IFingerSetterService(Interface):
22
def setUser(user, status):
23
"""Set the user's status to something"""
25
class IFingerSetterService(Interface):
27
def setUser(user, status):
28
"""Set the user's status to something"""
31
return "Internal error in server"
33
class FingerProtocol(basic.LineReceiver):
35
def lineReceived(self, user):
36
d = self.factory.getUser(user)
37
d.addErrback(catchError)
38
def writeValue(value):
39
self.transport.write(value+'\r\n')
40
self.transport.loseConnection()
41
d.addCallback(writeValue)
44
class IFingerFactory(Interface):
47
"""Return a deferred returning a string"""
49
def buildProtocol(addr):
50
"""Return a protocol returning a string"""
53
class FingerFactoryFromService(protocol.ServerFactory):
55
implements(IFingerFactory)
57
protocol = FingerProtocol
59
def __init__(self, service):
60
self.service = service
62
def getUser(self, user):
63
return self.service.getUser(user)
65
components.registerAdapter(FingerFactoryFromService,
69
class FingerSetterProtocol(basic.LineReceiver):
71
def connectionMade(self):
74
def lineReceived(self, line):
75
self.lines.append(line)
77
def connectionLost(self, reason):
78
if len(self.lines) == 2:
79
self.factory.setUser(*self.lines)
82
class IFingerSetterFactory(Interface):
84
def setUser(user, status):
85
"""Return a deferred returning a string"""
87
def buildProtocol(addr):
88
"""Return a protocol returning a string"""
91
class FingerSetterFactoryFromService(protocol.ServerFactory):
93
implements(IFingerSetterFactory)
95
protocol = FingerSetterProtocol
97
def __init__(self, service):
98
self.service = service
100
def setUser(self, user, status):
101
self.service.setUser(user, status)
104
components.registerAdapter(FingerSetterFactoryFromService,
105
IFingerSetterService,
106
IFingerSetterFactory)
108
class IRCReplyBot(irc.IRCClient):
110
def connectionMade(self):
111
self.nickname = self.factory.nickname
112
irc.IRCClient.connectionMade(self)
114
def privmsg(self, user, channel, msg):
115
user = user.split('!')[0]
116
if self.nickname.lower() == channel.lower():
117
d = self.factory.getUser(msg)
118
d.addErrback(catchError)
119
d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
120
d.addCallback(lambda m: self.msg(user, m))
123
class IIRCClientFactory(Interface):
130
"""Return a deferred returning a string"""
132
def buildProtocol(addr):
133
"""Return a protocol"""
136
class IRCClientFactoryFromService(protocol.ClientFactory):
138
implements(IIRCClientFactory)
140
protocol = IRCReplyBot
143
def __init__(self, service):
144
self.service = service
146
def getUser(self, user):
147
return self.service.getUser(user)
149
components.registerAdapter(IRCClientFactoryFromService,
153
class UserStatusTree(resource.Resource):
155
implements(resource.IResource)
157
def __init__(self, service):
158
resource.Resource.__init__(self)
159
self.service = service
160
self.putChild('RPC2', UserStatusXR(self.service))
162
def render_GET(self, request):
163
d = self.service.getUsers()
164
def formatUsers(users):
165
l = ['<li><a href="%s">%s</a></li>' % (user, user)
167
return '<ul>'+''.join(l)+'</ul>'
168
d.addCallback(formatUsers)
169
d.addCallback(request.write)
170
d.addCallback(lambda _: request.finish())
171
return server.NOT_DONE_YET
173
def getChild(self, path, request):
175
return UserStatusTree(self.service)
177
return UserStatus(path, self.service)
179
components.registerAdapter(UserStatusTree, IFingerService,
182
class UserStatus(resource.Resource):
184
def __init__(self, user, service):
185
resource.Resource.__init__(self)
187
self.service = service
189
def render_GET(self, request):
190
d = self.service.getUser(self.user)
191
d.addCallback(cgi.escape)
192
d.addCallback(lambda m:
193
'<h1>%s</h1>'%self.user+'<p>%s</p>'%m)
194
d.addCallback(request.write)
195
d.addCallback(lambda _: request.finish())
196
return server.NOT_DONE_YET
199
class UserStatusXR(xmlrpc.XMLRPC):
201
def __init__(self, service):
202
xmlrpc.XMLRPC.__init__(self)
203
self.service = service
205
def xmlrpc_getUser(self, user):
206
return self.service.getUser(user)
209
class FingerService(service.Service):
211
implements(IFingerService)
213
def __init__(self, filename):
214
self.filename = filename
220
for line in file(self.filename):
221
user, status = line.split(':', 1)
223
status = status.strip()
224
self.users[user] = status
225
self.call = reactor.callLater(30, self._read)
227
def getUser(self, user):
228
return defer.succeed(self.users.get(user, "No such user"))
231
return defer.succeed(self.users.keys())
235
class LocalFingerService(service.Service):
237
implements(IFingerService)
239
def getUser(self, user):
240
# need a local finger daemon running for this to work
241
return utils.getProcessOutput("finger", [user])
244
return defer.succeed([])
247
application = service.Application('finger', uid=1, gid=1)
248
f = LocalFingerService()
249
serviceCollection = service.IServiceCollection(application)
250
internet.TCPServer(79, IFingerFactory(f)
251
).setServiceParent(serviceCollection)
252
internet.TCPServer(8000, server.Site(resource.IResource(f))
253
).setServiceParent(serviceCollection)
254
i = IIRCClientFactory(f)
255
i.nickname = 'fingerbot'
256
internet.TCPClient('irc.freenode.org', 6667, i
257
).setServiceParent(serviceCollection)