]>
jfr.im git - irc/quakenet/qwebirc.git/blob - qwebirc/ajaxengine.py
1 from twisted
.web
import resource
, server
, static
2 from twisted
.names
import client
3 from twisted
.internet
import reactor
4 from authgateengine
import login_optional
, getSessionData
5 import simplejson
, md5
, sys
, os
, ircclient
, time
, config
, weakref
, traceback
10 return md5
.md5(os
.urandom(16)).hexdigest()
12 class BufferOverflowException(Exception):
15 class AJAXException(Exception):
18 class IDGenerationException(Exception):
24 def decorator(*args
, **kwargs
):
26 x
= fn(*args
, **kwargs
)
28 return server
.NOT_DONE_YET
30 except AJAXException
, e
:
33 return simplejson
.dumps(x
)
36 def cleanupSession(id):
43 def __init__(self
, id):
45 self
.subscriptions
= []
50 self
.cleanupschedule
= None
52 def subscribe(self
, channel
):
53 if len(self
.subscriptions
) >= config
.MAXSUBSCRIPTIONS
:
54 self
.subscriptions
.pop(0).close()
56 self
.subscriptions
.append(channel
)
59 def flush(self
, scheduled
=False):
63 if not self
.buffer or not self
.subscriptions
:
70 self
.schedule
= reactor
.callLater(self
.throttle
- t
, self
.flush
, True)
73 # process the rest of the packet
76 self
.schedule
= reactor
.callLater(0, self
.flush
, True)
79 self
.throttle
= t
+ config
.UPDATE_FREQ
81 encdata
= simplejson
.dumps(self
.buffer)
85 for x
in self
.subscriptions
:
89 self
.subscriptions
= newsubs
90 if self
.closed
and not self
.subscriptions
:
91 cleanupSession(self
.id)
93 def event(self
, data
):
94 bufferlen
= sum(map(len, self
.buffer))
95 if bufferlen
+ len(data
) > config
.MAXBUFLEN
:
97 self
.client
.error("Buffer overflow")
100 self
.buffer.append(data
)
103 def push(self
, data
):
105 self
.client
.write(data
)
107 def disconnect(self
):
108 # keep the session hanging around for a few seconds so the
109 # client has a chance to see what the issue was
112 reactor
.callLater(5, cleanupSession
, self
.id)
115 def __init__(self
, request
):
116 self
.request
= request
118 class SingleUseChannel(Channel
):
119 def write(self
, data
):
120 self
.request
.write(data
)
121 self
.request
.finish()
125 self
.request
.finish()
127 class MultipleUseChannel(Channel
):
128 def write(self
, data
):
129 self
.request
.write(data
)
132 class AJAXEngine(resource
.Resource
):
135 def __init__(self
, prefix
):
139 def render_POST(self
, request
):
140 path
= request
.path
[len(self
.prefix
):]
142 handler
= self
.COMMANDS
.get(path
[1:])
143 if handler
is not None:
144 return handler(self
, request
)
145 raise AJAXException("404")
147 # def render_GET(self, request):
148 # return self.render_POST(request)
150 def newConnection(self
, request
):
151 ticket
= login_optional(request
)
153 _
, ip
, port
= request
.transport
.getPeer()
155 nick
, ident
, realname
= request
.args
.get("nick"), "webchat", config
.REALNAME
157 if not ticket
is None:
158 realname
= "%s (%s:%d:%s)" % (realname
, ticket
.username
, ticket
.id, ticket
.authflags
)
161 raise AJAXException("Nickname not supplied")
166 id = get_session_id()
167 if not Sessions
.get(id):
170 raise IDGenerationException()
172 session
= IRCSession(id)
174 qticket
= getSessionData(request
).get("qticket")
178 perform
= ["PRIVMSG %s :TICKETAUTH %s" % (config
.QBOT
, qticket
)]
180 client
= ircclient
.createIRC(session
, nick
=nick
, ident
=ident
, ip
=ip
, realname
=realname
, perform
=perform
)
181 session
.client
= client
183 Sessions
[id] = session
187 def getSession(self
, request
):
188 sessionid
= request
.args
.get("s")
189 if sessionid
is None:
190 raise AJAXException("Bad session ID")
192 session
= Sessions
.get(sessionid
[0])
194 raise AJAXException("Bad session ID")
197 def subscribe(self
, request
):
198 self
.getSession(request
).subscribe(SingleUseChannel(request
))
201 def push(self
, request
):
202 command
= request
.args
.get("c")
204 raise AJAXException("No command specified")
208 session
= self
.getSession(request
)
211 decoded
= command
.decode("utf-8")
212 except UnicodeDecodeError:
213 decoded
= command
.decode("iso-8859-1", "ignore")
215 if len(decoded
) > config
.MAXLINELEN
:
217 raise AJAXException("Line too long")
220 session
.push(decoded
)
221 except AttributeError: # occurs when we haven't noticed an error
223 raise AJAXException("Connection closed by server.")
224 except Exception, e
: # catch all
226 traceback
.print_exc(file=sys
.stderr
)
227 raise AJAXException("Unknown error.")
231 COMMANDS
= dict(p
=push
, n
=newConnection
, s
=subscribe
)