lateefj / Frisky (http://src.hackingthought.com/projects/frisky/)
Frisky is an Asynchronous WSGI web server. Cross-platform, high performance, caching and compression API's included, and lightweight. Test server running Frisky: http://src.hackingthought.com/
| commit 15: | 8ebc1bf36ca1 |
| parent 14: | 12d5baa7906a |
| branch: | default |
Changed (Δ946 bytes):
TODO.txt (2 lines added, 1 lines removed)
frisky/httpd.py (3 lines added, 3 lines removed)
frisky/proc.py (10 lines added, 10 lines removed)
frisky/server.py (29 lines added, 2 lines removed)
samples/selector_sample/run.py (6 lines added, 4 lines removed)
1 |
1 |
Priorities: |
2 |
* Runs WSGI in seperate process for stability and performance |
|
3 |
2 |
* Create configuration file and support features listed below |
4 |
3 |
|
5 |
4 |
|
| … | … | @@ -56,6 +55,8 @@ grok - http://faassen.n--tree.net/blog/v |
56 |
55 |
werkzeug - http://dev.timparkin.co.uk/2009/01/werkzeug-and-werkzeugish-example.html |
57 |
56 |
repoze - http://blog.delaguardia.com.mx/index.php?op=ViewArticle&articleId=119&blogId=1 |
58 |
57 |
|
58 |
Static server blog - http://jtauber.com/blog/2009/01/26/serving_up_user_contributed_media_from_a_separate_server/ |
|
59 |
||
59 |
60 |
Caching: |
60 |
61 |
Need to support cache invalidation programmatically and cache invalidation |
61 |
62 |
timeouts |
Up to file-list frisky/httpd.py:
| … | … | @@ -352,8 +352,8 @@ class WSGIHandler(RequestHandler): |
352 |
352 |
# or can we pass the socket to write to ? Maybe can just pass |
353 |
353 |
# socket and it will work. Probably worth a try. |
354 |
354 |
if f is None: |
355 |
#f = proc.process_request_callback(self.callback, environ, response) |
|
356 |
f = self.callback(environ, response) |
|
355 |
f = proc.process_request_callback(server.CONFIG_FILE, environ, response) |
|
356 |
#f = self.callback(environ, response) |
|
357 |
357 |
|
358 |
358 |
# Write out the header |
359 |
359 |
self.wfile.write(str(response)) |
| … | … | @@ -378,7 +378,7 @@ def start(host='0.0.0.0', port=7777, cal |
378 |
378 |
""" |
379 |
379 |
# launch the server on the specified port |
380 |
380 |
s = Server(host, port, WSGIHandler, callback=callback) |
381 |
print "SimpleAsyncHTTPServer running on port %s" % |
|
381 |
print "SimpleAsyncHTTPServer running on port %s" % port |
|
382 |
382 |
try: |
383 |
383 |
asyncore.loop(timeout=2) |
384 |
384 |
except KeyboardInterrupt: |
Up to file-list frisky/proc.py:
| … | … | @@ -5,9 +5,10 @@ try: |
5 |
5 |
#2.6+ processing compatability |
6 |
6 |
from multiprocessing import Pool, Queue |
7 |
7 |
except: |
8 |
||
8 |
# 2.5 lowest support |
|
9 |
9 |
from processing import Pool, Queue |
10 |
10 |
|
11 |
from frisky import server |
|
11 |
12 |
log = logging.getLogger(name=__name__) |
12 |
13 |
# TODO: THIS NEED TO BE CONFIGUREATION!! |
13 |
14 |
REQUEST_TIMEOUT = 30 |
| … | … | @@ -19,19 +20,18 @@ def create_pool(): |
19 |
20 |
global pool |
20 |
21 |
pool = Pool(PROCESSES) |
21 |
22 |
|
22 |
def handle_wsgi_request(callback, environ, response): |
|
23 |
return callback(environ, response) |
|
23 |
def handle_wsgi_request(config_file, environ, response): |
|
24 |
if not server.CONFIGURED: |
|
25 |
server.load_config_file(config_file) |
|
26 |
#print('WSGI APPLICATION IS %s' % server.WSGI_APPLICATION) |
|
27 |
return server.WSGI_APPLICATION(environ, response) |
|
24 |
28 |
|
25 |
29 |
|
26 |
def process_request_callback(c |
|
30 |
def process_request_callback(config_file, environ, response): |
|
31 |
||
27 |
32 |
if pool is None: |
28 |
33 |
create_pool() |
29 |
||
30 |
for x in inspect.getmembers(callback): |
|
31 |
print x |
|
32 |
||
33 |
print('module %s and function %s and dir %s' % (callback.__module__, callback.__call__, dir(callback))) |
|
34 |
result = pool.apply_async(handle_wsgi_request, (callback, environ, response)) |
|
34 |
result = pool.apply_async(handle_wsgi_request, (config_file, environ, response)) |
|
35 |
35 |
return result.get(timeout=REQUEST_TIMEOUT) |
36 |
36 |
|
37 |
37 |
Up to file-list frisky/server.py:
| … | … | @@ -14,7 +14,7 @@ def configure(): |
14 |
14 |
""" |
15 |
15 |
|
16 |
16 |
""" |
17 |
FAWPS CODE |
|
17 |
FAWPS CODE TODO: figure out how to attribute correctly came from FAWPS code |
|
18 |
18 |
""" |
19 |
19 |
def redirect(start_response, location, permanent=None): |
20 |
20 |
header=[('location',location), |
| … | … | @@ -37,8 +37,13 @@ import logging |
37 |
37 |
import logging.handlers |
38 |
38 |
import mimetypes |
39 |
39 |
|
40 |
import simplejson |
|
41 |
||
40 |
42 |
from frisky.oracle import io |
41 |
43 |
|
44 |
CONFIG_FILE = None |
|
45 |
||
46 |
||
42 |
47 |
STATIC_CONFIG = {} |
43 |
48 |
|
44 |
49 |
DOMAIN_ALIAS = [] |
| … | … | @@ -48,6 +53,8 @@ LISTEN_PORT = 8080 |
48 |
53 |
LOG_FORMAT = '%(asctime)s %(levelname)-8s %(message)s' |
49 |
54 |
LOG_DATEFORMAT = '%a, %d %b %Y %H:%M:%S' |
50 |
55 |
|
56 |
WSGI_APPLICATION = None |
|
57 |
||
51 |
58 |
DEFAULT_CONFIG = { |
52 |
59 |
'logging':{ |
53 |
60 |
'level': logging.DEBUG, |
| … | … | @@ -59,7 +66,16 @@ DEFAULT_CONFIG = { |
59 |
66 |
CONFIGURED = False |
60 |
67 |
|
61 |
68 |
def configure(config): |
69 |
global CONFIGURED, WSGI_APPLICATION |
|
62 |
70 |
CONFIGURED = True |
71 |
if config.has_key('wsgi_callable'): |
|
72 |
callable = config['wsgi_callable'] |
|
73 |
func = callable.split('.')[-1] |
|
74 |
im = '.'.join(callable.split('.')[:-1]) |
|
75 |
# TODO: CLean this up so it isn't a rat nest. |
|
76 |
st = 'import %s\nglobal WSGI_APPLICATION\nWSGI_APPLICATION = %s.%s()' % (im, im, func) |
|
77 |
exec(st) |
|
78 |
||
63 |
79 |
if config.has_key('domain_aliases'): |
64 |
80 |
DOMAIN_ALIAS.extend(config['domain_aliases']) |
65 |
81 |
if config.has_key('url_forwards'): |
| … | … | @@ -175,7 +191,8 @@ def handle_callback(environ, start_respo |
175 |
191 |
if find_static_path(environ['PATH_INFO']): |
176 |
192 |
try: |
177 |
193 |
fpath = find_file_path(environ['PATH_INFO']) |
178 |
|
|
194 |
logging.debug('fpath is %s' % fpath) |
|
195 |
# Default cache to false |
|
179 |
196 |
cache_file = False |
180 |
197 |
|
181 |
198 |
if STATIC_CONFIG.has_key('CACHE') and STATIC_CONFIG['CACHE']['static']: |
| … | … | @@ -200,6 +217,16 @@ def handle_callback(environ, start_respo |
200 |
217 |
except FileNotFoundException, fnfe: |
201 |
218 |
logging.warning("File not found for path %s" % environ['PATH_INFO']) |
202 |
219 |
return None |
220 |
||
221 |
def load_config_file(config_file): |
|
222 |
print('Configuring with file %s' % config_file) |
|
223 |
f = open(config_file, 'r') |
|
224 |
config = simplejson.loads(f.read()) |
|
225 |
configure(config) |
|
203 |
226 |
|
227 |
if len(sys.argv) > 1: |
|
228 |
CONFIG_FILE = sys.argv[1] |
|
229 |
load_config_file(CONFIG_FILE) |
|
230 |
||
204 |
231 |
|
205 |
232 |
Up to file-list samples/selector_sample/run.py:
| … | … | @@ -7,7 +7,7 @@ Note: Yaro performance is horrible so no |
7 |
7 |
|
8 |
8 |
import selector |
9 |
9 |
|
10 |
|
|
10 |
#from frisky import httpd |
|
11 |
11 |
from frisky.oracle.io import optimize |
12 |
12 |
|
13 |
13 |
# It seems to have a small performance impact |
| … | … | @@ -23,11 +23,13 @@ def hello(environ, start_response): |
23 |
23 |
|
24 |
24 |
return ["Hello from Frisky Selector sample"] |
25 |
25 |
|
26 |
||
27 |
if __name__ == '__main__': |
|
26 |
def wsgi_callable(): |
|
28 |
27 |
SELECTOR = selector.Selector() |
29 |
28 |
SELECTOR.add('/', GET=hello) |
30 |
29 |
SELECTOR.add('/hello/{name}', GET=hello_name) |
30 |
return SELECTOR |
|
31 |
||
32 |
#if __name__ == '__main__': |
|
31 |
33 |
|
32 |
|
|
34 |
#httpd.start(callback=wsgi_callable()) |
|
33 |
35 |
