annotate openwebchat.py @ 33:8146a59c8045

Added basic 'chat' functionality.
author Atul Varma <varmaa@toolness.com>
date Mon, 27 Apr 2009 14:44:40 -0700
parents 1acccfa6a4f6
children 0e853a889c27
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
1 import os
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
2 import math
28
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
3 import re
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
4 import httplib
32
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
5 import cStringIO
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
6 import mimetools
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
7
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
8 from cosocket import *
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
9 import channels
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
10
32
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
11 class Conversation(list):
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
12 pass
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
13
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
14 class Conversations(dict):
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
15 pass
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
16
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
17 class OpenWebChatServer(object):
28
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
18 CONVERSATION_URL = re.compile('\/conversations\/([A-Za-z0-9_]+)')
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
19
33
8146a59c8045 Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents: 32
diff changeset
20 BOUNDARY = "'''"
8146a59c8045 Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents: 32
diff changeset
21
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
22 BLOCK_SIZE = 8192
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
23
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
24 MIME_TYPES = {'html' : 'text/html',
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
25 'js' : 'text/javascript',
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
26 'css' : 'text/css'}
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
27
32
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
28 def __init__(self, addr, conversations):
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
29 self._convs = conversations
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
30 self._server = CoroutineSocketServer(addr,
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
31 self._server_coroutine)
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
32
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
33 def run(self):
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
34 self._server.run()
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
35
28
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
36 def _until_http_response_sent(self, msg = '', mimetype = 'text/plain',
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
37 length = None, code = 200):
31
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
38 headers = {'Keep-Alive': 'timeout=99, max=99',
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
39 'Connection': 'Keep-Alive',
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
40 'Content-Type': mimetype}
30
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
41 if not mimetype.startswith('multipart'):
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
42 if length is None:
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
43 length = len(msg)
31
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
44 headers['Content-Length'] = str(length)
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
45
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
46 header_lines = ['HTTP/1.1 %d %s' % (code,
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
47 httplib.responses[code])]
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
48 header_lines.extend(['%s: %s' % (key, value)
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
49 for key, value in headers.items()])
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
50 header_lines.extend(['', msg])
041bda62b614 More refactorings.
Atul Varma <varmaa@toolness.com>
parents: 30
diff changeset
51 content = '\r\n'.join(header_lines)
28
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
52 yield until_sent(content)
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
53
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
54 def _until_file_sent(self, filename):
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
55 mimetype = self.MIME_TYPES[filename.split('.')[-1]]
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
56
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
57 length = os.stat(filename).st_size
27
7e74ceedaa26 More readable way of determining number of blocks needed, though I think I'm missing something...
Atul Varma <varmaa@toolness.com>
parents: 26
diff changeset
58 num_blocks = length / self.BLOCK_SIZE
7e74ceedaa26 More readable way of determining number of blocks needed, though I think I'm missing something...
Atul Varma <varmaa@toolness.com>
parents: 26
diff changeset
59 if length % self.BLOCK_SIZE:
7e74ceedaa26 More readable way of determining number of blocks needed, though I think I'm missing something...
Atul Varma <varmaa@toolness.com>
parents: 26
diff changeset
60 num_blocks += 1
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
61 infile = open(filename, 'r')
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
62
28
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
63 yield self._until_http_response_sent(mimetype = mimetype,
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
64 length = length)
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
65
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
66 for i in range(num_blocks):
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
67 # TODO: This could be bad since we're reading the file
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
68 # synchronously.
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
69 block = infile.read(self.BLOCK_SIZE)
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
70 yield until_sent(block)
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
71
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
72 def _server_coroutine(self, addr):
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
73 while 1:
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
74 yield self._until_one_request_processed(addr)
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
75
30
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
76 def _until_multipart_header_sent(self, boundary):
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
77 yield self._until_http_response_sent(
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
78 '--%s\r\n' % boundary,
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
79 mimetype = ('multipart/x-mixed-replace; '
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
80 'boundary="%s"' % boundary))
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
81
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
82 def _until_multipart_part_sent(self, boundary, msg):
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
83 yield until_sent('\r\n'.join(
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
84 ('Content-Length: %d' % len(msg),
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
85 'Content-Type: text/plain',
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
86 '',
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
87 msg,
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
88 '',
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
89 '--%s' % boundary,
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
90 '')))
e5b85cdd7228 Fixed some bugs.
Atul Varma <varmaa@toolness.com>
parents: 29
diff changeset
91
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
92 def _until_one_request_processed(self, addr):
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
93 request = yield until_received(terminator = '\r\n\r\n')
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
94 request = request.splitlines()
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
95 request_line = request[0]
32
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
96 stringfile = cStringIO.StringIO('\n'.join(request[1:]))
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
97 headers = mimetools.Message(stringfile)
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
98 req_parts = request_line.split()
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
99 if req_parts[1] == '/listen':
33
8146a59c8045 Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents: 32
diff changeset
100 yield self._until_multipart_header_sent(self.BOUNDARY)
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
101 while 1:
33
8146a59c8045 Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents: 32
diff changeset
102 msg = yield channels.until_message_received('global')
8146a59c8045 Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents: 32
diff changeset
103 yield self._until_multipart_part_sent(self.BOUNDARY, msg)
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
104 elif req_parts[1] == '/send':
32
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
105 length = int(headers.getheader('Content-Length', 0))
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
106 msg = yield until_received(bytes = length)
33
8146a59c8045 Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents: 32
diff changeset
107 yield channels.until_message_sent('global', msg)
28
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
108 yield self._until_http_response_sent('sent.')
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
109 elif req_parts[1] in ['/', '/jquery.js', '/openwebchat.js',
33
8146a59c8045 Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents: 32
diff changeset
110 '/json2.js', '/openwebchat.css']:
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
111 if req_parts[1] == '/':
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
112 filename = 'openwebchat.html'
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
113 else:
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
114 filename = req_parts[1][1:]
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
115
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
116 yield self._until_file_sent(filename)
28
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
117 else:
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
118 match = self.CONVERSATION_URL.match(req_parts[1])
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
119 if match:
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
120 yield self._until_http_response_sent('not implemented',
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
121 code = 501)
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
122 else:
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
123 yield self._until_http_response_sent('not found',
91c47c54b666 Refactorings.
Atul Varma <varmaa@toolness.com>
parents: 27
diff changeset
124 code = 404)
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
125
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
126 if __name__ == '__main__':
32
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
127 server = OpenWebChatServer(('127.0.0.1', 8071),
1acccfa6a4f6 Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents: 31
diff changeset
128 Conversations())
26
4a4b66f5229b Added open web chat module.
Atul Varma <varmaa@toolness.com>
parents:
diff changeset
129 server.run()