Example #1
0
    async def connect(self) -> None:
        """Initiate connection to device."""
        if not self._protocol_handlers:
            raise exceptions.NoServiceError("no service to connect to")

        # TODO: Parallelize with asyncio.gather? Needs to handle cancling
        # of ongoing tasks in case of error.
        for protocol_connect, _, _ in self._protocol_handlers.values():
            await protocol_connect()
Example #2
0
    def main_service(self, protocol: Protocol = None) -> BaseService:
        """Return suggested service used to establish connection."""
        protocols = ([protocol] if protocol is not None else
                     [Protocol.MRP, Protocol.DMAP])

        for prot in protocols:
            service = self._services.get(prot)
            if service is not None:
                return service

        raise exceptions.NoServiceError("no service to connect to")
Example #3
0
    def main_service(self, protocol=None):
        """Return suggested service used to establish connection."""
        protocols = [protocol] if protocol is not None else \
            [Protocol.MRP, Protocol.DMAP]

        for prot in protocols:
            service = self.get_service(prot)
            if service is not None:
                return service

        raise exceptions.NoServiceError(
            'no service to connect to')
Example #4
0
async def connect(
    config: interface.BaseConfig,
    loop: asyncio.AbstractEventLoop,
    protocol: Protocol = None,
    session: aiohttp.ClientSession = None,
) -> interface.AppleTV:
    """Connect to a device based on a configuration."""
    if not config.services:
        raise exceptions.NoServiceError("no service to connect to")

    if config.identifier is None:
        raise exceptions.DeviceIdMissingError("no device identifier")

    config_copy = deepcopy(config)
    session_manager = await http.create_session(session)
    core_dispatcher = CoreStateDispatcher()
    atv = FacadeAppleTV(config_copy, session_manager, core_dispatcher)

    try:
        for proto, proto_methods in PROTOCOLS.items():
            service = config_copy.get_service(proto)
            if service is None or not service.enabled:
                continue
            if not service.enabled:
                _LOGGER.debug("Ignore %s as it is disabled", proto.name)
                continue

            # Lock protocol argument so protocol does not have to deal
            # with that
            takeover_method = partial(atv.takeover, proto)

            # Core provides core access with a protocol specific twist
            core = Core(
                loop,
                config_copy,
                service,
                atv,
                session_manager,
                takeover_method,
                ProtocolStateDispatcher(proto, core_dispatcher),
            )

            for setup_data in proto_methods.setup(core):
                atv.add_protocol(setup_data)

        await atv.connect()
    except Exception:
        await session_manager.close()
        raise
    else:
        return atv
Example #5
0
    async def connect(self) -> None:
        """Initiate connection to device."""
        # No protocols to setup + no protocols previously set up => no service
        if self._protocols_to_setup.empty() and not self._protocol_handlers:
            raise exceptions.NoServiceError("no service to connect to")

        # Protocols set up already => we have already connected
        if self._protocol_handlers:
            raise exceptions.InvalidStateError("already connected")

        devinfo: Dict[str, Any] = {}

        # Set up protocols, ignoring duplicates
        while not self._protocols_to_setup.empty():
            setup_data = self._protocols_to_setup.get()

            if setup_data.protocol in self._protocol_handlers:
                _LOGGER.debug("Protocol %s already set up, ignoring",
                              setup_data.protocol)
                continue

            _LOGGER.debug("Connecting to protocol: %s", setup_data.protocol)
            if await setup_data.connect():
                _LOGGER.debug("Connected to protocol: %s", setup_data.protocol)
                self._protocol_handlers[setup_data.protocol] = setup_data

                for iface, instance in setup_data.interfaces.items():
                    self._interfaces[iface].register(instance,
                                                     setup_data.protocol)

                self._features.add_mapping(setup_data.protocol,
                                           setup_data.features)
                dict_merge(devinfo, setup_data.device_info())

        self._device_info = interface.DeviceInfo(devinfo)

        # Forward power events in case an interface exists for it
        try:
            power = cast(interface.Power,
                         self._interfaces[interface.Power].main_instance)
            power.listener = self._interfaces[interface.Power]
        except exceptions.NotSupportedError:
            _LOGGER.debug("Power management not supported by any protocols")
Example #6
0
async def pair(config: interface.BaseConfig,
               protocol: Protocol,
               loop: asyncio.AbstractEventLoop,
               session: aiohttp.ClientSession = None,
               **kwargs):
    """Pair a protocol for an Apple TV."""
    service = config.get_service(protocol)
    if not service:
        raise exceptions.NoServiceError(f"no service available for {protocol}")

    proto_methods = PROTOCOLS.get(protocol)
    if not proto_methods:
        raise RuntimeError(f"missing implementation for {protocol}")

    session = await http.create_session(session)
    try:
        return proto_methods.pair(config, service, session, loop, **kwargs)
    except Exception:
        await session.close()
        raise
Example #7
0
async def pair(config, protocol, loop, session=None, **kwargs):
    """Pair with an Apple TV."""
    service = config.get_service(protocol)
    if not service:
        raise exceptions.NoServiceError('no service available for protocol ' +
                                        str(protocol))

    protocol_handlers = {
        Protocol.DMAP: DmapPairingHandler,
        Protocol.MRP: MrpPairingHandler,
        Protocol.AirPlay: AirPlayPairingHandler,
    }

    handler = protocol_handlers.get(protocol, None)
    if handler is None:
        raise exceptions.UnsupportedProtocolError(str(protocol))

    if session is None:
        session = await net.create_session(loop)

    return handler(config, session, loop, **kwargs)
Example #8
0
async def pair(config: conf.AppleTV,
               protocol: Protocol,
               loop: asyncio.AbstractEventLoop,
               session: aiohttp.ClientSession = None,
               **kwargs):
    """Pair a protocol for an Apple TV."""
    service = config.get_service(protocol)
    if not service:
        raise exceptions.NoServiceError(f"no service available for {protocol}")

    handler = {
        Protocol.DMAP: DmapPairingHandler,
        Protocol.MRP: MrpPairingHandler,
        Protocol.AirPlay: AirPlayPairingHandler,
        Protocol.Companion: CompanionPairingHandler,
    }.get(protocol)

    if handler is None:
        raise RuntimeError(f"missing implementation for {protocol}")

    return handler(config, await http.create_session(session), loop, **kwargs)
Example #9
0
async def pair(config: conf.AppleTV,
               protocol: Protocol,
               loop: asyncio.AbstractEventLoop,
               session: aiohttp.ClientSession = None,
               **kwargs):
    """Pair a protocol for an Apple TV."""
    service = config.get_service(protocol)
    if not service:
        raise exceptions.NoServiceError("no service available for protocol " +
                                        str(protocol))

    handler = {
        Protocol.DMAP: DmapPairingHandler,
        Protocol.MRP: MrpPairingHandler,
        Protocol.AirPlay: AirPlayPairingHandler,
    }.get(protocol)

    if handler is None:
        raise exceptions.UnsupportedProtocolError(str(protocol))

    return handler(config, await net.create_session(session), loop, **kwargs)
Example #10
0
async def connect(
    config: conf.AppleTV,
    loop: asyncio.AbstractEventLoop,
    protocol: Protocol = None,
    session: aiohttp.ClientSession = None,
) -> interface.AppleTV:
    """Connect to a device based on a configuration."""
    if not config.services:
        raise exceptions.NoServiceError("no service to connect to")

    if config.identifier is None:
        raise exceptions.DeviceIdMissingError("no device identifier")

    session_manager = await http.create_session(session)
    atv = FacadeAppleTV(config, session_manager)

    for service in config.services:
        setup_method = _PROTOCOL_IMPLEMENTATIONS.get(service.protocol)
        if not setup_method:
            raise RuntimeError(
                "missing implementation for protocol {service.protocol}")

        setup_data = setup_method(loop, config, atv.interfaces, atv,
                                  session_manager)
        if setup_data:
            _LOGGER.debug("Adding protocol %s", service.protocol)
            atv.add_protocol(service.protocol, setup_data)
        else:
            _LOGGER.debug("Not adding protocol: %s", service.protocol)
    try:
        await atv.connect()
    except Exception:
        await session_manager.close()
        raise
    else:
        return atv