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 |
