|
| 1 | +""" Multicast DNS Service Discovery for Python, v0.14-wmcbrine |
| 2 | + Copyright 2003 Paul Scott-Murphy, 2014 William McBrine |
| 3 | +
|
| 4 | + This module provides a framework for the use of DNS Service Discovery |
| 5 | + using IP multicast. |
| 6 | +
|
| 7 | + This library is free software; you can redistribute it and/or |
| 8 | + modify it under the terms of the GNU Lesser General Public |
| 9 | + License as published by the Free Software Foundation; either |
| 10 | + version 2.1 of the License, or (at your option) any later version. |
| 11 | +
|
| 12 | + This library is distributed in the hope that it will be useful, |
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | + Lesser General Public License for more details. |
| 16 | +
|
| 17 | + You should have received a copy of the GNU Lesser General Public |
| 18 | + License along with this library; if not, write to the Free Software |
| 19 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 |
| 20 | + USA |
| 21 | +""" |
| 22 | + |
| 23 | +import asyncio |
| 24 | +import contextlib |
| 25 | +from typing import Optional, cast |
| 26 | + |
| 27 | + |
| 28 | +# Switch to asyncio.wait_for once https://bugs.python.org/issue39032 is fixed |
| 29 | +async def wait_condition_or_timeout(condition: asyncio.Condition, timeout: float) -> None: |
| 30 | + """Wait for a condition or timeout.""" |
| 31 | + loop = asyncio.get_event_loop() |
| 32 | + future = loop.create_future() |
| 33 | + |
| 34 | + def _handle_timeout() -> None: |
| 35 | + if not future.done(): |
| 36 | + future.set_result(None) |
| 37 | + |
| 38 | + timer_handle = loop.call_later(timeout, _handle_timeout) |
| 39 | + condition_wait = loop.create_task(condition.wait()) |
| 40 | + |
| 41 | + def _handle_wait_complete(_: asyncio.Task) -> None: |
| 42 | + if not future.done(): |
| 43 | + future.set_result(None) |
| 44 | + |
| 45 | + condition_wait.add_done_callback(_handle_wait_complete) |
| 46 | + |
| 47 | + try: |
| 48 | + await future |
| 49 | + finally: |
| 50 | + timer_handle.cancel() |
| 51 | + if not condition_wait.done(): |
| 52 | + condition_wait.cancel() |
| 53 | + with contextlib.suppress(asyncio.CancelledError): |
| 54 | + await condition_wait |
| 55 | + |
| 56 | + |
| 57 | +# Remove the call to _get_running_loop once we drop python 3.6 support |
| 58 | +def get_running_loop() -> Optional[asyncio.AbstractEventLoop]: |
| 59 | + """Check if an event loop is already running.""" |
| 60 | + with contextlib.suppress(RuntimeError): |
| 61 | + if hasattr(asyncio, "get_running_loop"): |
| 62 | + return cast( |
| 63 | + asyncio.AbstractEventLoop, |
| 64 | + asyncio.get_running_loop(), # type: ignore # pylint: disable=no-member # noqa |
| 65 | + ) |
| 66 | + return asyncio._get_running_loop() # pylint: disable=no-member,protected-access |
| 67 | + return None |
0 commit comments