Browse Source

update: several improvements

dev
Dnomd343 1 month ago
parent
commit
d21f838e98
  1. 70
      src/boot.py

70
src/boot.py

@ -4,8 +4,8 @@
"""
Syncplay Bootstrap using to convert redesigned parameter fields into arguments
that are non-intrusive to Syncplay Server. It supports command line arguments,
environment variables, JSON / YAML / TOML configuration input, and process them
according to priority.
environment variables, JSON / YAML / TOML configuration input, and processes
them according to priority.
The command line parameters of Syncplay server are not convenient for container
startup, especially for scenarios that require specified file, which can easily
@ -91,12 +91,12 @@ DESC = {
'listen_ipv6': ('ADDR', 'listening address of ipv6'),
}
ARG_OPTS: dict[str, dict] = {} # for loading cli arguments
ENV_OPTS: dict[str, type] = {} # for loading env variables
CFG_OPTS: dict[str, tuple[type, bool]] = {} # for loading configure file
ARG_OPTS: dict[str, dict[str, type | str]] = {} # for loading command line arguments
def debug_msg(prefix: str, message: Any) -> None:
""" Output debug message. """
@ -104,7 +104,7 @@ def debug_msg(prefix: str, message: Any) -> None:
print(f'\033[33m{prefix}\033[0m -> \033[90m{message}\033[0m', file=sys.stderr)
def build_opts() -> None:
def init_opts() -> None:
""" Build syncplay formatting options. """
for name, field in SyncplayOptions.__annotations__.items():
field_t, is_list = field.__args__[0], False
@ -148,10 +148,11 @@ def load_from_env() -> SyncplayOptions:
def load_from_args() -> SyncplayOptions:
""" Load syncplay options from command line arguments. """
def __build_args(name: str) -> list[str]:
match name := name.replace('_', '-'):
case 'port': return ['-p', f'--{name}']
case _: return [f'--{name}']
def __build_args(opt: str) -> list[str]:
match opt := opt.replace('_', '-'):
case 'port': return ['-p', f'--{opt}']
case 'motd': return ['-m', f'--{opt}']
case _: return [f'--{opt}']
parser = argparse.ArgumentParser(description='Syncplay Docker Bootstrap')
for name, opts in ARG_OPTS.items():
@ -159,7 +160,13 @@ def load_from_args() -> SyncplayOptions:
args = parser.parse_args(sys.argv[1:])
debug_msg('Command line arguments', args)
return {x: y for x, y in vars(args).items() if not (y is None or y is False)}
options: SyncplayOptions = {}
for arg, value in vars(args).items():
if value is None or value is False:
continue
options[arg] = value
return options
def load_from_config(path: str) -> SyncplayOptions:
@ -174,7 +181,7 @@ def load_from_config(path: str) -> SyncplayOptions:
elif path.endswith('.toml'):
return tomllib.loads(content)
else:
return yaml.safe_load(content) # assume yaml format
return yaml.safe_load(content) # assume YAML format
assert type(config := __load_file()) is dict
debug_msg('Configure content', config)
@ -185,14 +192,32 @@ def load_from_config(path: str) -> SyncplayOptions:
if value is not None:
if is_list:
assert type(value) is list
assert all(type(x) == field_t for x in value)
assert all(type(x) is field_t for x in value)
else:
assert type(value) == field_t
assert type(value) is field_t
options[key] = value
return options
def convert(opts: SyncplayOptions) -> list[str]:
def load_opts() -> SyncplayOptions:
""" Combine syncplay options from multiple source. """
env_opts = load_from_env()
cli_opts = load_from_args()
cfg_opts = load_from_config((env_opts | cli_opts).get('config', 'config.yml'))
debug_msg('Environment options', env_opts)
debug_msg('Command line options', cli_opts)
debug_msg('Configure file options', cfg_opts)
final_opts: SyncplayOptions = {}
for opt, value in (env_opts | cfg_opts | cli_opts).items():
if type(value) is not bool or value:
final_opts[opt] = value
debug_msg('Bootstrap final options', final_opts)
return final_opts
def sp_convert(opts: SyncplayOptions) -> list[str]:
""" Construct the startup arguments for syncplay server. """
def __temp_file(file: str, content: str) -> str:
@ -234,7 +259,7 @@ def convert(opts: SyncplayOptions) -> list[str]:
rooms = '\n'.join(opts['permanent_rooms'])
args += ['--permanent-rooms-file', __temp_file('rooms.list', rooms)]
if 'listen_ipv4' in opts and 'listen_ipv6' in opts:
if 'listen_ipv4' in opts and 'listen_ipv6' in opts: # dual stack
args += ['--interface-ipv4', opts['listen_ipv4']]
args += ['--interface-ipv6', opts['listen_ipv6']]
elif 'listen_ipv4' in opts:
@ -245,19 +270,8 @@ def convert(opts: SyncplayOptions) -> list[str]:
if __name__ == '__main__':
build_opts()
env_opts = load_from_env()
cli_opts = load_from_args()
cfg_opts = load_from_config((env_opts | cli_opts).get('config', 'config.yml'))
debug_msg('Environment options', env_opts)
debug_msg('Command line options', cli_opts)
debug_msg('Configure file options', cfg_opts)
final_opts = {x: y for x, y in (env_opts | cfg_opts | cli_opts).items() if y != False}
debug_msg('Bootstrap final options', final_opts)
sys.argv = ['syncplay'] + convert(final_opts)
init_opts()
sys.argv = ['syncplay'] + sp_convert(load_opts())
debug_msg('Syncplay startup arguments', sys.argv)
from syncplay import ep_server

Loading…
Cancel
Save