forked from platypush/platypush
Migrated from waitress to gunicorn.
`waitress`, unlike `gunicorn`, doesn't provide an easy way to plug into a WSGI socket that can be used for the websocket interface.
This commit is contained in:
parent
ca65db016e
commit
3aefc9607d
5 changed files with 48 additions and 37 deletions
|
@ -201,6 +201,7 @@ autodoc_default_options = {
|
||||||
}
|
}
|
||||||
|
|
||||||
autodoc_mock_imports = [
|
autodoc_mock_imports = [
|
||||||
|
'gunicorn',
|
||||||
'googlesamples.assistant.grpc.audio_helpers',
|
'googlesamples.assistant.grpc.audio_helpers',
|
||||||
'google.assistant.embedded',
|
'google.assistant.embedded',
|
||||||
'google.assistant.library',
|
'google.assistant.library',
|
||||||
|
|
|
@ -3,7 +3,7 @@ import pathlib
|
||||||
import secrets
|
import secrets
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process, cpu_count
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from websockets.exceptions import ConnectionClosed # type: ignore
|
from websockets.exceptions import ConnectionClosed # type: ignore
|
||||||
|
@ -11,10 +11,9 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from websockets import ConnectionClosed, serve as websocket_serve # type: ignore
|
from websockets import ConnectionClosed, serve as websocket_serve # type: ignore
|
||||||
|
|
||||||
import waitress
|
|
||||||
|
|
||||||
from platypush.backend import Backend
|
from platypush.backend import Backend
|
||||||
from platypush.backend.http.app import application
|
from platypush.backend.http.app import application
|
||||||
|
from platypush.backend.http.wsgi import WSGIApplicationWrapper
|
||||||
from platypush.bus.redis import RedisBus
|
from platypush.bus.redis import RedisBus
|
||||||
from platypush.config import Config
|
from platypush.config import Config
|
||||||
from platypush.context import get_or_create_event_loop
|
from platypush.context import get_or_create_event_loop
|
||||||
|
@ -174,7 +173,6 @@ class HttpBackend(Backend):
|
||||||
ssl_capath=None,
|
ssl_capath=None,
|
||||||
maps=None,
|
maps=None,
|
||||||
secret_key_file=None,
|
secret_key_file=None,
|
||||||
flask_args=None,
|
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -213,9 +211,6 @@ class HttpBackend(Backend):
|
||||||
:param secret_key_file: Path to the file containing the secret key that will be used by Flask
|
:param secret_key_file: Path to the file containing the secret key that will be used by Flask
|
||||||
(default: ``~/.local/share/platypush/flask.secret.key``).
|
(default: ``~/.local/share/platypush/flask.secret.key``).
|
||||||
:type secret_key_file: str
|
:type secret_key_file: str
|
||||||
|
|
||||||
:param flask_args: Extra key-value arguments that should be passed to the Flask service.
|
|
||||||
:type flask_args: dict[str, str]
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
@ -239,7 +234,6 @@ class HttpBackend(Backend):
|
||||||
self.resource_dirs = {}
|
self.resource_dirs = {}
|
||||||
|
|
||||||
self.active_websockets = set()
|
self.active_websockets = set()
|
||||||
self.flask_args = flask_args or {}
|
|
||||||
self.ssl_context = (
|
self.ssl_context = (
|
||||||
get_ssl_server_context(
|
get_ssl_server_context(
|
||||||
ssl_cert=ssl_cert,
|
ssl_cert=ssl_cert,
|
||||||
|
@ -420,24 +414,18 @@ class HttpBackend(Backend):
|
||||||
def _web_server_proc(self):
|
def _web_server_proc(self):
|
||||||
def proc():
|
def proc():
|
||||||
self.logger.info('Starting local web server on port %s', self.port)
|
self.logger.info('Starting local web server on port %s', self.port)
|
||||||
kwargs = {
|
|
||||||
'host': self.bind_address,
|
|
||||||
'port': self.port,
|
|
||||||
}
|
|
||||||
|
|
||||||
assert isinstance(
|
assert isinstance(
|
||||||
self.bus, RedisBus
|
self.bus, RedisBus
|
||||||
), 'The HTTP backend only works if backed by a Redis bus'
|
), 'The HTTP backend only works if backed by a Redis bus'
|
||||||
|
|
||||||
application.config['redis_queue'] = self.bus.redis_queue
|
application.config['redis_queue'] = self.bus.redis_queue
|
||||||
application.secret_key = self._get_secret_key()
|
application.secret_key = self._get_secret_key()
|
||||||
|
kwargs = {
|
||||||
|
'bind': f'{self.bind_address}:{self.port}',
|
||||||
|
'workers': (cpu_count() * 2) + 1,
|
||||||
|
}
|
||||||
|
|
||||||
if self.ssl_context:
|
WSGIApplicationWrapper(f'{__package__}.app:application', kwargs).run()
|
||||||
kwargs['ssl_context'] = self.ssl_context
|
|
||||||
if self.flask_args:
|
|
||||||
kwargs.update(self.flask_args)
|
|
||||||
|
|
||||||
waitress.serve(application, **kwargs)
|
|
||||||
|
|
||||||
return proc
|
return proc
|
||||||
|
|
||||||
|
|
21
platypush/backend/http/wsgi/__init__.py
Normal file
21
platypush/backend/http/wsgi/__init__.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from gunicorn.app.wsgiapp import WSGIApplication
|
||||||
|
|
||||||
|
|
||||||
|
class WSGIApplicationWrapper(WSGIApplication):
|
||||||
|
"""
|
||||||
|
Wrapper for the Flask application into a WSGI application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, app_uri, options=None):
|
||||||
|
self.options = options or {}
|
||||||
|
self.app_uri = app_uri
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def load_config(self):
|
||||||
|
config = {
|
||||||
|
key: value
|
||||||
|
for key, value in self.options.items()
|
||||||
|
if key in self.cfg.settings and value is not None # type: ignore
|
||||||
|
}
|
||||||
|
for key, value in config.items():
|
||||||
|
self.cfg.set(key.lower(), value) # type: ignore
|
|
@ -2,24 +2,25 @@
|
||||||
# Platypush common requirements
|
# Platypush common requirements
|
||||||
###
|
###
|
||||||
|
|
||||||
pyyaml
|
|
||||||
marshmallow
|
|
||||||
marshmallow_dataclass
|
|
||||||
python-prctl
|
|
||||||
flask
|
|
||||||
websockets
|
|
||||||
redis
|
|
||||||
python-dateutil
|
|
||||||
tz
|
|
||||||
frozendict
|
|
||||||
requests
|
|
||||||
sqlalchemy
|
|
||||||
alembic
|
alembic
|
||||||
bcrypt
|
bcrypt
|
||||||
rsa
|
|
||||||
zeroconf>=0.27.0
|
|
||||||
paho-mqtt
|
|
||||||
websocket-client
|
|
||||||
croniter
|
croniter
|
||||||
|
flask
|
||||||
|
frozendict
|
||||||
|
gunicorn
|
||||||
|
marshmallow
|
||||||
|
marshmallow_dataclass
|
||||||
|
paho-mqtt
|
||||||
|
python-dateutil
|
||||||
python-magic
|
python-magic
|
||||||
waitress
|
python-prctl
|
||||||
|
pyyaml
|
||||||
|
redis
|
||||||
|
requests
|
||||||
|
rsa
|
||||||
|
simple_websocket
|
||||||
|
sqlalchemy
|
||||||
|
tz
|
||||||
|
websocket-client
|
||||||
|
wsproto
|
||||||
|
zeroconf>=0.27.0
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -65,6 +65,7 @@ setup(
|
||||||
'croniter',
|
'croniter',
|
||||||
'flask',
|
'flask',
|
||||||
'frozendict',
|
'frozendict',
|
||||||
|
'gunicorn',
|
||||||
'marshmallow',
|
'marshmallow',
|
||||||
'marshmallow_dataclass',
|
'marshmallow_dataclass',
|
||||||
'python-dateutil',
|
'python-dateutil',
|
||||||
|
@ -75,7 +76,6 @@ setup(
|
||||||
'rsa',
|
'rsa',
|
||||||
'sqlalchemy',
|
'sqlalchemy',
|
||||||
'tz',
|
'tz',
|
||||||
'waitress',
|
|
||||||
'websocket-client',
|
'websocket-client',
|
||||||
'websockets',
|
'websockets',
|
||||||
'wheel',
|
'wheel',
|
||||||
|
|
Loading…
Reference in a new issue