
    |;i|                    R   d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ ddlmZ ddlmZ ddlmZmZmZmZ dd	lmZmZmZ dd
lmZ ddlmZ ddlmZ ddlm Z m!Z!m"Z"m#Z# ddl$m%Z% ddl&m'Z'm(Z( ddl)m*Z*m+Z+ ddl,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7 dZ8e!jr                  de!jt                  de!jv                  diZ<e!jr                  Z=e!jt                  Z>e!jv                  Z?ej                  ZAdZBdZCerddlDmEZE eFZGeHZIeJZKeLZMeNeeOe   f   ZPej                  ZQej                  ZR G d d      ZS G d d      ZT	 	 	 	 	 	 	 	 d(dZU	 	 	 	 	 	 	 	 d)dZV	 	 	 	 	 	 	 	 	 	 	 	 d*dZW	 	 	 	 	 	 	 	 	 	 	 	 d+d ZX	 	 	 	 d,d!ZY G d" d#      ZZ G d$ d%e%      Z[ G d& d'e[ej                        Z]y)-a  Multicast DNS Service Discovery for Python, v0.14-wmcbrine
Copyright 2003 Paul Scott-Murphy, 2014 William McBrine

This module provides a framework for the use of DNS Service Discovery
using IP multicast.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
    )annotationsN)Iterable)partial)TracebackType)TYPE_CHECKINGAnyCallablecast   )
DNSPointerDNSQuestionDNSQuestionType)log)DNSOutgoing)RecordUpdate)ServiceListenerServiceStateChangeSignalSignalRegistrationInterface)RecordUpdateListener)cached_possible_typesservice_type_name)current_time_millismillis_to_seconds)_ADDRESS_RECORD_TYPES_BROWSER_TIME	_CLASS_IN_DNS_PACKET_HEADER_LEN_EXPIRE_REFRESH_TIME_PERCENT_FLAGS_QR_QUERY_MAX_MSG_TYPICAL
_MDNS_ADDR_MDNS_ADDR6
_MDNS_PORT	_TYPE_PTR)   x   add_serviceremove_serviceupdate_service   g?)Zeroconfc                  `    e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 d
dZddZddZddZddZddZ	ddZ
y	)_ScheduledPTRQuery)alias	cancelledexpire_time_millisnamettlwhen_millisc                X    || _         || _        || _        d| _        || _        || _        y)zCreate a scheduled query.FN)r/   r2   r3   r0   r1   r4   )selfr/   r2   r3   r1   r4   s         M/home/ubuntu/myenv/lib/python3.12/site-packages/zeroconf/_services/browser.py__init__z_ScheduledPTRQuery.__init__p   s4     
	 "4 '    c                    d| j                   j                   d| j                   d| j                   d| j                   d| j
                   d| j                   d| j                   dS )	z6Return a string representation of the scheduled query.<z alias=z name=z ttl=z cancelled=z expire_time_millis=z when_millis=>)	__class____name__r/   r2   r3   r0   r1   r4   r6   s    r7   __repr__z_ScheduledPTRQuery.__repr__   s~     ''( )ZZL !II; 88* ( )""&"9"9!: ;++,		
r9   c                b    t        |      t        u r| j                  |j                  k  S t        S zCompare two scheduled queries.typer.   r4   NotImplementedr6   others     r7   __lt__z_ScheduledPTRQuery.__lt__   ,    ;,,##e&7&777r9   c                    t        |      t        u r,| j                  |j                  k  xs | j                  |      S t        S rB   rD   r.   r4   __eq__rE   rF   s     r7   __le__z_ScheduledPTRQuery.__le__   :    ;,,##e&7&77M4;;u;MMr9   c                b    t        |      t        u r| j                  |j                  k(  S t        S rB   rC   rF   s     r7   rL   z_ScheduledPTRQuery.__eq__   s,    ;,,##u'8'888r9   c                    t        |      t        u r,| j                  |j                  kD  xs | j                  |      S t        S rB   rK   rF   s     r7   __ge__z_ScheduledPTRQuery.__ge__   rN   r9   c                b    t        |      t        u r| j                  |j                  kD  S t        S rB   rC   rF   s     r7   __gt__z_ScheduledPTRQuery.__gt__   rI   r9   N)r/   strr2   rT   r3   intr1   floatr4   rV   returnNone)rW   rT   )rG   r.   rW   bool)rG   r   rW   rY   )r>   
__module____qualname__	__slots__r8   r@   rH   rM   rL   rQ   rS    r9   r7   r.   r.   f   sf    I'' ' 	'
 "' ' 
'8
r9   r.   c                  $    e Zd ZdZdZddZddZy)_DNSPointerOutgoingBucketzA DNSOutgoing bucket.)bytes
now_millisoutc                J    || _         t        t        |      | _        d| _        y)z&Create a bucket to wrap a DNSOutgoing.r   N)ra   r   r    rb   r`   )r6   ra   	multicasts      r7   r8   z"_DNSPointerOutgoingBucket.__init__   s    $	:
r9   c                    | j                   j                  |       |D ](  }| j                   j                  || j                         * | xj                  |z  c_        y)z=Add a new set of questions and known answers to the outgoing.N)rb   add_questionadd_answer_at_timera   r`   )r6   max_compressed_sizequestionanswersanswers        r7   addz_DNSPointerOutgoingBucket.add   sL    h' 	AFHH''@	A

))
r9   N)ra   rV   rd   rY   rW   rX   )rh   int_ri   r   rj   zset[DNSPointer]rW   rX   )r>   rZ   r[   __doc__r\   r8   rl   r]   r9   r7   r_   r_      s    .I*r9   r_   c                    t        | ||      S )a  Aggregate queries so that as many known answers as possible fit in the same packet
    without having known answers spill over into the next packet unless the
    question and known answers are always going to exceed the packet size.

    Some responders do not implement multi-packet known answer suppression
    so we try to keep all the known answers in the same packet as the
    questions.
    )%_group_ptr_queries_with_known_answers)nowrd   question_with_known_answerss      r7   $group_ptr_queries_with_known_answersrs      s     1iA\]]r9   c           
        |j                         D ci c]%  \  }}||j                  t        d |D              z   ' }}}t        t        z
  }g }t        ||j                  d      D ]j  }||   }||   }	|D ])  }
|
j                  |z   |k  s|
j                  |||	        : t        | |      }
|
j                  |||	       |j                  |
       l |D 
cg c]  }
|
j                   c}
S c c}}w c c}
w )z7Inner wrapper for group_ptr_queries_with_known_answers.c              3  4   K   | ]  }|j                     y wN)max_size_compressed).0rk   s     r7   	<genexpr>z8_group_ptr_queries_with_known_answers.<locals>.<genexpr>   s     *b&6+E+E*bs   T)keyreverse)itemsmax_sizesumr!   r   sortedgetr`   rl   r_   appendrb   )ra   rd   rr   ri   known_answersquery_by_sizemax_bucket_sizequery_bucketsrh   rj   query_buckets              r7   rp   rp      s#    (C'H'H'J-#Hm 	8$$s*bTa*b'bbb-M - ')??O57M /
 ,H5-h7) 
	/L!!$77?J  !4hH
	/ 5ZKL0(GD  .#/& 2??L??3-2 @s   *C/C5c                   i }|| n|t         u }| j                  }| j                  }|D ]  }	t        |	t        t
              }
||
_        |j                  |	t        t
              D ch c]  }|j                  |      s| }}|s*|j                  |
||      rt        j                  d|
       t        rt        t        t           |      }n|}|||
<   |r|j!                  |
||        t#        |||      S c c}w )z8Generate a service query for sending with zeroconf.send.z0Asking %s was suppressed by the question history)QU_QUESTIONquestion_historycacher   r%   r   unicastget_all_by_detailsis_stale
suppressesr   debugr   r
   setr   add_question_at_timerp   )zcra   types_rd   question_typequestions_with_known_answersqu_questionr   r   type_ri   recordr   pointer_known_answerss                 r7   generate_service_queryr     s    ?A #0#8i-m{>ZK**HHE Wui;&  225)YO
??:. 
 

 /::8ZQ^_IIH(S$(Z-$H!$1!1F$X.11(JV#W& 1YHdee!
s   &C8c                :     t        | t        |         |||       y)z.Dispatch a service state change to a listener.N)getattr_ON_CHANGE_DISPATCH)listenerzeroconfservice_typer2   state_changes        r7   _on_change_dispatcherr   $  s      9GH),78<QUVr9   c                    | J t        | d      st        j                  | dt        d       t	        t
        |       S )z:Generate a service_state_changed handlers from a listener.r*   zy has no update_service method. Provide one (it can be empty if you don't care about the updates), it'll become mandatory.   )
stacklevel)hasattrwarningswarnFutureWarningr   r   )r   s    r7   $_service_state_changed_from_listenerr   /  sN     8-.l E E		
 ((33r9   c                      e Zd ZdZdZ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZddZ	 	 	 	 	 	 	 	 ddZddZ	ddZ
dd	Z	 	 	 	 	 	 	 	 dd
ZddZddZ	 	 	 	 	 	 	 	 ddZy)QuerySchedulerzSchedule outgoing PTR queries for Continuous Multicast DNS Querying

    https://datatracker.ietf.org/doc/html/rfc6762#section-5.2

    )_addr_clock_resolution_millis_first_random_delay_interval_loop _min_time_between_queries_millis
_multicast	_next_run_next_scheduled_for_alias_port_query_heap_question_type_startup_queries_sent_types_zcc	                   || _         || _        || _        || _        || _        || _        || _        d | _        d| _        i | _	        g | _
        d | _        t        j                  d      j                  dz  | _        || _        y )Nr   	monotonic  )r   r   r   r   r   r   r   r   r   r   r   r   timeget_clock_info
resolutionr   r   )	r6   r   typesaddrportrd   delayfirst_random_delay_intervalr   s	            r7   r8   zQueryScheduler.__init__V  s     

#,G)05-7;
%&"HJ&5759(,(;(;K(H(S(SVZ(Z%+r9   c                    t        t        j                  | j                         }|| _        |j                  || j                        | _        y)a  Start the scheduler.

        https://datatracker.ietf.org/doc/html/rfc6762#section-5.2
        To avoid accidental synchronization when, for some reason, multiple
        clients begin querying at exactly the same moment (e.g., because of
        some common external trigger event), a Multicast DNS querier SHOULD
        also delay the first query of the series by a randomly chosen amount
        in the range 20-120 ms.
        N)r   randomrandintr   r   
call_later_process_startup_queriesr   )r6   loopstart_delays      r7   startzQueryScheduler.startp  s<     (8Y8Y(Z[
d6S6STr9   c                    | j                   !| j                   j                          d| _         | j                  j                          | j                  j                          y)zStop the scheduler.N)r   cancelr   clearr   r?   s    r7   stopzQueryScheduler.stop~  sG    >>%NN!!#!DN&&,,. r9   c                    t        |j                  |j                  |j                  ||      }| j	                  |       yzSchedule a query for a pointer.N)r.   r/   r2   r3   _schedule_ptr_query)r6   pointerr1   refresh_time_millisscheduled_ptr_querys        r7   _schedule_ptr_refreshz$QueryScheduler._schedule_ptr_refresh  s9     1MM7<<6HJ]
 	  !45r9   c                b    || j                   |j                  <   t        | j                  |       yr   )r   r/   heappushr   )r6   scheduled_querys     r7   r   z"QueryScheduler._schedule_ptr_query  s(    @O&&'<'<=!!?3r9   c                d    | j                   j                  |j                  d      }|rd|_        yy)zCancel a query for a pointer.NT)r   popr/   r0   )r6   r   	scheduleds      r7   cancel_ptr_refreshz!QueryScheduler.cancel_ptr_refresh  s.    2266w}}dK	"&I r9   c                ^   | j                   j                  |j                        }|j                  t              }|M| j
                   ||j                  z
  cxk  r| j
                  k  ry d|_        | j                   |j                  = |j                  d      }| j                  |||       y)z!Reschedule a query for a pointer.NTd   )	r   r   r/   get_expiration_timer   r   r4   r0   r   )r6   r   currentr   r1   s        r7   reschedule_ptr_first_refreshz+QueryScheduler.reschedule_ptr_first_refresh  s    0044W]]C%99:VW 666&)<)<<9889 	9
 !%G..w}}=$88=""7,>@STr9   c                    |j                   dz  }||z  }||z   }||j                  k\  ryt        |j                  |j                  |j                   |j                  |      }| j                  |       y)zKReschedule a query for a pointer at an additional percentage of expiration.r   N)r3   r1   r.   r/   r2   r   )r6   queryra   additional_percentage
ttl_millisadditional_waitnext_query_timer   s           r7   schedule_rescue_queryz$QueryScheduler.schedule_rescue_query  sw     YY%
$'<<$6e666 0KKJJII$$
 	  !45r9   c                   t         r| j                  J | j                  j                  ry t	               }| j                  | j                  dk(  || j                         | xj                  dz  c_        | j                  t        k\  rB| j                  j                  t        || j                  z         | j                        | _        y | j                  j                  | j                  dz  | j                        | _        y )Nr   r   r   )r   r   r   doner   async_send_ready_queriesr   r   STARTUP_QUERIEScall_atr   r   _process_ready_typesr   r   r   )r6   ra   s     r7   r   z'QueryScheduler._process_startup_queries  s    ::))) 88==(*
 	%%d&@&@A&EzSWS^S^_""a'"
 %%8!ZZ//!*t/T/T"TU))DN ..t/I/I1/LdNkNklr9   c                <   t         r| j                  J | j                  j                  ryt	               }t               }d}|| j                  z   }g }| j                  r| j                  d   }|j                  rt        | j                         =|j                  |kD  r|}net        | j                        }|j                  |j                         | j                  |j                  = |j                  |       | j                  r|D ]  }| j!                  ||t"                |r| j%                  d||       || j&                  z   }||j                  |kD  r|j                  }n|}| j                  j)                  t+        |      | j,                        | _        y)zFGenerate a list of ready types that is due and schedule the next time.Nr   F)r   r   r   r   r   r   r   r   r0   heappopr4   rl   r2   r   r/   r   r   "RESCUE_RECORD_RETRY_TTL_PERCENTAGEr   r   r   r   r   r   )	r6   ra   ready_typesnext_scheduledend_time_millisschedule_rescuer   next_time_millisnext_when_milliss	            r7   r   z#QueryScheduler._process_ready_types  s~   ::))) 88==(*
 !$48$t'D'DD46$$Q'E(()  ?2!&D,,-EOOEJJ'..u{{;
 ""5) " % 	^E&&uj:\]	^ ))%[I%(M(MM%.*D*DGW*W-99/++,=>N,OQUQjQjkr9   c                    | j                   |rt        n| j                   }t        | j                  ||| j                  |      }|r9|D ]3  }| j                  j                  || j                  | j                         5 yy)zSend any ready queries.N)r   r   r   r   r   
async_sendr   r   )r6   first_requestra   r   r   outsrb   s          r7   r   z'QueryScheduler.async_send_ready_queries  sq     (,':':'B}Z^ZmZm%dhh
KZgh A##CTZZ@A r9   N)r   r,   r   set[str]r   
str | Noner   rU   rd   rY   r   rU   r   ztuple[int, int]r   DNSQuestionType | NonerW   rX   )r   zasyncio.AbstractEventLooprW   rX   rW   rX   )r   r   r1   float_r   r  rW   rX   )r   r.   rW   rX   )r   r   rW   rX   )r   r.   ra   r  r   r  rW   rX   )r   rY   ra   r  r   r   rW   rX   )r>   rZ   r[   rn   r\   r8   r   r   r   r   r   r   r   r   r   r   r]   r9   r7   r   r   >  s   I",, , 	,
 , , , &5, ., 
,4U!
6
6 #
6 $	
6
 

64
'U$6!6 6  &	6
 
60m43ljA!A/5ADLA	Ar9   r   c                      e Zd ZdZdZdddeedf	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZe	dd       Z
ddZ	 	 	 	 	 	 	 	 ddZdd	Zdd
ZddZddZddZy)_ServiceBrowserBasezBase class for ServiceBrowser.)	_cacher   _pending_handlers_query_sender_task_service_state_changedr   query_schedulerr   r   Nc	           
        |s	|sJ d       t        t        |t              r|n|g      | _        | j                  D ]  }	t	        |	d        || _        |j                  | _        |j                  J |j                  | _	        i | _
        t               | _        t        || j                  |||dt        t        fv |t         |      | _        d| _        d| _        t)        |d      rt+        t,        |      }d}t+        t        t.        d      |xs g       }|r|j1                  t3        |             |D ]  }
| j4                  j7                  |
        y)a,  Used to browse for a service for specific type(s).

        Constructor parameters are as follows:

        * `zc`: A Zeroconf instance
        * `type_`: fully qualified service type name
        * `handler`: ServiceListener or Callable that knows how to process ServiceStateChange events
        * `listener`: ServiceListener
        * `addr`: address to send queries (will default to multicast)
        * `port`: port to send queries (will default to mdns 5353)
        * `delay`: The initial delay between answering questions
        * `question_type`: The type of questions to ask (DNSQuestionType.QM or DNSQuestionType.QU)

        The listener object will have its add_service() and
        remove_service() methods called when this browser
        discovers changes in the services availability.
        z(You need to specify at least one handlerF)strictNr(   ).N)r   
isinstancelistr   r   r   r   r  r   r   r  r   r	  r   r"   r#   "_FIRST_QUERY_DELAY_RANDOM_INTERVALr
  r   r  r   r
   r   r	   r   r   service_state_changedregister_handler)r6   r   r   handlersr   r   r   r   r   check_type_hs              r7   r8   z_ServiceBrowserBase.__init__4  s?   8 8O%OO#"Jud,C5%Q
:: 	9Kk%8	9 hhww"""WW
LN&,h#-JJT:{33.	 
 	7;8]+OX6HHXi018>rBOO@JK 	;A&&77:	;r9   c                    | j                   j                  | | j                  D cg c]  }t        |t        t
               c}       t        j                  | j                               | _	        yc c}w )zGenerate the next time and setup listeners.

        Must be called by uses of this base class after they
        have finished setting their properties.
        N)
r   async_add_listenerr   r   r%   r   asyncioensure_future_async_start_query_senderr  )r6   r   s     r7   _async_startz _ServiceBrowserBase._async_startt  sV     	""4`d`j`j)kW\+eY	*R)kl")"7"78V8V8X"Y *ls   A1
c                .    | j                   j                  S rv   )r	  registration_interfacer?   s    r7   r  z)_ServiceBrowserBase.service_state_changed~  s    **AAAr9   c           	         |D cg c]/  }| j                   j                  t        |            D ]  }||f 1 c}}S c c}}w )zHReturn the type and name for records matching the types we are browsing.)r   intersectionr   )r6   namesr2   r   s       r7   _names_matching_typesz)_ServiceBrowserBase._names_matching_types  sM     ',
"9P9PQfgkQl9m
05UDM

 	
 
s   4>c                    ||f}|t         u s?|t        u r!| j                  j                  |      t         us|t        u r|| j                  vr|| j                  |<   y y y rv   )SERVICE_STATE_CHANGE_ADDEDSERVICE_STATE_CHANGE_REMOVEDr  r   SERVICE_STATE_CHANGE_UPDATED)r6   r   r   r2   rz   s        r7   _enqueue_callbackz%_ServiceBrowserBase._enqueue_callback  si     Um66 <<**..s3;UU <<DLbLbAb*6D""3' Bc<r9   c                   |D ]  }|j                   }|j                  }|j                  }|t        u rt        rt        t        |      }|}| j                  j                  t        |j                              D ]  }	|=| j                  t        |	|j                         | j                  j                  |       B|j!                  |      r=| j                  t"        |	|j                         | j                  j%                  |       | j                  j                  |        %||j!                  |      r:|t&        v rp| j(                  }
|
j+                  |j                        D ch c]  }|j                   }}| j-                  |      D ]  \  }	}| j                  t.        |	|        | j-                  |j                  f      D ]  \  }	}| j                  t.        |	|         yc c}w )a	  Callback invoked by Zeroconf when new information arrives.

        Updates information required by browser in the Zeroconf cache.

        Ensures that there is are no unnecessary duplicates in the list.

        This method will be run in the event loop.
        N)newoldrD   r%   r   r
   r   r   r  r   r2   r%  r"  r/   r
  r   
is_expiredr#  r   r   r  async_entries_with_serverr   r$  )r6   r   rq   recordsrecord_updater   
old_recordrecord_typer   r   r   servicer  r2   s                 r7   async_update_recordsz(_ServiceBrowserBase.async_update_records  s    % !	RM"&&F&**J ++Ki' !*f5F !ZZ445J7<<5XY SE!)../I5RYR_R_`,,II'R ++C0../KUT[TaTab,,??H,,II'RS  %):):3)?335:5T5TU[U`U`5ab'bb#'#=#=e#D VKE4**+GPTUV#996;;.I Rt&&'CUDQRA!	R4 cs   .G4c                    | j                   j                         D ]  }| j                  |        | j                   j                          y)zCalled when a record update has completed for all handlers.

        At this point the cache will have the new records.

        This method will be run in the event loop.

        This method is expected to be overridden by subclasses.
        N)r  r|   !_fire_service_state_changed_eventr   r6   pendings     r7   async_update_records_completez1_ServiceBrowserBase.async_update_records_complete  sB     --335 	<G227;	<$$&r9   c                v    |d   }|d   }| j                   j                  | j                  |d   |d   |       y)zFire a service state changed event.

        When running with ServiceBrowser, this will happen in the dedicated
        thread.

        When running with AsyncServiceBrowser, this will happen in the event loop.
        r   r   )r   r   r2   r   N)r	  firer   )r6   event	name_typer   s       r7   r2  z5_ServiceBrowserBase._fire_service_state_changed_event  sG     !H	Qx##((WW"11%	 	) 	
r9   c                    d| _         | j                  j                          | j                  j	                  |        | j
                  J d       | j
                  j                          d| _        y)Cancel the browser.TNz2Attempted to cancel a browser that was not started)r   r
  r   r   async_remove_listenerr  r   r?   s    r7   _async_cancelz!_ServiceBrowserBase._async_cancel  s_    	!!#%%d+&&2h4hh2&&("&r9   c                   K   | j                   j                  s"| j                   j                          d{    | j                  j	                  | j
                         y7 *w)zStart scheduling queries.N)r   startedasync_wait_for_startr
  r   r   r?   s    r7   r  z-_ServiceBrowserBase._async_start_query_sender  sD     ww''..000""4::. 1s   4A#A!+A#r   r,   r   z
str | listr  z2ServiceListener | list[Callable[..., None]] | Noner   zServiceListener | Noner   r   r   rU   r   rU   r   r  rW   rX   r  )rW   r   )r  zIterable[str]rW   zlist[tuple[str, str]])r   r   r   str_r2   rB  rW   rX   )r   r,   rq   r  r+  zlist[RecordUpdate]rW   rX   )r8  z*tuple[tuple[str, str], ServiceStateChange]rW   rX   )r>   rZ   r[   rn   r\   r$   r   r8   r  propertyr  r   r%  r0  r5  r2  r=  r  r]   r9   r7   r  r  %  s    (
I  HL+/"04>;>; >; E	>;
 )>; >; >; >; .>; 
>;@Z B B
7(7 7 	7
 
7&*RX'
"'/r9   r  c                       e Zd ZdZdddeedf	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d	 fdZd
dZd
dZd
dZ	ddZ
	 	 	 	 	 	 	 	 ddZ xZS )ServiceBrowserzUsed to browse for a service of a specific type.

    The listener object will have its add_service() and
    remove_service() methods called when this browser
    discovers changes in the services availability.Nc	           
     6   |j                   J |j                   j                         st        d      t        j                  j                  |        t        	|   ||||||||       t        j                         | _        d| _	        | j                          |j                   j                  | j                         dj                  dj                  | j                  D cg c]  }|d d 	 c}      t!        | d| j"                              | _        y c c}w )NzThe event loop is not runningTzzeroconf-ServiceBrowser-{}-{}-i	native_id)r   
is_runningRuntimeError	threadingThreadr8   superqueueSimpleQueuedaemonr   call_soon_threadsafer  formatjoinr   r   identr2   )
r6   r   r   r  r   r   r   r   r   r=   s
            r7   r8   zServiceBrowser.__init__  s     ww"""ww!!#>??!!$'UHhdE=Y ).(9(9(;



$$T%6%673::HHdjj9UeCRj9:D+tzz2
	9s   #Dc                    | j                   j                  J | j                  j                  d       | j                   j                  j	                  | j
                         | j                          y)r;  N)r   r   rN  putrQ  r=  rS  r?   s    r7   r   zServiceBrowser.cancel  sK    ww||'''

t))$*<*<=		r9   c                b    	 | j                   j                         }|y| j                  |       /)zRun the browser thread.N)rN  r   r2  )r6   r8  s     r7   runzServiceBrowser.run  s0    JJNN$E}2259	 r9   c                    | j                   j                         D ]  }| j                  j                  |        | j                   j	                          y)zCalled when a record update has completed for all handlers.

        At this point the cache will have the new records.

        This method will be run in the event loop.
        N)r  r|   rN  rV  r   r3  s     r7   r5  z,ServiceBrowser.async_update_records_complete'  sD     --335 	$GJJNN7#	$$$&r9   c                    | S rv   r]   r?   s    r7   	__enter__zServiceBrowser.__enter__2  s    r9   c                $    | j                          y rv   )r   )r6   exc_typeexc_valexc_tbs       r7   __exit__zServiceBrowser.__exit__5  s     	r9   rA  r  )rW   rE  )r]  ztype[BaseException] | Noner^  zBaseException | Noner_  zTracebackType | NonerW   zbool | None)r>   rZ   r[   rn   r$   r   r8   r   rX  r5  r[  r`  __classcell__)r=   s   @r7   rE  rE    s    7 HL+/"04

 
 E	

 )
 
 
 
 .
 

8:	', & %	
 
r9   rE  )rq   r  rd   bool_rr   _QuestionWithKnownAnswersrW   list[DNSOutgoing])ra   r  rd   rb  rr   rc  rW   rd  )r   r,   ra   r  r   r   rd   rY   r   r  rW   rd  )r   r   r   r,   r   rT   r2   rT   r   r   rW   rX   )r   r   rW   zCallable[..., None])^rn   
__future__r   r  heapqrN  r   rK  r   r   collections.abcr   	functoolsr   r   r   typingr   r   r	   r
   _dnsr   r   r   _loggerr   _protocol.outgoingr   _record_updater   	_servicesr   r   r   r   _updatesr   _utils.namer   r   _utils.timer   r   constr   r   r   r   r   r    r!   r"   r#   r$   r%   r  AddedRemovedUpdatedr   r"  r#  r$  QUr   r   r   _corer,   rV   r  rU   rm   rY   rb  rT   rB  dictr   rc  r   r   r.   r_   rs   rp   r   r   r   r   r  rL  rE  r]   r9   r7   <module>ry     sj  , #        $    < ;  , )  , B @    &/ " m 0 0  055 199 199   %( " 	

 c*o!=> 
-->>O Od* *&^	^^ ";^ 	^ $@$@$@ ";$@ 	$@Nfff f 	f
 *f fDWWW W 	W
 %W 
W444dA dANM/. M/`G()*:*: Gr9   