3 from zope.interface import Interface, implements
5 from twisted.application import internet, service
6 from twisted.internet import protocol, reactor, defer
7 from twisted.words.protocols import irc
8 from twisted.protocols import basic
9 from twisted.python import components, log
10 from twisted.web import resource, server, xmlrpc
11 from twisted.spread import pb
13 from OpenSSL import SSL
15 class IFingerService(Interface):
19 Return a deferred returning a string.
24 Return a deferred returning a list of strings.
28 class IFingerSetterService(Interface):
30 def setUser(user, status):
32 Set the user's status to something.
37 return "Internal error in server"
40 class FingerProtocol(basic.LineReceiver):
42 def lineReceived(self, user):
43 d = self.factory.getUser(user)
44 d.addErrback(catchError)
45 def writeValue(value):
46 self.transport.write(value+'\n')
47 self.transport.loseConnection()
48 d.addCallback(writeValue)
51 class IFingerFactory(Interface):
55 Return a deferred returning a string.
58 def buildProtocol(addr):
60 Return a protocol returning a string.
64 class FingerFactoryFromService(protocol.ServerFactory):
65 implements(IFingerFactory)
67 protocol = FingerProtocol
69 def __init__(self, service):
70 self.service = service
72 def getUser(self, user):
73 return self.service.getUser(user)
75 components.registerAdapter(FingerFactoryFromService,
80 class FingerSetterProtocol(basic.LineReceiver):
82 def connectionMade(self):
85 def lineReceived(self, line):
86 self.lines.append(line)
88 def connectionLost(self, reason):
89 if len(self.lines) == 2:
90 self.factory.setUser(*self.lines)
93 class IFingerSetterFactory(Interface):
95 def setUser(user, status):
97 Return a deferred returning a string.
100 def buildProtocol(addr):
102 Return a protocol returning a string.
106 class FingerSetterFactoryFromService(protocol.ServerFactory):
108 implements(IFingerSetterFactory)
110 protocol = FingerSetterProtocol
112 def __init__(self, service):
113 self.service = service
115 def setUser(self, user, status):
116 self.service.setUser(user, status)
119 components.registerAdapter(FingerSetterFactoryFromService,
120 IFingerSetterService,
121 IFingerSetterFactory)
124 class IRCReplyBot(irc.IRCClient):
126 def connectionMade(self):
127 self.nickname = self.factory.nickname
128 irc.IRCClient.connectionMade(self)
130 def privmsg(self, user, channel, msg):
131 user = user.split('!')[0]
132 if self.nickname.lower() == channel.lower():
133 d = self.factory.getUser(msg)
134 d.addErrback(catchError)
135 d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
136 d.addCallback(lambda m: self.msg(user, m))
139 class IIRCClientFactory(Interface):
147 Return a deferred returning a string.
150 def buildProtocol(addr):
156 class IRCClientFactoryFromService(protocol.ClientFactory):
158 implements(IIRCClientFactory)
160 protocol = IRCReplyBot
163 def __init__(self, service):
164 self.service = service
166 def getUser(self, user):
167 return self.service.getUser(user)
169 components.registerAdapter(IRCClientFactoryFromService,
174 class UserStatusTree(resource.Resource):
176 template = """<html><head><title>Users</title></head><body>
184 def __init__(self, service):
185 resource.Resource.__init__(self)
186 self.service = service
188 def getChild(self, path, request):
192 return UserStatusXR(self.service)
194 return UserStatus(path, self.service)
196 def render_GET(self, request):
197 users = self.service.getUsers()
199 request.write(self.template % {'users': ''.join([
200 # Name should be quoted properly these uses.
201 '<li><a href="%s">%s</a></li>' % (name, name)
202 for name in users])})
204 users.addCallback(cbUsers)
206 log.err(err, "UserStatusTree failed")
208 users.addErrback(ebUsers)
209 return server.NOT_DONE_YET
211 components.registerAdapter(UserStatusTree, IFingerService, resource.IResource)
214 class UserStatus(resource.Resource):
216 template='''<html><head><title>%(title)s</title></head>
217 <body><h1>%(name)s</h1><p>%(status)s</p></body></html>'''
219 def __init__(self, user, service):
220 resource.Resource.__init__(self)
222 self.service = service
224 def render_GET(self, request):
225 status = self.service.getUser(self.user)
226 def cbStatus(status):
227 request.write(self.template % {
232 status.addCallback(cbStatus)
234 log.err(err, "UserStatus failed")
236 status.addErrback(ebStatus)
237 return server.NOT_DONE_YET
240 class UserStatusXR(xmlrpc.XMLRPC):
242 def __init__(self, service):
243 xmlrpc.XMLRPC.__init__(self)
244 self.service = service
246 def xmlrpc_getUser(self, user):
247 return self.service.getUser(user)
249 def xmlrpc_getUsers(self):
250 return self.service.getUsers()
253 class IPerspectiveFinger(Interface):
255 def remote_getUser(username):
257 Return a user's status.
260 def remote_getUsers():
262 Return a user's status.
266 class PerspectiveFingerFromService(pb.Root):
268 implements(IPerspectiveFinger)
270 def __init__(self, service):
271 self.service = service
273 def remote_getUser(self, username):
274 return self.service.getUser(username)
276 def remote_getUsers(self):
277 return self.service.getUsers()
279 components.registerAdapter(PerspectiveFingerFromService,
284 class FingerService(service.Service):
286 implements(IFingerService)
288 def __init__(self, filename):
289 self.filename = filename
293 for line in file(self.filename):
294 user, status = line.split(':', 1)
296 status = status.strip()
297 self.users[user] = status
298 self.call = reactor.callLater(30, self._read)
300 def getUser(self, user):
301 return defer.succeed(self.users.get(user, "No such user"))
304 return defer.succeed(self.users.keys())
306 def startService(self):
308 service.Service.startService(self)
310 def stopService(self):
311 service.Service.stopService(self)
315 class ServerContextFactory:
317 def getContext(self):
319 Create an SSL context.
321 This is a sample implementation that loads a certificate from a file
324 ctx = SSL.Context(SSL.SSLv23_METHOD)
325 ctx.use_certificate_file('server.pem')
326 ctx.use_privatekey_file('server.pem')
333 def makeService(config):
335 s = service.MultiService()
336 f = FingerService(config['file'])
337 h = internet.TCPServer(1079, IFingerFactory(f))
338 h.setServiceParent(s)
341 # website on port 8000
342 r = resource.IResource(f)
343 r.templateDirectory = config['templates']
344 site = server.Site(r)
345 j = internet.TCPServer(8000, site)
346 j.setServiceParent(s)
349 # if config.get('ssl'):
350 # k = internet.SSLServer(443, site, ServerContextFactory())
351 # k.setServiceParent(s)
354 if config.has_key('ircnick'):
355 i = IIRCClientFactory(f)
356 i.nickname = config['ircnick']
357 ircserver = config['ircserver']
358 b = internet.TCPClient(ircserver, 6667, i)
359 b.setServiceParent(s)
361 # Pespective Broker on port 8889
362 if config.has_key('pbport'):
363 m = internet.TCPServer(
364 int(config['pbport']),
365 pb.PBServerFactory(IPerspectiveFinger(f)))
366 m.setServiceParent(s)