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
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 implements(resource.IResource)
151 def __init__(self, service):
152 resource.Resource.__init__(self)
153 self.service = service
154 self.putChild('RPC2', UserStatusXR(self.service))
156 def render_GET(self, request):
157 d = self.service.getUsers()
158 def formatUsers(users):
159 l = ['<li><a href="%s">%s</a></li>' % (user, user)
161 return '<ul>'+''.join(l)+'</ul>'
162 d.addCallback(formatUsers)
163 d.addCallback(request.write)
164 d.addCallback(lambda _: request.finish())
165 return server.NOT_DONE_YET
167 def getChild(self, path, request):
169 return UserStatusTree(self.service)
171 return UserStatus(path, self.service)
173 components.registerAdapter(UserStatusTree, IFingerService,
176 class UserStatus(resource.Resource):
178 def __init__(self, user, service):
179 resource.Resource.__init__(self)
181 self.service = service
183 def render_GET(self, request):
184 d = self.service.getUser(self.user)
185 d.addCallback(cgi.escape)
186 d.addCallback(lambda m:
187 '<h1>%s</h1>'%self.user+'<p>%s</p>'%m)
188 d.addCallback(request.write)
189 d.addCallback(lambda _: request.finish())
190 return server.NOT_DONE_YET
193 class UserStatusXR(xmlrpc.XMLRPC):
195 def __init__(self, service):
196 xmlrpc.XMLRPC.__init__(self)
197 self.service = service
199 def xmlrpc_getUser(self, user):
200 return self.service.getUser(user)
202 class MemoryFingerService(service.Service):
204 implements([IFingerService, IFingerSetterService])
206 def __init__(self, **kwargs):
209 def getUser(self, user):
210 return defer.succeed(self.users.get(user, "No such user"))
213 return defer.succeed(self.users.keys())
215 def setUser(self, user, status):
216 self.users[user] = status
219 application = service.Application('finger', uid=1, gid=1)
220 f = MemoryFingerService(moshez='Happy and well')
221 serviceCollection = service.IServiceCollection(application)
222 internet.TCPServer(79, IFingerFactory(f)
223 ).setServiceParent(serviceCollection)
224 internet.TCPServer(8000, server.Site(resource.IResource(f))
225 ).setServiceParent(serviceCollection)
226 i = IIRCClientFactory(f)
227 i.nickname = 'fingerbot'
228 internet.TCPClient('irc.freenode.org', 6667, i
229 ).setServiceParent(serviceCollection)
230 internet.TCPServer(1079, IFingerSetterFactory(f), interface='127.0.0.1'
231 ).setServiceParent(serviceCollection)