2121"""
2222import asyncio
2323import contextlib
24- import queue
25- import threading
2624from types import TracebackType # noqa # used in type hints
2725from typing import Awaitable , Callable , Dict , List , Optional , Type , Union
2826
2927from ._core import NotifyListener , Zeroconf
30- from ._dns import DNSOutgoing
3128from ._exceptions import NonUniqueNameException
3229from ._services import ServiceInfo , _ServiceBrowserBase , instance_name_from_service_info
3330from ._utils .aio import wait_condition_or_timeout
3633from .const import _BROWSER_TIME , _CHECK_TIME , _LISTENER_TIME , _MDNS_PORT , _REGISTER_TIME , _UNREGISTER_TIME
3734
3835
39- def _get_best_available_queue () -> queue .Queue :
40- """Create the best available queue type."""
41- if hasattr (queue , "SimpleQueue" ):
42- return queue .SimpleQueue () # type: ignore # pylint: disable=all
43- return queue .Queue ()
44-
45-
46- class _AsyncSender (threading .Thread ):
47- """A thread to handle sending DNSOutgoing for asyncio."""
48-
49- def __init__ (self , zc : 'Zeroconf' ):
50- """Create the sender thread."""
51- super ().__init__ ()
52- self .zc = zc
53- self .queue = _get_best_available_queue ()
54- self .start ()
55- self .name = "AsyncZeroconfSender"
56-
57- def send (self , out : DNSOutgoing , addr : Optional [str ] = None , port : int = _MDNS_PORT ) -> None :
58- """Queue a send to be processed by the thread."""
59- self .queue .put ((out , addr , port ))
60-
61- def close (self ) -> None :
62- """Close the instance."""
63- self .queue .put (None )
64- self .join ()
65-
66- def run (self ) -> None :
67- """Runner that processes sends FIFO."""
68- while True :
69- event = self .queue .get ()
70- if event is None :
71- return
72- self .zc .send (* event )
73-
74-
7536class AsyncNotifyListener (NotifyListener ):
7637 """A NotifyListener that async code can use to wait for events."""
7738
@@ -115,6 +76,7 @@ async def async_request(self, aiozc: 'AsyncZeroconf', timeout: float) -> bool:
11576 delay = _LISTENER_TIME
11677 next_ = now
11778 last = now + timeout
79+ await aiozc .zeroconf .async_wait_for_start ()
11880 try :
11981 aiozc .zeroconf .add_listener (self , None )
12082 while not self ._is_complete :
@@ -124,7 +86,7 @@ async def async_request(self, aiozc: 'AsyncZeroconf', timeout: float) -> bool:
12486 out = self .generate_request_query (aiozc .zeroconf , now )
12587 if not out .questions :
12688 return self .load_from_cache (aiozc .zeroconf )
127- aiozc .sender . send (out )
89+ aiozc .zeroconf . async_send (out )
12890 next_ = now + delay
12991 delay *= 2
13092
@@ -180,7 +142,7 @@ async def async_run(self) -> None:
180142
181143 out = self .generate_ready_queries ()
182144 if out :
183- self .aiozc .sender . send (out , addr = self .addr , port = self .port )
145+ self .aiozc .zeroconf . async_send (out , addr = self .addr , port = self .port )
184146
185147 if not self ._handlers_to_call :
186148 continue
@@ -236,15 +198,14 @@ def __init__(
236198 self .async_notify = AsyncNotifyListener (self )
237199 self .zeroconf .add_notify_listener (self .async_notify )
238200 self .async_browsers : Dict [AsyncServiceListener , AsyncServiceBrowser ] = {}
239- self .sender = _AsyncSender (self .zeroconf )
240201 self .condition = asyncio .Condition ()
241202
242203 async def _async_broadcast_service (self , info : ServiceInfo , interval : int , ttl : Optional [int ]) -> None :
243204 """Send a broadcasts to announce a service at intervals."""
244205 for i in range (3 ):
245206 if i != 0 :
246207 await asyncio .sleep (millis_to_seconds (interval ))
247- self .sender . send (self .zeroconf .generate_service_broadcast (info , ttl ))
208+ self .zeroconf . async_send (self .zeroconf .generate_service_broadcast (info , ttl ))
248209
249210 async def async_register_service (
250211 self ,
@@ -261,6 +222,7 @@ async def async_register_service(
261222 The service will be broadcast in a task. This task is returned
262223 and therefore can be awaited if necessary.
263224 """
225+ await self .zeroconf .async_wait_for_start ()
264226 await self .async_check_service (info , cooperating_responders )
265227 self .zeroconf .registry .add (info )
266228 return asyncio .ensure_future (self ._async_broadcast_service (info , _REGISTER_TIME , None ))
@@ -274,7 +236,7 @@ async def async_check_service(self, info: ServiceInfo, cooperating_responders: b
274236 for i in range (3 ):
275237 if i != 0 :
276238 await asyncio .sleep (millis_to_seconds (_CHECK_TIME ))
277- self .sender . send (self .zeroconf .generate_service_query (info ))
239+ self .zeroconf . async_send (self .zeroconf .generate_service_query (info ))
278240 self ._raise_on_name_conflict (info )
279241
280242 def _raise_on_name_conflict (self , info : ServiceInfo ) -> None :
@@ -304,13 +266,13 @@ async def async_update_service(self, info: ServiceInfo) -> Awaitable:
304266
305267 def _close (self ) -> None :
306268 """Shutdown zeroconf and the sender."""
307- self .sender .close ()
308269 self .zeroconf .remove_notify_listener (self .async_notify )
309270 self .zeroconf .close ()
310271
311272 async def async_close (self ) -> None :
312273 """Ends the background threads, and prevent this instance from
313274 servicing further queries."""
275+ await self .zeroconf .async_wait_for_start ()
314276 await self .async_remove_all_service_listeners ()
315277 await self .loop .run_in_executor (None , self ._close )
316278
0 commit comments