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

Loading…
Cancel
Save