]>
jfr.im git - irc/quakenet/qwebirc.git/blob - qwebirc/ajaxengine.py
d74bd39fb45bc61ef7cf8186d4d6a99beffd0e06
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
158 raise AJAXException("Nickname not supplied")
163 id = get_session_id()
164 if not Sessions
.get(id):
167 raise IDGenerationException()
169 session
= IRCSession(id)
171 qticket
= getSessionData(request
).get("qticket")
175 perform
= ["PRIVMSG %s :TICKETAUTH %s" % (config
.QBOT
, qticket
)]
177 client
= ircclient
.createIRC(session
, nick
=nick
, ident
=ident
, ip
=ip
, realname
=realname
, perform
=perform
)
178 session
.client
= client
180 Sessions
[id] = session
184 def getSession(self
, request
):
185 sessionid
= request
.args
.get("s")
186 if sessionid
is None:
187 raise AJAXException("Bad session ID")
189 session
= Sessions
.get(sessionid
[0])
191 raise AJAXException("Bad session ID")
194 def subscribe(self
, request
):
195 self
.getSession(request
).subscribe(SingleUseChannel(request
))
198 def push(self
, request
):
199 command
= request
.args
.get("c")
201 raise AJAXException("No command specified")
205 session
= self
.getSession(request
)
208 decoded
= command
.decode("utf-8")
209 except UnicodeDecodeError:
210 decoded
= command
.decode("iso-8859-1", "ignore")
212 if len(decoded
) > config
.MAXLINELEN
:
214 raise AJAXException("Line too long")
217 session
.push(decoded
)
218 except AttributeError: # occurs when we haven't noticed an error
220 raise AJAXException("Connection closed by server.")
221 except Exception, e
: # catch all
223 traceback
.print_exc(file=sys
.stderr
)
224 raise AJAXException("Unknown error.")
228 COMMANDS
= dict(p
=push
, n
=newConnection
, s
=subscribe
)