]> jfr.im git - irc/quakenet/qwebirc.git/blame - qwebirc/ajaxengine.py
Add command parsing and lots of other stuff...
[irc/quakenet/qwebirc.git] / qwebirc / ajaxengine.py
CommitLineData
07b243e0 1from twisted.web import resource, server, static\r
4d256d41
CP
2from twisted.names import client\r
3from twisted.internet import reactor\r
4import simplejson, md5, sys, os, ircclient, time, config\r
5\r
6Sessions = {}\r
7\r
8def get_session_id():\r
9 return md5.md5(os.urandom(16)).hexdigest()\r
10 \r
11def jsondump(fn):\r
12 def decorator(*args, **kwargs):\r
13 x = fn(*args, **kwargs)\r
14 if isinstance(x, list):\r
15 return simplejson.dumps(x)\r
16 return x\r
17 return decorator\r
18\r
19class IRCSession:\r
20 def __init__(self, id):\r
21 self.id = id\r
22 self.subscriptions = []\r
23 self.buffer = []\r
24 self.throttle = 0\r
25 self.schedule = None\r
26 \r
27 def subscribe(self, channel):\r
28 self.subscriptions.append(channel)\r
29 self.flush()\r
30 \r
31 def flush(self, scheduled=False):\r
32 if scheduled:\r
33 self.schedule = None\r
34 \r
35 if not self.buffer or not self.subscriptions:\r
36 return\r
37 \r
38 t = time.time()\r
39 \r
40 if t < self.throttle:\r
41 if not self.schedule:\r
42 self.schedule = reactor.callLater(self.throttle - t, self.flush, True)\r
43 return\r
b15204e3
CP
44 else:\r
45 # process the rest of the packet\r
46 if not scheduled:\r
47 if not self.schedule:\r
48 self.schedule = reactor.callLater(0, self.flush, True)\r
49 return\r
50 \r
4d256d41
CP
51 self.throttle = t + config.UPDATE_FREQ\r
52\r
53 encdata = simplejson.dumps(self.buffer)\r
54 self.buffer = []\r
55 \r
56 newsubs = []\r
57 for x in self.subscriptions:\r
58 if x.write(encdata):\r
59 newsubs.append(x)\r
60\r
61 self.subscriptions = newsubs\r
62 \r
63 def event(self, data):\r
64 self.buffer.append(data)\r
65 self.flush()\r
66 \r
67 def push(self, data):\r
68 self.client.write(data)\r
69 \r
70class Channel:\r
71 def __init__(self, request):\r
72 self.request = request\r
73 \r
74class SingleUseChannel(Channel):\r
75 def write(self, data):\r
76 self.request.write(data)\r
77 self.request.finish()\r
78 return False\r
79 \r
80class MultipleUseChannel(Channel):\r
81 def write(self, data):\r
82 self.request.write(data)\r
83 return True\r
07b243e0
CP
84\r
85class AJAXEngine(resource.Resource):\r
4d256d41
CP
86 isLeaf = True\r
87 \r
88 def __init__(self, prefix):\r
89 self.prefix = prefix\r
90\r
91 @jsondump\r
92 def render_GET(self, request):\r
93 path = request.path[len(self.prefix):]\r
94 if path == "/n":\r
95 ip = request.transport.getPeer()\r
96 ip = ip[1]\r
97\r
98 nick, ident = request.args.get("nick"), "webchat"\r
99 if not nick:\r
100 return [False, "Nickname not supplied"]\r
101 \r
102 nick = nick[0]\r
103 \r
104 id = get_session_id()\r
105 \r
106 session = IRCSession(id)\r
107\r
108 client = ircclient.createIRC(session, nick=nick, ident=ident, ip=ip, realname=nick)\r
109 session.client = client\r
110 \r
111 Sessions[id] = session\r
112 \r
113 return [True, id]\r
114 \r
115 if path.startswith("/s/"):\r
116 sessionid = path[3:]\r
117 session = Sessions.get(sessionid)\r
118 \r
119 if not session:\r
120 return [False, "Bad session ID"]\r
121\r
122 session.subscribe(SingleUseChannel(request))\r
123 return server.NOT_DONE_YET\r
124 if path.startswith("/p/"):\r
125 command = request.args.get("c")\r
126 if not command:\r
127 return [False, "No command specified"]\r
128\r
129 command = command[0]\r
130 \r
131 sessionid = path[3:]\r
132 session = Sessions.get(sessionid)\r
133 if not session:\r
134 return [False, "Bad session ID"]\r
135\r
136 try:\r
137 decoded = command.decode("utf-8")\r
138 except UnicodeDecodeError:\r
139 decoded = command.decode("iso-8859-1", "ignore")\r
140 session.push(decoded)\r
141 return [True]\r
142\r
143 return [False, "404"]\r
144\r