comparison piecrust/commands/builtin/serving.py @ 219:d7a548ebcd58

serve: Add server sent events for showing pipeline errors in the debug window. The server can now run an endpoint that streams pipeline status, including errors or "fixed" statuses. As a result, I had to investigate using event-loop based server alternatives, before I figured out the correct flag to set in Werkzeug. Support for Gunicorn is therefore now possible, although disabled by default. I will come in handy though when proper support for CMS-mode is enabled.
author Ludovic Chabant <ludovic@chabant.com>
date Mon, 02 Feb 2015 08:34:44 -0800
parents f3aa511eef99
children 4f00bb99400e
comparison
equal deleted inserted replaced
218:10f24c62b05b 219:d7a548ebcd58
11 super(ServeCommand, self).__init__() 11 super(ServeCommand, self).__init__()
12 self.name = 'serve' 12 self.name = 'serve'
13 self.description = "Runs a local web server to serve your website." 13 self.description = "Runs a local web server to serve your website."
14 14
15 def setupParser(self, parser, app): 15 def setupParser(self, parser, app):
16 parser.add_argument('-p', '--port', 16 parser.add_argument(
17 '-p', '--port',
17 help="The port for the web server", 18 help="The port for the web server",
18 default=8080) 19 default=8080)
19 parser.add_argument('-a', '--address', 20 parser.add_argument(
21 '-a', '--address',
20 help="The host for the web server", 22 help="The host for the web server",
21 default='localhost') 23 default='localhost')
22 parser.add_argument('--use-reloader', 24 parser.add_argument(
25 '--use-reloader',
23 help="Restart the server when PieCrust code changes", 26 help="Restart the server when PieCrust code changes",
24 action='store_true') 27 action='store_true')
25 parser.add_argument('--use-debugger', 28 parser.add_argument(
29 '--use-debugger',
26 help="Show the debugger when an error occurs", 30 help="Show the debugger when an error occurs",
27 action='store_true') 31 action='store_true')
32 parser.add_argument(
33 '--wsgi',
34 help="The WSGI server implementation to use",
35 choices=['werkzeug', 'gunicorn'],
36 default='werkzeug')
28 37
29 def run(self, ctx): 38 def run(self, ctx):
39 host = ctx.args.address
40 port = int(ctx.args.port)
41 debug = ctx.args.debug or ctx.args.use_debugger
42
30 server = Server( 43 server = Server(
31 ctx.app.root_dir, 44 ctx.app.root_dir,
32 host=ctx.args.address, 45 debug=debug,
33 port=ctx.args.port,
34 debug=(ctx.args.debug or ctx.args.use_debugger),
35 use_reloader=ctx.args.use_reloader) 46 use_reloader=ctx.args.use_reloader)
36 server.run() 47 app = server.getWsgiApp()
37 48
49 if ctx.args.wsgi == 'werkzeug':
50 from werkzeug.serving import run_simple
51 run_simple(host, port, app,
52 threaded=True,
53 use_debugger=debug,
54 use_reloader=ctx.args.use_reloader)
55
56 elif ctx.args.wsgi == 'gunicorn':
57 from gunicorn.app.base import BaseApplication
58
59 class PieCrustGunicornApplication(BaseApplication):
60 def __init__(self, app, options):
61 self.app = app
62 self.options = options
63 super(PieCrustGunicornApplication, self).__init__()
64
65 def load_config(self):
66 for k, v in self.options.items():
67 if k in self.cfg.settings and v is not None:
68 self.cfg.set(k, v)
69
70 def load(self):
71 return self.app
72
73 options = {
74 'bind': '%s:%s' % (host, port),
75 'accesslog': '-',
76 'worker_class': 'gaiohttp',
77 'workers': 2,
78 'timeout': 999999}
79 if debug:
80 options['loglevel'] = 'debug'
81 if ctx.args.use_reloader:
82 options['reload'] = True
83 app_wrapper = PieCrustGunicornApplication(app, options)
84 app_wrapper.run()
85