import clypi from aioq3rcon import Client, IncorrectPasswordError from clypi import Command, Spinner, arg from clypi import parsers as cp from typing_extensions import override from . import config, console from .__about__ import __version__ from .subcommands import Status, Subcommands class Q3rconCli(Command): subcommand: Subcommands | None = None host: str = arg( 'localhost', short='h', help='The host to connect to', env='Q3RCON_CLI_HOST', group='Connection', parser=cp.Str(min=1), ) port: int = arg( 28960, short='p', help='The port to connect to', env='Q3RCON_CLI_PORT', group='Connection', parser=cp.Int(min=1, max=65535), ) password: str = arg( '', short='P', help='The password for authentication', env='Q3RCON_CLI_PASSWORD', group='Connection', parser=cp.Str(min=8), ) interactive: bool = arg( False, short='i', help='Whether to start in interactive mode (defaults to false)', ) version: bool = arg( False, short='v', help='Show the version and exit', ) @override async def pre_run_hook(self): if self.subcommand is not None and self.interactive: console.err.print( 'Cannot use subcommands in interactive mode.', style='yellow', ) self.print_help() raise SystemExit(1) if self.subcommand: ( self.subcommand.timeout, self.subcommand.fragment_read_timeout, self.subcommand.interpret, ) = config.get(self.subcommand.prog().split()[0].lower()) @override async def run(self): if self.version: print(f'q3rcon-cli version: {clypi.style(__version__, fg="green")}') return if self.interactive: await self.run_interactive() return if self.subcommand is None: await Status(self.host, self.port, self.password).run() return self.print_help() async def run_interactive(self): print( clypi.style('Entering interactive mode. Type', fg='blue'), clypi.style("'Q'", fg='yellow'), clypi.style('to quit.', fg='blue'), ) while command := input(clypi.style('cmd: ', fg='green')): if command.lower() == 'q': break timeout, fragment_read_timeout, interpret = config.get( command.split()[0].lower() ) async with Spinner(f"Sending command: '{command}'", suffix='...'): async with Client( self.host, self.port, self.password, timeout=timeout, fragment_read_timeout=fragment_read_timeout, ) as client: try: response = await client.send_command( command, interpret=interpret ) except TimeoutError: console.err.print( f"Timeout waiting for response for command: '{command}'" ) console.out.print_response(response) def main(): try: cli = Q3rconCli().parse() cli.start() except IncorrectPasswordError: console.err.print('Incorrect password provided.') except TimeoutError: console.err.print( f"Timeout waiting for response for command: '{type(cli.subcommand).__name__.lower()}'" )