]>
Commit | Line | Data |
---|---|---|
07b243e0 | 1 | from twisted.web import resource, server, static\r |
4d256d41 CP |
2 | from twisted.names import client\r |
3 | from twisted.internet import reactor\r | |
4 | import simplejson, md5, sys, os, ircclient, time, config\r | |
5 | \r | |
6 | Sessions = {}\r | |
7 | \r | |
8 | def get_session_id():\r | |
9 | return md5.md5(os.urandom(16)).hexdigest()\r | |
10 | \r | |
11 | def 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 | |
19 | class 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 | |
70 | class Channel:\r | |
71 | def __init__(self, request):\r | |
72 | self.request = request\r | |
73 | \r | |
74 | class 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 | |
80 | class MultipleUseChannel(Channel):\r | |
81 | def write(self, data):\r | |
82 | self.request.write(data)\r | |
83 | return True\r | |
07b243e0 CP |
84 | \r |
85 | class 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 |