import asyncio
import socket
from collections.abc import Iterable, AsyncIterator
from typing import NamedTuple, Optional


class Result(NamedTuple):  # <1>
    domain: str
    found: bool


OptionalLoop = Optional[asyncio.AbstractEventLoop]  # <2>


async def probe(domain: str, loop: OptionalLoop = None) -> Result:  # <3>
    if loop is None:
        loop = asyncio.get_running_loop()
    try:
        await loop.getaddrinfo(domain, None)
    except socket.gaierror:
        return Result(domain, False)
    return Result(domain, True)


async def multi_probe(
        domains: Iterable[str]) -> AsyncIterator[Result]:  # <4>
    loop = asyncio.get_running_loop()
    coros = [probe(domain, loop) for domain in domains]  # <5>
    for coro in asyncio.as_completed(coros):  # <6>
        result = await coro  # <7>
        yield result  # <8>
