Mercurial > piecrust2
comparison piecrust/serving/middlewares.py @ 553:cc6f3dbe3048
serve: Extract some of the server's functionality into WSGI middlewares.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sat, 08 Aug 2015 22:01:47 -0700 |
parents | |
children | 93b656f0af54 |
comparison
equal
deleted
inserted
replaced
552:9612cfc6455a | 553:cc6f3dbe3048 |
---|---|
1 import os.path | |
2 from werkzeug.wrappers import Request, Response | |
3 from werkzeug.wsgi import ClosingIterator | |
4 from piecrust import RESOURCES_DIR, CACHE_DIR | |
5 from piecrust.serving.util import make_wrapped_file_response | |
6 | |
7 | |
8 class StaticResourcesMiddleware(object): | |
9 """ WSGI middleware that serves static files from the `resources/server` | |
10 directory in the PieCrust package. | |
11 """ | |
12 def __init__(self, app): | |
13 self.app = app | |
14 | |
15 def __call__(self, environ, start_response): | |
16 static_mount = '/__piecrust_static/' | |
17 | |
18 request = Request(environ) | |
19 if request.path.startswith(static_mount): | |
20 rel_req_path = request.path[len(static_mount):] | |
21 mount = os.path.join(RESOURCES_DIR, 'server') | |
22 full_path = os.path.join(mount, rel_req_path) | |
23 try: | |
24 response = make_wrapped_file_response( | |
25 environ, request, full_path) | |
26 return response(environ, start_response) | |
27 except OSError: | |
28 pass | |
29 | |
30 return self.app(environ, start_response) | |
31 | |
32 | |
33 class PieCrustDebugMiddleware(object): | |
34 """ WSGI middleware that handles debugging of PieCrust stuff. | |
35 """ | |
36 def __init__(self, app, root_dir, debug=False, | |
37 sub_cache_dir=None, run_sse_check=None): | |
38 self.app = app | |
39 self.root_dir = root_dir | |
40 self.debug = debug | |
41 self.run_sse_check = run_sse_check | |
42 self._proc_loop = None | |
43 self._out_dir = os.path.join(root_dir, CACHE_DIR, 'server') | |
44 if sub_cache_dir: | |
45 self._out_dir = os.path.join(sub_cache_dir, 'server') | |
46 self._handlers = { | |
47 'werkzeug_shutdown': self._shutdownWerkzeug, | |
48 'pipeline_status': self._startSSEProvider} | |
49 | |
50 if not self.run_sse_check or self.run_sse_check(): | |
51 # When using a server with code reloading, some implementations | |
52 # use process forking and we end up going here twice. We only want | |
53 # to start the pipeline loop in the inner process most of the | |
54 # time so we let the implementation tell us if this is OK. | |
55 from piecrust.serving.procloop import ProcessingLoop | |
56 self._proc_loop = ProcessingLoop(root_dir, self._out_dir, | |
57 sub_cache_dir=sub_cache_dir, | |
58 debug=debug) | |
59 self._proc_loop.start() | |
60 | |
61 def __call__(self, environ, start_response): | |
62 debug_mount = '/__piecrust_debug/' | |
63 | |
64 request = Request(environ) | |
65 if request.path.startswith(debug_mount): | |
66 rel_req_path = request.path[len(debug_mount):] | |
67 handler = self._handlers.get(rel_req_path) | |
68 if handler is not None: | |
69 return handler(request, start_response) | |
70 | |
71 return self.app(environ, start_response) | |
72 | |
73 def _shutdownWerkzeug(self, request, start_response): | |
74 shutdown_func = request.environ.get('werkzeug.server.shutdown') | |
75 if shutdown_func is None: | |
76 raise RuntimeError('Not running with the Werkzeug Server') | |
77 shutdown_func() | |
78 response = Response("Server shutting down...") | |
79 return response(request.environ, start_response) | |
80 | |
81 def _startSSEProvider(self, request, start_response): | |
82 from piecrust.serving.procloop import ( | |
83 PipelineStatusServerSentEventProducer) | |
84 provider = PipelineStatusServerSentEventProducer( | |
85 self._proc_loop) | |
86 it = provider.run() | |
87 response = Response(it, mimetype='text/event-stream') | |
88 response.headers['Cache-Control'] = 'no-cache' | |
89 response.headers['Last-Event-ID'] = \ | |
90 self._proc_loop.last_status_id | |
91 return ClosingIterator( | |
92 response(request.environ, start_response), | |
93 [provider.close]) | |
94 |