Mercurial > cosocket
annotate openwebchat.py @ 86:408738c3cd5d
Added a handle_tick function to coroutine dispatchers.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Fri, 01 May 2009 15:37:57 -0700 |
parents | a095f39117d9 |
children | 43d37495e9d4 |
rev | line source |
---|---|
26 | 1 import os |
51
fda6e9c4f2df
Port is now settable from cmd line
Atul Varma <varmaa@toolness.com>
parents:
46
diff
changeset
|
2 import sys |
26 | 3 import math |
28 | 4 import re |
5 import httplib | |
32
1acccfa6a4f6
Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents:
31
diff
changeset
|
6 import cStringIO |
1acccfa6a4f6
Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents:
31
diff
changeset
|
7 import mimetools |
58
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
8 import weakref |
63
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
9 import cgi |
26 | 10 |
11 from cosocket import * | |
12 import channels | |
13 | |
37
979b247cba5d
Serialization of conversation is now done in JSON format.
Atul Varma <varmaa@toolness.com>
parents:
36
diff
changeset
|
14 try: |
979b247cba5d
Serialization of conversation is now done in JSON format.
Atul Varma <varmaa@toolness.com>
parents:
36
diff
changeset
|
15 import json |
979b247cba5d
Serialization of conversation is now done in JSON format.
Atul Varma <varmaa@toolness.com>
parents:
36
diff
changeset
|
16 except ImportError: |
979b247cba5d
Serialization of conversation is now done in JSON format.
Atul Varma <varmaa@toolness.com>
parents:
36
diff
changeset
|
17 import simplejson as json |
979b247cba5d
Serialization of conversation is now done in JSON format.
Atul Varma <varmaa@toolness.com>
parents:
36
diff
changeset
|
18 |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
19 class Conversations(object): |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
20 def __init__(self): |
58
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
21 self._convs = weakref.WeakValueDictionary() |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
22 |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
23 def __len__(self): |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
24 return len(self._convs) |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
25 |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
26 def get(self, name): |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
27 if name not in self._convs: |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
28 filename = '%s.conversation' % name |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
29 if not os.path.exists(filename): |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
30 open(filename, 'w').close() |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
31 |
58
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
32 conv = Conversation(open(filename, 'r+w')) |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
33 self._convs[name] = conv |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
34 else: |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
35 conv = self._convs[name] |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
36 return conv |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
37 |
32
1acccfa6a4f6
Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents:
31
diff
changeset
|
38 class Conversation(list): |
36
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
39 def __init__(self, fileobj): |
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
40 list.__init__(self) |
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
41 self.__file = fileobj |
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
42 items = [] |
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
43 for line in self.__file.readlines(): |
37
979b247cba5d
Serialization of conversation is now done in JSON format.
Atul Varma <varmaa@toolness.com>
parents:
36
diff
changeset
|
44 items.append(json.loads(line)) |
36
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
45 self[:] = items |
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
46 |
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
47 def append(self, item): |
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
48 list.append(self, item) |
37
979b247cba5d
Serialization of conversation is now done in JSON format.
Atul Varma <varmaa@toolness.com>
parents:
36
diff
changeset
|
49 self.__file.write('%s\n' % json.dumps(item)) |
36
d93c08dca64b
Conversation is now serialized to disk and appended to when new messages come in.
Atul Varma <varmaa@toolness.com>
parents:
35
diff
changeset
|
50 self.__file.flush() |
32
1acccfa6a4f6
Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents:
31
diff
changeset
|
51 |
63
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
52 def _parse_qs(querystring): |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
53 querydict = {} |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
54 cgi_querydict = cgi.parse_qs(querystring) |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
55 for key, value in cgi_querydict.items(): |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
56 querydict[key] = cgi_querydict[key][0] |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
57 return querydict |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
58 |
26 | 59 class OpenWebChatServer(object): |
63
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
60 QUERYSTRING_TEMPLATE = re.compile('([^\?]*)\?(.*)') |
56
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
61 REDIRECT_TEMPLATE = re.compile('\/([A-Za-z0-9_]+)') |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
62 URL_TEMPLATE = re.compile('\/([A-Za-z0-9_]+)/(.*)') |
28 | 63 |
33
8146a59c8045
Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents:
32
diff
changeset
|
64 BOUNDARY = "'''" |
8146a59c8045
Added basic 'chat' functionality.
Atul Varma <varmaa@toolness.com>
parents:
32
diff
changeset
|
65 |
26 | 66 BLOCK_SIZE = 8192 |
67 | |
68 MIME_TYPES = {'html' : 'text/html', | |
69 'js' : 'text/javascript', | |
70 'css' : 'text/css'} | |
71 | |
65 | 72 def __init__(self, addr, conversations, is_keep_alive = False): |
73 self._is_keep_alive = is_keep_alive | |
58
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
74 self._num_connections = 0 |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
75 self._convs = conversations |
26 | 76 self._server = CoroutineSocketServer(addr, |
77 self._server_coroutine) | |
78 | |
79 def run(self): | |
86
408738c3cd5d
Added a handle_tick function to coroutine dispatchers.
Atul Varma <varmaa@toolness.com>
parents:
83
diff
changeset
|
80 self._server.run(timeout = 5.0) |
26 | 81 |
28 | 82 def _until_http_response_sent(self, msg = '', mimetype = 'text/plain', |
56
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
83 length = None, code = 200, |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
84 additional_headers = None): |
65 | 85 headers = {'Content-Type': mimetype} |
86 if self._is_keep_alive: | |
87 headers.update({'Keep-Alive': 'timeout=99, max=99', | |
88 'Connection': 'Keep-Alive'}) | |
56
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
89 if additional_headers: |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
90 headers.update(additional_headers) |
30 | 91 if not mimetype.startswith('multipart'): |
92 if length is None: | |
93 length = len(msg) | |
31 | 94 headers['Content-Length'] = str(length) |
95 | |
96 header_lines = ['HTTP/1.1 %d %s' % (code, | |
97 httplib.responses[code])] | |
98 header_lines.extend(['%s: %s' % (key, value) | |
99 for key, value in headers.items()]) | |
100 header_lines.extend(['', msg]) | |
101 content = '\r\n'.join(header_lines) | |
28 | 102 yield until_sent(content) |
26 | 103 |
104 def _until_file_sent(self, filename): | |
105 mimetype = self.MIME_TYPES[filename.split('.')[-1]] | |
106 | |
107 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
|
108 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
|
109 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
|
110 num_blocks += 1 |
26 | 111 infile = open(filename, 'r') |
112 | |
28 | 113 yield self._until_http_response_sent(mimetype = mimetype, |
114 length = length) | |
26 | 115 |
116 for i in range(num_blocks): | |
117 # TODO: This could be bad since we're reading the file | |
118 # synchronously. | |
119 block = infile.read(self.BLOCK_SIZE) | |
120 yield until_sent(block) | |
121 | |
122 def _server_coroutine(self, addr): | |
58
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
123 self._num_connections += 1 |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
124 try: |
65 | 125 if self._is_keep_alive: |
126 while 1: | |
127 yield self._until_one_request_processed(addr) | |
128 else: | |
58
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
129 yield self._until_one_request_processed(addr) |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
130 finally: |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
131 self._num_connections -= 1 |
26 | 132 |
54
d1331955845f
JSON data is now sent w/ the proper mime type.
Atul Varma <varmaa@toolness.com>
parents:
51
diff
changeset
|
133 def __multipart_boundary(self, boundary, mimetype = 'application/json'): |
45
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
134 # Here we actually declare the content type and start the |
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
135 # transfer of the document itself; this is needed to |
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
136 # trigger an error on the browser-side, because a closed |
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
137 # connection during any other phase is unlikely to |
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
138 # cause any event to trigger on the client webpage. |
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
139 return '\r\n'.join(('--%s' % boundary, |
54
d1331955845f
JSON data is now sent w/ the proper mime type.
Atul Varma <varmaa@toolness.com>
parents:
51
diff
changeset
|
140 'Content-Type: %s' % mimetype, |
45
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
141 '', |
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
142 '')) |
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
143 |
30 | 144 def _until_multipart_header_sent(self, boundary): |
145 yield self._until_http_response_sent( | |
45
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
146 self.__multipart_boundary(boundary), |
30 | 147 mimetype = ('multipart/x-mixed-replace; ' |
148 'boundary="%s"' % boundary)) | |
149 | |
150 def _until_multipart_part_sent(self, boundary, msg): | |
151 yield until_sent('\r\n'.join( | |
45
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
152 (msg, |
30 | 153 '', |
45
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
154 self.__multipart_boundary(boundary)) |
27785e0ac4d8
Added error detection on the client-side.
Atul Varma <varmaa@toolness.com>
parents:
44
diff
changeset
|
155 )) |
30 | 156 |
63
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
157 def _parse_id(self, string): |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
158 i = 0 |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
159 if string: |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
160 try: |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
161 i = int(string) |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
162 if i < 0: |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
163 i = 0 |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
164 except ValueError: |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
165 pass |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
166 return i |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
167 |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
168 def _until_conv_request_processed(self, addr, headers, method, |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
169 conv_name, page): |
63
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
170 match = self.QUERYSTRING_TEMPLATE.match(page) |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
171 querydict = {} |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
172 if match: |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
173 querydict.update(_parse_qs(match.group(2))) |
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
174 page = match.group(1) |
64
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
175 if page == 'listen': |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
176 i = self._parse_id(querydict.get('start')) |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
177 conv = self._convs.get(conv_name) |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
178 while i >= len(conv): |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
179 yield channels.until_message_received(conv_name) |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
180 yield self._until_http_response_sent( |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
181 json.dumps({'messages': conv[i:]}), |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
182 mimetype = 'application/json' |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
183 ) |
559c48a58254
Added the option to long poll instead of using mime multipart.
Atul Varma <varmaa@toolness.com>
parents:
63
diff
changeset
|
184 elif page == 'listen/multipart': |
63
b19641a0d5ad
Refactoring: better querystring parsing.
Atul Varma <varmaa@toolness.com>
parents:
61
diff
changeset
|
185 i = self._parse_id(querydict.get('start')) |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
186 yield self._until_multipart_header_sent(self.BOUNDARY) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
187 conv = self._convs.get(conv_name) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
188 while 1: |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
189 while i < len(conv): |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
190 msg = json.dumps(conv[i]) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
191 i += 1 |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
192 yield self._until_multipart_part_sent(self.BOUNDARY, msg) |
60
aa0763886ec9
open web chat now uses a separate channel for each conversation.
Atul Varma <varmaa@toolness.com>
parents:
58
diff
changeset
|
193 yield channels.until_message_received(conv_name) |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
194 elif page == 'send': |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
195 length = int(headers.getheader('Content-Length', 0)) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
196 msg = yield until_received(bytes = length) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
197 conv = self._convs.get(conv_name) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
198 conv.append(json.loads(msg)) |
60
aa0763886ec9
open web chat now uses a separate channel for each conversation.
Atul Varma <varmaa@toolness.com>
parents:
58
diff
changeset
|
199 yield channels.until_message_sent(conv_name, None) |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
200 yield self._until_http_response_sent('sent.') |
73
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
201 elif page == '': |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
202 yield self._until_file_sent('openwebchat.html') |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
203 else: |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
204 yield self._until_http_response_sent('not found', |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
205 code = 404) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
206 |
26 | 207 def _until_one_request_processed(self, addr): |
208 request = yield until_received(terminator = '\r\n\r\n') | |
209 request = request.splitlines() | |
210 request_line = request[0] | |
32
1acccfa6a4f6
Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents:
31
diff
changeset
|
211 stringfile = cStringIO.StringIO('\n'.join(request[1:])) |
1acccfa6a4f6
Added support for header parsing.
Atul Varma <varmaa@toolness.com>
parents:
31
diff
changeset
|
212 headers = mimetools.Message(stringfile) |
26 | 213 req_parts = request_line.split() |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
214 method = req_parts[0] |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
215 match = self.URL_TEMPLATE.match(req_parts[1]) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
216 if not match: |
56
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
217 match = self.REDIRECT_TEMPLATE.match(req_parts[1]) |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
218 if match: |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
219 newpath = req_parts[1] + '/' |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
220 yield self._until_http_response_sent( |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
221 newpath, |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
222 code = 301, |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
223 additional_headers = {'Location': newpath} |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
224 ) |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
225 else: |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
226 yield self._until_http_response_sent('not found', |
0bb64cafd063
Added redirects to add extra slash at end of conversation name.
Atul Varma <varmaa@toolness.com>
parents:
55
diff
changeset
|
227 code = 404) |
28 | 228 else: |
55
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
229 conv_name = match.group(1) |
5e08a9f4730e
We now support multiple conversations based on the URL.
Atul Varma <varmaa@toolness.com>
parents:
54
diff
changeset
|
230 page = match.group(2) |
58
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
231 if conv_name == 'status': |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
232 # TODO: Return 404 if page is non-empty. |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
233 lines = ('open connections : %d' % self._num_connections, |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
234 'open conversations: %d'% len(self._convs)) |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
235 yield self._until_http_response_sent('\r\n'.join(lines)) |
73
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
236 elif conv_name == 'media': |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
237 if page in ['js/jquery.js', |
83
a095f39117d9
date sent display is much better
Atul Varma <varmaa@toolness.com>
parents:
73
diff
changeset
|
238 'js/jquery.timeago.js', |
73
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
239 'js/openwebchat.js', |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
240 'js/json2.js', |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
241 'css/openwebchat.css']: |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
242 filename = os.path.join('media', *page.split('/')) |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
243 yield self._until_file_sent(filename) |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
244 else: |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
245 yield self._until_http_response_sent('not found', |
878871076cfa
Moved static files into a new media subdirectory.
Atul Varma <varmaa@toolness.com>
parents:
67
diff
changeset
|
246 code = 404) |
58
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
247 else: |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
248 yield self._until_conv_request_processed(addr, headers, |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
249 method, conv_name, |
7a2ecb3e800f
conversations dict is now a weak value dict. Added a status page showing current resource usage.
Atul Varma <varmaa@toolness.com>
parents:
56
diff
changeset
|
250 page) |
26 | 251 |
67
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
252 class Args(object): |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
253 def __str__(self): |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
254 items = [] |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
255 for key in self.__dict__: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
256 items.append('%s=%s' % (key, self.__dict__[key])) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
257 return ', '.join(items) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
258 |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
259 def get_args(args = sys.argv[1:], **kwargs): |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
260 new_args = Args() |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
261 regexp = re.compile(r'([A-Za-z0-9_]+)=(.*)') |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
262 for key in kwargs: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
263 setattr(new_args, key, kwargs[key]) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
264 |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
265 for arg in args: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
266 match = regexp.match(arg) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
267 if match: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
268 key = match.group(1) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
269 if key not in kwargs: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
270 raise ValueError('invalid argument: %s' % key) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
271 value = match.group(2) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
272 constructor = type(kwargs[key]) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
273 if constructor == bool: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
274 constructor = make_boolish |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
275 setattr(new_args, key, constructor(value)) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
276 return new_args |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
277 |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
278 def make_boolish(val): |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
279 if type(val) is not bool: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
280 if val.lower() in ['true', '1', 'yes']: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
281 val = True |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
282 elif val.lower() in ['false', '0', 'no']: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
283 val = False |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
284 else: |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
285 raise ValueError('not a boolean: %s' % val) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
286 return val |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
287 |
26 | 288 if __name__ == '__main__': |
67
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
289 args = get_args(ip = '127.0.0.1', |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
290 port = 8071, |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
291 is_keep_alive = True) |
51
fda6e9c4f2df
Port is now settable from cmd line
Atul Varma <varmaa@toolness.com>
parents:
46
diff
changeset
|
292 |
67
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
293 server = OpenWebChatServer(addr = (args.ip, args.port), |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
294 conversations = Conversations(), |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
295 is_keep_alive = args.is_keep_alive) |
4f449ed51dd3
Made cmd-line args more flexible, robust, and readable.
Atul Varma <varmaa@toolness.com>
parents:
66
diff
changeset
|
296 print "Starting server with configuration: %s" % args |
26 | 297 server.run() |