1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 17:06:17 +00:00
supysonic/supysonic/server/__init__.py
Alban Féron 36efefcda6
Fix supysonic-server with gunicorn creating the application too early
Was causing SQL connection issues when using forked workers

Closes #241
2023-01-16 22:10:39 +01:00

126 lines
3.3 KiB
Python

# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2021-2023 Alban 'spl0k' Féron
#
# Distributed under terms of the GNU AGPLv3 license.
import importlib
import os
import os.path
from click import command, option, Option
from click.exceptions import UsageError, ClickException
from click.types import Choice
_servers = [
e.name[:-3]
for e in os.scandir(os.path.dirname(__file__))
if not e.name.startswith("_") and e.name.endswith(".py")
]
class MutuallyExclusiveOption(Option):
def __init__(self, *args, **kwargs):
self.mutually_exclusive = set(kwargs.pop("mutually_exclusive", []))
help = kwargs.get("help", "")
if self.mutually_exclusive:
ex_str = ", ".join(self.mutually_exclusive)
kwargs[
"help"
] = "{} NOTE: This argument is mutually exclusive with arguments: [{}].".format(
help, ex_str
)
super().__init__(*args, **kwargs)
def handle_parse_result(self, ctx, opts, args):
if self.mutually_exclusive.intersection(opts) and self.name in opts:
raise UsageError(
"Illegal usage: `{}` is mutually exclusive with arguments `{}`.".format(
self.name, ", ".join(self.mutually_exclusive)
)
)
return super().handle_parse_result(ctx, opts, args)
def get_server(name):
return importlib.import_module("." + name, __package__).server
def find_first_available_server():
for module in _servers:
try:
return get_server(module)
except ImportError:
pass
return None
@command()
@option(
"-S",
"--server",
type=Choice(_servers),
help="Specify which WSGI server to use. Pick the first available if none is set",
)
@option(
"-h",
"--host",
default="0.0.0.0",
show_default=True,
help="Hostname or IP address on which to listen",
cls=MutuallyExclusiveOption,
mutually_exclusive=("socket",),
)
@option(
"-p",
"--port",
default=5722,
show_default=True,
help="TCP port on which to listen",
cls=MutuallyExclusiveOption,
mutually_exclusive=("socket",),
)
@option(
"-s",
"--socket",
help="Unix socket on which to bind to, Can't be used with --host and --port",
cls=MutuallyExclusiveOption,
mutually_exclusive=("host", "port"),
)
@option(
"--processes",
type=int,
help="Number of processes to spawn. May not be supported by all servers",
)
@option(
"--threads",
type=int,
help="Number of threads used to process application logic. May not be supported by all servers",
)
def main(server, host, port, socket, processes, threads):
"""Starts the Supysonic web server"""
if server is None:
server = find_first_available_server()
if server is None:
raise ClickException(
f"Couldn't load any server, please install one of {_servers}"
)
else:
try:
server = get_server(server)
except ImportError:
raise ClickException(f"Couldn't load {server}, please install it first")
if socket is not None:
host = None
port = None
server(
host=host, port=port, socket=socket, processes=processes, threads=threads
).run()