comparison 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
comparison
equal deleted inserted replaced
916:84ce51430346 917:33a89139c284
4 4
5 5
6 logger = logging.getLogger(__name__) 6 logger = logging.getLogger(__name__)
7 7
8 8
9 def run_werkzeug_server(appfactory, host, port, 9 def run_piecrust_server(wsgi, appfactory, host, port,
10 use_debugger=False, use_reloader=False): 10 is_cmdline_mode=False,
11 serve_admin=False,
12 use_debugger=False,
13 use_reloader=False):
14
15 if wsgi == 'werkzeug':
16 _run_werkzeug_server(appfactory, host, port,
17 is_cmdline_mode=is_cmdline_mode,
18 serve_admin=serve_admin,
19 use_debugger=use_debugger,
20 use_reloader=use_reloader)
21
22 elif wsgi == 'gunicorn':
23 options = {
24 'bind': '%s:%s' % (host, port),
25 'accesslog': '-', # print access log to stderr
26 }
27 if use_debugger:
28 options['loglevel'] = 'debug'
29 if use_reloader:
30 options['reload'] = True
31 _run_gunicorn_server(appfactory,
32 is_cmdline_mode=is_cmdline_mode,
33 gunicorn_options=options)
34
35 else:
36 raise Exception("Unknown WSGI server: %s" % wsgi)
37
38
39 def _run_werkzeug_server(appfactory, host, port, *,
40 is_cmdline_mode=False,
41 serve_admin=False,
42 use_debugger=False,
43 use_reloader=False):
11 from werkzeug.serving import run_simple 44 from werkzeug.serving import run_simple
12 45
13 def _run_sse_check(): 46 def _run_sse_check():
14 # We don't want to run the processing loop here if this isn't 47 # We don't want to run the processing loop here if this isn't
15 # the actual process that does the serving. In most cases it is, 48 # the actual process that does the serving. In most cases it is,
19 # `WERKZEUG_RUN_MAIN` variable set. 52 # `WERKZEUG_RUN_MAIN` variable set.
20 return (not use_reloader or 53 return (not use_reloader or
21 os.environ.get('WERKZEUG_RUN_MAIN') == 'true') 54 os.environ.get('WERKZEUG_RUN_MAIN') == 'true')
22 55
23 app = _get_piecrust_server(appfactory, 56 app = _get_piecrust_server(appfactory,
57 is_cmdline_mode=is_cmdline_mode,
58 serve_site=True,
59 serve_admin=serve_admin,
24 run_sse_check=_run_sse_check) 60 run_sse_check=_run_sse_check)
25 61
26 # We need to do a few things to get Werkzeug to properly shutdown or 62 # We need to do a few things to get Werkzeug to properly shutdown or
27 # restart while SSE responses are running. This is because Werkzeug runs 63 # restart while SSE responses are running. This is because Werkzeug runs
28 # them in background threads (because we tell it to), but those threads 64 # them in background threads (because we tell it to), but those threads
43 # see the comment down there for more info. 79 # see the comment down there for more info.
44 def _shutdown_server(): 80 def _shutdown_server():
45 from piecrust.serving import procloop 81 from piecrust.serving import procloop
46 procloop.server_shutdown = True 82 procloop.server_shutdown = True
47 83
84 if serve_admin:
85 from piecrust.admin import pubutil
86 pubutil.server_shutdown = True
87
48 def _shutdown_server_and_raise_sigint(): 88 def _shutdown_server_and_raise_sigint():
49 if not use_reloader or os.environ.get('WERKZEUG_RUN_MAIN') == 'true': 89 if not use_reloader or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
50 # We only need to shutdown the SSE requests for the process 90 # We only need to shutdown the SSE requests for the process
51 # that actually runs them. 91 # that actually runs them.
52 print("") 92 print("")
73 # not exit. 113 # not exit.
74 _shutdown_server() 114 _shutdown_server()
75 raise 115 raise
76 116
77 117
78 def run_gunicorn_server(appfactory, gunicorn_options=None): 118 def _run_gunicorn_server(appfactory,
119 is_cmdline_mode=False,
120 gunicorn_options=None):
79 from gunicorn.app.base import BaseApplication 121 from gunicorn.app.base import BaseApplication
80 122
81 class PieCrustGunicornApplication(BaseApplication): 123 class PieCrustGunicornApplication(BaseApplication):
82 def __init__(self, app, options): 124 def __init__(self, app, options):
83 self.app = app 125 self.app = app
90 self.cfg.set(k, v) 132 self.cfg.set(k, v)
91 133
92 def load(self): 134 def load(self):
93 return self.app 135 return self.app
94 136
95 app = _get_piecrust_server(appfactory) 137 app = _get_piecrust_server(appfactory,
138 is_cmdline_mode=is_cmdline_mode)
96 139
97 gunicorn_options = gunicorn_options or {} 140 gunicorn_options = gunicorn_options or {}
98 app_wrapper = PieCrustGunicornApplication(app, gunicorn_options) 141 app_wrapper = PieCrustGunicornApplication(app, gunicorn_options)
99 app_wrapper.run() 142 app_wrapper.run()
100 143
101 144
102 def _get_piecrust_server(appfactory, run_sse_check=None): 145 def _get_piecrust_server(appfactory, *,
103 from piecrust.serving.middlewares import ( 146 serve_site=True,
104 StaticResourcesMiddleware, PieCrustDebugMiddleware) 147 serve_admin=False,
105 from piecrust.serving.server import WsgiServer 148 is_cmdline_mode=False,
106 app = WsgiServer(appfactory) 149 run_sse_check=None):
107 app = StaticResourcesMiddleware(app) 150 app = None
108 app = PieCrustDebugMiddleware( 151
109 app, appfactory, run_sse_check=run_sse_check) 152 if serve_site:
153 from piecrust.serving.middlewares import (
154 PieCrustStaticResourcesMiddleware, PieCrustDebugMiddleware)
155 from piecrust.serving.server import PieCrustServer
156
157 app = PieCrustServer(appfactory)
158 app = PieCrustStaticResourcesMiddleware(app)
159
160 if is_cmdline_mode:
161 app = PieCrustDebugMiddleware(
162 app, appfactory, run_sse_check=run_sse_check)
163
164 if serve_admin:
165 from piecrust.admin.web import create_foodtruck_app
166
167 admin_root_url = '/pc-admin'
168 es = {
169 'FOODTRUCK_CMDLINE_MODE': is_cmdline_mode,
170 'FOODTRUCK_ROOT': appfactory.root_dir,
171 'FOODTRUCK_URL_PREFIX': admin_root_url,
172 'DEBUG': appfactory.debug}
173 if is_cmdline_mode:
174 es.update({
175 'SECRET_KEY': os.urandom(22),
176 'LOGIN_DISABLED': True})
177
178 if appfactory.debug and is_cmdline_mode:
179 # Disable PIN protection with Werkzeug's debugger.
180 os.environ['WERKZEUG_DEBUG_PIN'] = 'off'
181
182 admin_app = create_foodtruck_app(es)
183 admin_app.wsgi_app = _PieCrustSiteOrAdminMiddleware(
184 app, admin_app.wsgi_app, admin_root_url)
185 app = admin_app
186
110 return app 187 return app
111 188
189
190 class _PieCrustSiteOrAdminMiddleware:
191 def __init__(self, main_app, admin_app, admin_root_url):
192 from werkzeug.exceptions import abort
193
194 def _err_resp(e, sr):
195 abort(404)
196
197 self.main_app = main_app
198 self.admin_app = admin_app or _err_resp
199 self.admin_root_url = admin_root_url
200
201 def __call__(self, environ, start_response):
202 path_info = environ.get('PATH_INFO', '')
203 if path_info.startswith(self.admin_root_url):
204 return self.admin_app(environ, start_response)
205 return self.main_app(environ, start_response)