diff piecrust/serving/wrappers.py @ 917:33a89139c284

serve: Add `--admin` option to run the administration panel. - Removed the `admin run` command. - Cleaned up middlewares a bit.
author Ludovic Chabant <ludovic@chabant.com>
date Fri, 29 Sep 2017 08:42:38 -0700
parents 1bb0d973dc69
children 7ecb946bfafd
line wrap: on
line diff
--- a/piecrust/serving/wrappers.py	Wed Sep 27 19:07:55 2017 -0700
+++ b/piecrust/serving/wrappers.py	Fri Sep 29 08:42:38 2017 -0700
@@ -6,8 +6,41 @@
 logger = logging.getLogger(__name__)
 
 
-def run_werkzeug_server(appfactory, host, port,
-                        use_debugger=False, use_reloader=False):
+def run_piecrust_server(wsgi, appfactory, host, port,
+                        is_cmdline_mode=False,
+                        serve_admin=False,
+                        use_debugger=False,
+                        use_reloader=False):
+
+    if wsgi == 'werkzeug':
+        _run_werkzeug_server(appfactory, host, port,
+                             is_cmdline_mode=is_cmdline_mode,
+                             serve_admin=serve_admin,
+                             use_debugger=use_debugger,
+                             use_reloader=use_reloader)
+
+    elif wsgi == 'gunicorn':
+        options = {
+            'bind': '%s:%s' % (host, port),
+            'accesslog': '-',  # print access log to stderr
+        }
+        if use_debugger:
+            options['loglevel'] = 'debug'
+        if use_reloader:
+            options['reload'] = True
+        _run_gunicorn_server(appfactory,
+                             is_cmdline_mode=is_cmdline_mode,
+                             gunicorn_options=options)
+
+    else:
+        raise Exception("Unknown WSGI server: %s" % wsgi)
+
+
+def _run_werkzeug_server(appfactory, host, port, *,
+                         is_cmdline_mode=False,
+                         serve_admin=False,
+                         use_debugger=False,
+                         use_reloader=False):
     from werkzeug.serving import run_simple
 
     def _run_sse_check():
@@ -21,6 +54,9 @@
                 os.environ.get('WERKZEUG_RUN_MAIN') == 'true')
 
     app = _get_piecrust_server(appfactory,
+                               is_cmdline_mode=is_cmdline_mode,
+                               serve_site=True,
+                               serve_admin=serve_admin,
                                run_sse_check=_run_sse_check)
 
     # We need to do a few things to get Werkzeug to properly shutdown or
@@ -45,6 +81,10 @@
         from piecrust.serving import procloop
         procloop.server_shutdown = True
 
+        if serve_admin:
+            from piecrust.admin import pubutil
+            pubutil.server_shutdown = True
+
     def _shutdown_server_and_raise_sigint():
         if not use_reloader or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
             # We only need to shutdown the SSE requests for the process
@@ -75,7 +115,9 @@
         raise
 
 
-def run_gunicorn_server(appfactory, gunicorn_options=None):
+def _run_gunicorn_server(appfactory,
+                         is_cmdline_mode=False,
+                         gunicorn_options=None):
     from gunicorn.app.base import BaseApplication
 
     class PieCrustGunicornApplication(BaseApplication):
@@ -92,20 +134,72 @@
         def load(self):
             return self.app
 
-    app = _get_piecrust_server(appfactory)
+    app = _get_piecrust_server(appfactory,
+                               is_cmdline_mode=is_cmdline_mode)
 
     gunicorn_options = gunicorn_options or {}
     app_wrapper = PieCrustGunicornApplication(app, gunicorn_options)
     app_wrapper.run()
 
 
-def _get_piecrust_server(appfactory, run_sse_check=None):
-    from piecrust.serving.middlewares import (
-        StaticResourcesMiddleware, PieCrustDebugMiddleware)
-    from piecrust.serving.server import WsgiServer
-    app = WsgiServer(appfactory)
-    app = StaticResourcesMiddleware(app)
-    app = PieCrustDebugMiddleware(
-        app, appfactory, run_sse_check=run_sse_check)
+def _get_piecrust_server(appfactory, *,
+                         serve_site=True,
+                         serve_admin=False,
+                         is_cmdline_mode=False,
+                         run_sse_check=None):
+    app = None
+
+    if serve_site:
+        from piecrust.serving.middlewares import (
+            PieCrustStaticResourcesMiddleware, PieCrustDebugMiddleware)
+        from piecrust.serving.server import PieCrustServer
+
+        app = PieCrustServer(appfactory)
+        app = PieCrustStaticResourcesMiddleware(app)
+
+        if is_cmdline_mode:
+            app = PieCrustDebugMiddleware(
+                app, appfactory, run_sse_check=run_sse_check)
+
+    if serve_admin:
+        from piecrust.admin.web import create_foodtruck_app
+
+        admin_root_url = '/pc-admin'
+        es = {
+            'FOODTRUCK_CMDLINE_MODE': is_cmdline_mode,
+            'FOODTRUCK_ROOT': appfactory.root_dir,
+            'FOODTRUCK_URL_PREFIX': admin_root_url,
+            'DEBUG': appfactory.debug}
+        if is_cmdline_mode:
+            es.update({
+                'SECRET_KEY': os.urandom(22),
+                'LOGIN_DISABLED': True})
+
+        if appfactory.debug and is_cmdline_mode:
+            # Disable PIN protection with Werkzeug's debugger.
+            os.environ['WERKZEUG_DEBUG_PIN'] = 'off'
+
+        admin_app = create_foodtruck_app(es)
+        admin_app.wsgi_app = _PieCrustSiteOrAdminMiddleware(
+            app, admin_app.wsgi_app, admin_root_url)
+        app = admin_app
+
     return app
 
+
+class _PieCrustSiteOrAdminMiddleware:
+    def __init__(self, main_app, admin_app, admin_root_url):
+        from werkzeug.exceptions import abort
+
+        def _err_resp(e, sr):
+            abort(404)
+
+        self.main_app = main_app
+        self.admin_app = admin_app or _err_resp
+        self.admin_root_url = admin_root_url
+
+    def __call__(self, environ, start_response):
+        path_info = environ.get('PATH_INFO', '')
+        if path_info.startswith(self.admin_root_url):
+            return self.admin_app(environ, start_response)
+        return self.main_app(environ, start_response)