]>
jfr.im git - irc/quakenet/qwebirc.git/blob - qwebirc/ajaxengine.py
0da0f384514719c3b26d15e4d157b042c41a968e
1 from twisted
.web
import resource
, server
, static
2 from twisted
.names
import client
3 from twisted
.internet
import reactor
5 import simplejson
, md5
, sys
, os
, ircclient
, time
, config
, weakref
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 _
, ip
, port
= request
.transport
.getPeer()
153 nick
, ident
= request
.args
.get("nick"), "webchat"
155 raise AJAXException("Nickname not supplied")
160 id = get_session_id()
161 if not Sessions
.get(id):
164 raise IDGenerationException()
166 session
= IRCSession(id)
168 client
= ircclient
.createIRC(session
, nick
=nick
, ident
=ident
, ip
=ip
, realname
=config
.REALNAME
)
169 session
.client
= client
171 Sessions
[id] = session
175 def getSession(self
, request
):
176 sessionid
= request
.args
.get("s")
177 if sessionid
is None:
178 raise AJAXException("Bad session ID")
180 session
= Sessions
.get(sessionid
[0])
182 raise AJAXException("Bad session ID")
185 def subscribe(self
, request
):
186 self
.getSession(request
).subscribe(SingleUseChannel(request
))
189 def push(self
, request
):
190 command
= request
.args
.get("c")
192 raise AJAXException("No command specified")
196 session
= self
.getSession(request
)
199 decoded
= command
.decode("utf-8")
200 except UnicodeDecodeError:
201 decoded
= command
.decode("iso-8859-1", "ignore")
203 if len(decoded
) > config
.MAXLINELEN
:
205 raise AJAXException("Line too long")
208 session
.push(decoded
)
209 except AttributeError: # occurs when we haven't noticed an error
211 raise AJAXException("Connection closed by server.")
212 except Exception, e
: # catch all
214 traceback
.print_exc(file=sys
.stderr
)
215 raise AJAXException("Unknown error.")
219 COMMANDS
= dict(p
=push
, n
=newConnection
, s
=subscribe
)