Exemple #1
0
 def _factory(self, streams=None):
     context = {"host": self.host, "shell": self, "immp": immp}
     console = aioconsole.AsynchronousConsole(locals=context,
                                              streams=streams)
     context["pprint"] = partial(self._pprint, console)
     log.debug("Accepted console connection")
     return console
Exemple #2
0
 def _factory(streams: Any = None) -> aioconsole.AsynchronousConsole:
     return aioconsole.AsynchronousConsole(
         locals=locals, streams=streams, loop=loop)
async def main_async(loop: asyncio.AbstractEventLoop, command: Commands = None) -> ExitCodes:
    """
    Async Main entrypoint

    Args:
        command (Commands):

    Returns:
         None
    """
    auth_manager: AuthenticationManager = None

    if command:
        # Take passed command and append actual cmdline
        cmdline_arguments = sys.argv[1:]
        cmdline_arguments.insert(0, command)
    else:
        cmdline_arguments = None

    args = parse_arguments(cmdline_arguments)
    handle_logging_setup(args)

    LOGGER.debug('Parsed arguments: {0}'.format(args))

    command = args.command
    LOGGER.debug('Chosen command: {0}'.format(command))

    if 'interactive' in args and args.interactive and \
         (args.address or args.liveid):
        LOGGER.error('Flag \'--interactive\' is incompatible with'
                     ' providing an IP address (--address) or LiveID (--liveid) explicitly')
        sys.exit(ExitCodes.ArgParsingError)
    elif args.liveid and args.address:
        LOGGER.warning('You passed --address AND --liveid: Will only use that specific'
                       'combination!')
    elif command == Commands.PowerOff and args.all and (args.liveid or args.address):
        LOGGER.error('Poweroff with --all flag + explicitly provided LiveID / IP address makes no sense')
        sys.exit(ExitCodes.ArgParsingError)
    elif command == Commands.PowerOff and args.interactive and args.all:
        LOGGER.error('Combining args --all and --interactive not supported')
        sys.exit(ExitCodes.ArgParsingError)

    print('Xbox SmartGlass main client started')

    if 'tokens' in args:
        """
        Do Xbox live authentication
        """
        LOGGER.debug('Command {0} supports authenticated connection'.format(command))
        print('Authenticating...')
        try:
            auth_manager = await do_authentication(args)
        except AuthenticationException:
            LOGGER.exception('Authentication failed!')
            LOGGER.error("Please re-run xbox-authenticate to get a fresh set")
            sys.exit(ExitCodes.AuthenticationError)
        print('Authentication done')

    if command == Commands.TUI:
        """
        Text user interface (powered by urwid)
        """
        # Removing stream handlers to not pollute TUI
        for h in [sh for sh in logging.root.handlers
                  if isinstance(sh, logging.StreamHandler)]:
            LOGGER.debug('Removing StreamHandler {0} from root logger'.format(h))
            logging.root.removeHandler(h)

        await tui.run_tui(loop, args.consoles, auth_manager)
        return ExitCodes.OK

    elif command == Commands.PowerOn:
        """
        Powering up console
        """
        if not args.liveid:
            LOGGER.error('No LiveID (--liveid) provided for power on!')
            sys.exit(ExitCodes.ArgParsingError)

        LOGGER.info('Sending poweron packet for LiveId: {0} to {1}'
                    .format(args.liveid,
                            'IP: ' + args.address if args.address else 'MULTICAST'))
        await Console.power_on(args.liveid, args.address, tries=10)
        sys.exit(0)

    """
    Discovery
    """
    discovered = await cli_discover_consoles(args)

    if command == Commands.Discover:
        """
        Simply print discovered consoles
        """
        print("Discovered %d consoles: " % len(discovered))
        for console in discovered:
            print("  %s" % console)
        sys.exit(ExitCodes.OK)

    elif command == Commands.PowerOff and args.all:
        """
        Early call for poweroff --all
        """
        """Powering off all discovered consoles"""
        for c in discovered:
            print('Powering off console {0}'.format(c))
            await c.power_off()
        sys.exit(ExitCodes.OK)

    """
    Choosing/filtering a console from the discovered ones
    """
    console = None
    if args.interactive:
        LOGGER.debug('Starting interactive console choice')
        console = choose_console_interactively(discovered)
    elif len(discovered) == 1:
        LOGGER.debug('Choosing sole console, no user interaction required')
        console = discovered[0]
    elif len(discovered) > 1:
        LOGGER.error(
            'More than one console was discovered and no exact'
            ' connection parameters were provided')

    if not console:
        LOGGER.error('Choosing a console failed!')
        sys.exit(ExitCodes.ConsoleChoice)

    LOGGER.info('Choosen target console: {0}'.format(console))

    LOGGER.debug('Setting console callbacks')
    console.on_device_status += \
        lambda x: LOGGER.info('Device status: {0}'.format(x))
    console.on_connection_state += \
        lambda x: LOGGER.info('Connection state: {0}'.format(x))
    console.on_pairing_state += \
        lambda x: LOGGER.info('Pairing state: {0}'.format(x))
    console.on_console_status += \
        lambda x: LOGGER.info('Console status: {0}'.format(x))
    console.on_timeout += \
        lambda x: LOGGER.error('Timeout occured!') or sys.exit(1)

    userhash = ''
    xsts_token = ''
    
    if auth_manager:
        userhash = auth_manager.xsts_token.userhash
        xsts_token = auth_manager.xsts_token.token

        LOGGER.debug('Authentication info:')
        LOGGER.debug('Userhash: {0}'.format(userhash))
        LOGGER.debug('XToken: {0}'.format(xsts_token))
    else:
        LOGGER.info('Running in anonymous mode')

    LOGGER.info('Attempting connection...')
    state = await console.connect(userhash, xsts_token)
    if state != ConnectionState.Connected:
        LOGGER.error('Connection failed! Console: {0}'.format(console))
        sys.exit(1)

    # FIXME: Waiting explicitly
    LOGGER.info('Connected to console: {0}'.format(console))
    LOGGER.debug('Waiting a second before proceeding...')
    await console.wait(1)

    if command == Commands.PowerOff:
        """
        Power off (single console)
        """
        print('Powering off console {0}'.format(console))
        await console.power_off()
        sys.exit(ExitCodes.OK)

    elif command == Commands.REPL or command == Commands.REPLServer:
        banner = 'You are connected to the console @ {0}\n'\
                 .format(console.address)
        banner += 'Type in \'console\' to acccess the object\n'
        banner += 'Type in \'exit()\' to quit the application'

        scope_vars = {'console': console}

        if command == Commands.REPL:
            LOGGER.info('Starting up local REPL console')
            console = aioconsole.AsynchronousConsole(locals=scope_vars, loop=loop)
            await console.interact(banner)

        else:
            startinfo = 'Starting up REPL server @ {0}:{1}'.format(args.bind, args.port)
            print(startinfo)
            LOGGER.info(startinfo)

            server = await aioconsole.start_interactive_server(
                host=args.bind, port=args.port, loop=loop)
            await server

    elif command == Commands.FalloutRelay:
        """
        Fallout 4 relay
        """
        print('Starting Fallout 4 relay service...')
        console.add_manager(TitleManager)
        console.title.on_connection_info += fallout4_relay.on_connection_info
        await console.start_title_channel(
            title_id=fallout4_relay.FALLOUT_TITLE_ID
        )
        print('Fallout 4 relay started')
    elif command == Commands.GamepadInput:
        """
        Gamepad input
        """
        print('Starting gamepad input handler...')
        console.add_manager(manager.InputManager)
        await gamepad_input.input_loop(console)
    elif command == Commands.TextInput:
        """
        Text input
        """
        print('Starting text input handler...')
        console.add_manager(manager.TextManager)
        console.text.on_systemtext_configuration += text_input.on_text_config
        console.text.on_systemtext_input += functools.partial(text_input.on_text_input, console)
        console.text.on_systemtext_done += text_input.on_text_done

        while True:
            try:
                await asyncio.sleep(1)
            except KeyboardInterrupt:
                print('Quitting text input handler')
                return ExitCodes.OK