|
|
|
#!/usr/bin/env python3
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import yaml
|
|
|
|
import argparse
|
|
|
|
from typing import Any
|
|
|
|
from syncplay import ep_server
|
|
|
|
|
|
|
|
WorkDir = '/data/'
|
|
|
|
CertDir = '/certs/'
|
|
|
|
ConfigFile = 'config.yml'
|
|
|
|
|
|
|
|
|
|
|
|
def debug(msg: str) -> None:
|
|
|
|
""" Print out debug information. """
|
|
|
|
if 'DEBUG' in os.environ and os.environ['DEBUG'] in ['ON', 'TRUE']:
|
|
|
|
print(f'\033[90m{msg}\033[0m', file=sys.stderr)
|
|
|
|
|
|
|
|
|
|
|
|
def temp_file(file: str, content: str) -> str:
|
|
|
|
""" Create and save content to temporary files. """
|
|
|
|
file = os.path.join('/tmp/', file)
|
|
|
|
with open(file, 'w') as fp:
|
|
|
|
fp.write(content)
|
|
|
|
return file
|
|
|
|
|
|
|
|
|
|
|
|
def load_args() -> dict[str, Any]:
|
|
|
|
""" Loading arguments from the command line. """
|
|
|
|
parser = argparse.ArgumentParser(description='Syncplay Docker Bootstrap')
|
|
|
|
parser.add_argument('-p', '--port', type=int, help='listen port of syncplay server')
|
|
|
|
parser.add_argument('--password', type=str, help='authentication of syncplay server')
|
|
|
|
parser.add_argument('--motd', type=str, help='welcome text after the user enters the room')
|
|
|
|
parser.add_argument('--salt', type=str, help='string used to secure passwords')
|
|
|
|
parser.add_argument('--random-salt', action='store_true', help='use a randomly generated salt value')
|
|
|
|
parser.add_argument('--isolate-rooms', action='store_true', help='room isolation enabled')
|
|
|
|
parser.add_argument('--disable-chat', action='store_true', help='disables the chat feature')
|
|
|
|
parser.add_argument('--disable-ready', action='store_true', help='disables the readiness indicator feature')
|
|
|
|
parser.add_argument('--enable-stats', action='store_true', help='enable syncplay server statistics')
|
|
|
|
parser.add_argument('--enable-tls', action='store_true', help='enable tls support of syncplay server')
|
|
|
|
parser.add_argument('--persistent', action='store_true', help='enables room persistence')
|
|
|
|
parser.add_argument('--max-username', type=int, help='maximum length of usernames')
|
|
|
|
parser.add_argument('--max-chat-message', type=int, help='maximum length of chat messages')
|
|
|
|
parser.add_argument('--permanent-rooms', type=str, nargs='*', help='permanent rooms of syncplay server')
|
|
|
|
args = parser.parse_args()
|
|
|
|
debug(f'Command line arguments -> {args}')
|
|
|
|
return {k.replace('_', '-'): v for k, v in vars(args).items()}
|
|
|
|
|
|
|
|
|
|
|
|
def load_config(args: dict[str, Any], file: str) -> dict[str, Any]:
|
|
|
|
""" Complete uninitialized arguments from configure file. """
|
|
|
|
if not os.path.exists(file):
|
|
|
|
return args
|
|
|
|
config = yaml.safe_load(open(file).read())
|
|
|
|
options = [
|
|
|
|
'port', 'password', 'motd', 'salt', 'random-salt',
|
|
|
|
'isolate-rooms', 'disable-chat', 'disable-ready',
|
|
|
|
'enable-stats', 'enable-tls', 'persistent',
|
|
|
|
'max-username', 'max-chat-message', 'permanent-rooms',
|
|
|
|
]
|
|
|
|
override = {x: config[x] for x in options if not args[x] and x in config}
|
|
|
|
debug(f'Configure file override -> {override}')
|
|
|
|
return args | override
|
|
|
|
|
|
|
|
|
|
|
|
def build_args(opts: dict):
|
|
|
|
""" Construct the startup arguments for syncplay server. """
|
|
|
|
args = ['--port', str(opts.get('port', 8999))]
|
|
|
|
if 'password' in opts:
|
|
|
|
args += ['--password', opts['password']]
|
|
|
|
if 'motd' in opts:
|
|
|
|
args += ['--motd-file', temp_file('motd.data', opts['motd'])]
|
|
|
|
|
|
|
|
salt = opts.get('salt', None if 'random-salt' in opts else '')
|
|
|
|
if salt is not None:
|
|
|
|
args += ['--salt', salt] # using random salt without this option
|
|
|
|
for opt in ['isolate-rooms', 'disable-chat', 'disable-ready']:
|
|
|
|
if opt in opts:
|
|
|
|
args.append(f'--{opt}')
|
|
|
|
|
|
|
|
if 'enable-stats' in opts:
|
|
|
|
args += ['--stats-db-file', os.path.join(WorkDir, 'stats.db')]
|
|
|
|
if 'enable-tls' in opts:
|
|
|
|
args += ['--tls', CertDir]
|
|
|
|
if 'persistent' in opts:
|
|
|
|
args += ['--rooms-db-file', os.path.join(WorkDir, 'rooms.db')]
|
|
|
|
|
|
|
|
if 'max-username' in opts:
|
|
|
|
args += ['--max-username-length', str(opts['max-username'])]
|
|
|
|
if 'max-chat-message' in opts:
|
|
|
|
args += ['--max-chat-message-length', str(opts['max-chat-message'])]
|
|
|
|
if 'permanent-rooms' in opts:
|
|
|
|
rooms = '\n'.join(opts['permanent-rooms'])
|
|
|
|
args += ['--permanent-rooms-file', temp_file('rooms.list', rooms)]
|
|
|
|
return args
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
origin_args = load_config(load_args(), os.path.join(WorkDir, ConfigFile))
|
|
|
|
origin_args = {k: v for k, v in origin_args.items() if v is not None and v is not False} # remove invalid items
|
|
|
|
debug(f'Parsed arguments -> {origin_args}')
|
|
|
|
syncplay_args = build_args(origin_args)
|
|
|
|
debug(f'Syncplay startup arguments -> {syncplay_args}')
|
|
|
|
sys.argv = ['syncplay'] + syncplay_args
|
|
|
|
sys.exit(ep_server.main())
|