diff --git a/ceopardy/__init__.py b/ceopardy/__init__.py index bdee236..f9c66d0 100644 --- a/ceopardy/__init__.py +++ b/ceopardy/__init__.py @@ -78,10 +78,13 @@ # flask-cors is optional; prod serves everything from the same origin. pass +# Use threading mode so the WSGI layer stays plain Werkzeug — its debugger +# and exception logging just work. If someone fronts this with gunicorn +# (see README), they pick the worker class at the CLI level (-k eventlet). socketio = SocketIO( app, cors_allowed_origins="*", - async_mode="eventlet", + async_mode="threading", ) db = SQLAlchemy(app) diff --git a/ceopardy/__main__.py b/ceopardy/__main__.py index eeb2f68..abce08f 100644 --- a/ceopardy/__main__.py +++ b/ceopardy/__main__.py @@ -35,7 +35,10 @@ def _cmd_serve(args): print(f" Host: http://localhost:{port}/host") if debug: print(" Debug: ON (verbose logging + auto-reload)") - socketio.run(app, host=host, port=port, debug=debug) + # Werkzeug is the only WSGI server we use here. Flask-SocketIO refuses it + # by default; we opt in because Ceopardy is meant for single-operator + # local use (binds to 127.0.0.1, see README on exposing via nginx). + socketio.run(app, host=host, port=port, debug=debug, allow_unsafe_werkzeug=True) def _walk(traversable, prefix=""): diff --git a/run.py b/run.py index 433f639..7a2d083 100644 --- a/run.py +++ b/run.py @@ -25,4 +25,12 @@ # debug=False. # WARNING: This app is not ready to be exposed on the network. # Game host interface would be exposed. - socketio.run(app, host="127.0.0.1", port=5000, debug=True) + # allow_unsafe_werkzeug: Flask-SocketIO refuses Werkzeug otherwise. See + # the same opt-in (and rationale) in ceopardy/__main__.py:_cmd_serve. + socketio.run( + app, + host="127.0.0.1", + port=5000, + debug=True, + allow_unsafe_werkzeug=True, + )