summaryrefslogtreecommitdiff
path: root/doc/core/howto/tutorial/listings/finger/finger19c.tac
diff options
context:
space:
mode:
Diffstat (limited to 'doc/core/howto/tutorial/listings/finger/finger19c.tac')
-rwxr-xr-xdoc/core/howto/tutorial/listings/finger/finger19c.tac305
1 files changed, 305 insertions, 0 deletions
diff --git a/doc/core/howto/tutorial/listings/finger/finger19c.tac b/doc/core/howto/tutorial/listings/finger/finger19c.tac
new file mode 100755
index 0000000..98502a5
--- /dev/null
+++ b/doc/core/howto/tutorial/listings/finger/finger19c.tac
@@ -0,0 +1,305 @@
+# Do everything properly, and componentize
+from twisted.application import internet, service
+from twisted.internet import protocol, reactor, defer, utils
+from twisted.words.protocols import irc
+from twisted.protocols import basic
+from twisted.python import components
+from twisted.web import resource, server, static, xmlrpc
+from zope.interface import Interface, implements
+import cgi
+import pwd
+import os
+
+class IFingerService(Interface):
+
+ def getUser(user):
+ """
+ Return a deferred returning a string.
+ """
+
+ def getUsers():
+ """
+ Return a deferred returning a list of strings.
+ """
+
+
+class IFingerSetterService(Interface):
+
+ def setUser(user, status):
+ """
+ Set the user's status to something.
+ """
+
+
+class IFingerSetterService(Interface):
+
+ def setUser(user, status):
+ """
+ Set the user's status to something.
+ """
+
+
+def catchError(err):
+ return "Internal error in server"
+
+
+class FingerProtocol(basic.LineReceiver):
+
+ def lineReceived(self, user):
+ d = self.factory.getUser(user)
+ d.addErrback(catchError)
+ def writeValue(value):
+ self.transport.write(value+'\r\n')
+ self.transport.loseConnection()
+ d.addCallback(writeValue)
+
+
+class IFingerFactory(Interface):
+
+ def getUser(user):
+ """
+ Return a deferred returning a string.
+ """
+
+ def buildProtocol(addr):
+ """
+ Return a protocol returning a string.
+ """
+
+
+class FingerFactoryFromService(protocol.ServerFactory):
+
+ implements(IFingerFactory)
+
+ protocol = FingerProtocol
+
+ def __init__(self, service):
+ self.service = service
+
+ def getUser(self, user):
+ return self.service.getUser(user)
+
+components.registerAdapter(FingerFactoryFromService,
+ IFingerService,
+ IFingerFactory)
+
+
+class FingerSetterProtocol(basic.LineReceiver):
+
+ def connectionMade(self):
+ self.lines = []
+
+ def lineReceived(self, line):
+ self.lines.append(line)
+
+ def connectionLost(self, reason):
+ if len(self.lines) == 2:
+ self.factory.setUser(*self.lines)
+
+
+class IFingerSetterFactory(Interface):
+
+ def setUser(user, status):
+ """
+ Return a deferred returning a string.
+ """
+
+ def buildProtocol(addr):
+ """
+ Return a protocol returning a string.
+ """
+
+
+class FingerSetterFactoryFromService(protocol.ServerFactory):
+
+ implements(IFingerSetterFactory)
+
+ protocol = FingerSetterProtocol
+
+ def __init__(self, service):
+ self.service = service
+
+ def setUser(self, user, status):
+ self.service.setUser(user, status)
+
+
+components.registerAdapter(FingerSetterFactoryFromService,
+ IFingerSetterService,
+ IFingerSetterFactory)
+
+
+class IRCReplyBot(irc.IRCClient):
+
+ def connectionMade():
+ self.nickname = self.factory.nickname
+ irc.IRCClient.connectionMade(self)
+
+ def privmsg(self, user, channel, msg):
+ user = user.split('!')[0]
+ if self.nickname.lower() == channel.lower():
+ d = self.factory.getUser(msg)
+ d.addErrback(catchError)
+ d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
+ d.addCallback(lambda m: self.msg(user, m))
+
+
+class IIRCClientFactory(Interface):
+
+ """
+ @ivar nickname
+ """
+
+ def getUser(user):
+ """
+ Return a deferred returning a string.
+ """
+
+ def buildProtocol(addr):
+ """
+ Return a protocol.
+ """
+
+
+class IRCClientFactoryFromService(protocol.ClientFactory):
+
+ implements(IIRCClientFactory)
+
+ protocol = IRCReplyBot
+ nickname = None
+
+ def __init__(self, service):
+ self.service = service
+
+ def getUser(self, user):
+ return self.service.getUser(user)
+
+components.registerAdapter(IRCClientFactoryFromService,
+ IFingerService,
+ IIRCClientFactory)
+
+
+class UserStatusTree(resource.Resource):
+
+ implements(resource.IResource)
+
+ def __init__(self, service):
+ resource.Resource.__init__(self)
+ self.service = service
+ self.putChild('RPC2', UserStatusXR(self.service))
+
+ def render_GET(self, request):
+ d = self.service.getUsers()
+ def formatUsers(users):
+ l = ['<li><a href="%s">%s</a></li>' % (user, user)
+ for user in users]
+ return '<ul>'+''.join(l)+'</ul>'
+ d.addCallback(formatUsers)
+ d.addCallback(request.write)
+ d.addCallback(lambda _: request.finish())
+ return server.NOT_DONE_YET
+
+ def getChild(self, path, request):
+ if path=="":
+ return UserStatusTree(self.service)
+ else:
+ return UserStatus(path, self.service)
+
+components.registerAdapter(UserStatusTree, IFingerService,
+ resource.IResource)
+
+
+class UserStatus(resource.Resource):
+
+ def __init__(self, user, service):
+ resource.Resource.__init__(self)
+ self.user = user
+ self.service = service
+
+ def render_GET(self, request):
+ d = self.service.getUser(self.user)
+ d.addCallback(cgi.escape)
+ d.addCallback(lambda m:
+ '<h1>%s</h1>'%self.user+'<p>%s</p>'%m)
+ d.addCallback(request.write)
+ d.addCallback(lambda _: request.finish())
+ return server.NOT_DONE_YET
+
+
+class UserStatusXR(xmlrpc.XMLRPC):
+
+ def __init__(self, service):
+ xmlrpc.XMLRPC.__init__(self)
+ self.service = service
+
+ def xmlrpc_getUser(self, user):
+ return self.service.getUser(user)
+
+
+class FingerService(service.Service):
+
+ implements(IFingerService)
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.users = {}
+
+ def _read(self):
+ self.users.clear()
+ for line in file(self.filename):
+ user, status = line.split(':', 1)
+ user = user.strip()
+ status = status.strip()
+ self.users[user] = status
+ self.call = reactor.callLater(30, self._read)
+
+ def getUser(self, user):
+ return defer.succeed(self.users.get(user, "No such user"))
+
+ def getUsers(self):
+ return defer.succeed(self.users.keys())
+
+ def startService(self):
+ self._read()
+ service.Service.startService(self)
+
+ def stopService(self):
+ service.Service.stopService(self)
+ self.call.cancel()
+
+
+# Yet another back-end
+
+class LocalFingerService(service.Service):
+
+ implements(IFingerService)
+
+ def getUser(self, user):
+ user = user.strip()
+ try:
+ entry = pwd.getpwnam(user)
+ except KeyError:
+ return defer.succeed("No such user")
+ try:
+ f = file(os.path.join(entry[5],'.plan'))
+ except (IOError, OSError):
+ return defer.succeed("No such user")
+ data = f.read()
+ data = data.strip()
+ f.close()
+ return defer.succeed(data)
+
+ def getUsers(self):
+ return defer.succeed([])
+
+
+application = service.Application('finger', uid=1, gid=1)
+f = LocalFingerService()
+serviceCollection = service.IServiceCollection(application)
+internet.TCPServer(79, IFingerFactory(f)
+ ).setServiceParent(serviceCollection)
+internet.TCPServer(8000, server.Site(resource.IResource(f))
+ ).setServiceParent(serviceCollection)
+i = IIRCClientFactory(f)
+i.nickname = 'fingerbot'
+internet.TCPClient('irc.freenode.org', 6667, i
+ ).setServiceParent(serviceCollection)