o
    3b^A                     @   s  d 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mZm	Z	m
Z
mZmZ edZdZdZg dZeeddZes?eed	ZG d
d deZG dd deZG dd deZG dd deZG dd deZG dd deZdadee fddZddejdefddZdS )zLibvirt event loop implementation using asyncio

Register the implementation of default loop:

    >>> import libvirtaio
    >>> libvirtaio.virEventRegisterAsyncIOImpl()

.. seealso::
    https://libvirt.org/html/libvirt-libvirt-event.html
    N)AnyCallableDict	GeneratorOptionalTypeVar_Tz,Wojtek Porczyk <woju@invisiblethingslab.com>z	LGPL-2.1+)getCurrentImplvirEventAsyncIOImplvirEventRegisterAsyncIOImplensure_futureasyncc                       sf   e Zd ZdZe Zdddeee	gdf de	de
de
d	df fd
dZd	efddZdddZ  ZS )CallbackzBase class for holding callback

    :param virEventAsyncIOImpl impl: the implementation in which we run
    :param cb: the callback itself
    :param opaque: the opaque tuple passed by libvirt
    implr
   cbNopaqueargskwargsreturnc                    s4   t  j|i | t| j| _|| _|| _|| _d S N)super__init__next_iden_counteridenr   r   r   )selfr   r   r   r   r   	__class__ ,/usr/lib/python3/dist-packages/libvirtaio.pyr   E   s
   
zCallback.__init__c                 C   s   d | jj| jS )Nz<{} iden={}>)formatr   __name__r   r   r   r   r   __repr__L   s   zCallback.__repr__c                 C   s(   | j jd| j | j | j| j dS )zSchedule *ff* callbackz"callback %d close(), scheduling ffN)r   logdebugr   schedule_ff_callbackr   r"   r   r   r   closeO   s   zCallback.closer   N)r!   
__module____qualname____doc__	itertoolscountr   r   intr   r   r   strr#   r'   __classcell__r   r   r   r   r   :   s    2r   c                   @   s^   e Zd ZdZdddeddfddZd	eddfd
dZdddZdddZdeddfddZ	dS )
DescriptorzManager of one file descriptor

    :param virEventAsyncIOImpl impl: the implementation in which we run
    :param int fd: the file descriptor
    r   r
   fdr   Nc                 C   s   || _ || _i | _d S r   )r   r2   	callbacks)r   r   r2   r   r   r   r   _   s   
zDescriptor.__init__eventc                 C   sB   t | j D ]}|jdur|j|@ r||j| j||j qdS )zDispatch the event to the descriptors

        :param int event: The event (from libvirt's constants) being dispatched
        N)listr3   valuesr4   r   r   r2   r   )r   r4   callbackr   r   r   _handled   s
   zDescriptor._handlec                 C   s   t dd | j D rtdt t dd | j D r+| jj| j	| j
tj n| jj| j	 t dd | j D rM| jj| j	| j
tj dS | jj| j	 dS )zRegister or unregister callbacks at event loop

        This should be called after change of any ``.event`` in callbacks.
        c                 s   s$    | ]}|j tjtjB  @ V  qd S r   )r4   libvirtVIR_EVENT_HANDLE_READABLEVIR_EVENT_HANDLE_WRITABLE.0r7   r   r   r   	<genexpr>x   s    z$Descriptor.update.<locals>.<genexpr>zTThe only event supported are VIR_EVENT_HANDLE_READABLE and VIR_EVENT_HANDLE_WRITABLEc                 s       | ]	}|j tj@ V  qd S r   )r4   r9   r:   r<   r   r   r   r>          c                 s   r?   r   )r4   r9   r;   r<   r   r   r   r>      r@   N)anyr3   r6   warningswarnUserWarningr   loop
add_readerr2   r8   r9   r:   remove_reader
add_writerr;   remove_writerr"   r   r   r   updatem   s*   zDescriptor.updater7   
FDCallbackc                 C   s   || j |j< |   dS )zAdd a callback to the descriptor

        :param FDCallback callback: the callback to add
        :rtype: None

        After adding the callback, it is immediately watched.
        N)r3   r   rJ   )r   r7   r   r   r   
add_handle   s   zDescriptor.add_handler   c                 C   s   | j |}|   |S )a  Remove a callback from the descriptor

        :param int iden: the identifier of the callback
        :returns: the callback
        :rtype: FDCallback

        After removing the callback, the descriptor may be unwatched, if there
        are no more handles for it.
        )r3   poprJ   )r   r   r7   r   r   r   remove_handle   s   
zDescriptor.remove_handler(   )r7   rK   r   N)
r!   r)   r*   r+   r.   r   r8   rJ   rL   rN   r   r   r   r   r1   Y   s    
	
"r1   c                       s4   e Zd ZdZd fddZdedefd	d
Z  ZS )DescriptorDictzdDescriptors collection

    This is used internally by virEventAsyncIOImpl to hold descriptors.
    r   r
   r   Nc                    s   t    || _d S r   )r   r   r   )r   r   r   r   r   r      s   

zDescriptorDict.__init__r2   c                 C   s   t | j|}|| |< |S r   )r1   r   )r   r2   
descriptorr   r   r   __missing__   s   zDescriptorDict.__missing__)r   r
   r   N)	r!   r)   r*   r+   r   r.   r1   rQ   r0   r   r   r   r   rO      s    rO   c                
       sV   e Zd ZdZdededededdf
 fdd	Zdefd
dZ	deddfddZ
  ZS )rK   zCallback for file descriptor (watcher)

    :param Descriptor descriptor: the descriptor manager
    :param int event: bitset of events on which to fire the callback
    r   rP   r4   r   r   Nc                   s"   t  j|i | || _|| _d S r   )r   r   rP   r4   )r   rP   r4   r   r   r   r   r   r         
zFDCallback.__init__c                 C   s   d | jj| j| jj| jS )Nz<{} iden={} fd={} event={}>)r    r   r!   r   rP   r2   r4   r"   r   r   r   r#      s   zFDCallback.__repr__c                 C   s   || _ | j  dS )z1Update the callback and fix descriptor's watchersN)r4   rP   rJ   )r   r4   r   r   r   rJ      s   zFDCallback.update)r!   r)   r*   r+   r   r1   r.   r   r/   r#   rJ   r0   r   r   r   r   rK      s
    "rK   c                       sz   e Zd ZdZdededdf fddZdefdd	Zej	de
eddf fd
dZdeddfddZd fddZ  ZS )TimeoutCallbackzCallback for timerr   r   r   Nc                    s"   t  j|i | d| _d | _d S )N)r   r   timeout_task)r   r   r   r   r   r   r      rR   zTimeoutCallback.__init__c                 C   s   d | jj| j| jS )Nz<{} iden={} timeout={}>)r    r   r!   r   rU   r"   r   r   r   r#      s   zTimeoutCallback.__repr__c                 c   s    	 z | j dkr| j d }| jjd| t|E dH  ndV  W n tjy6   | jjd| j Y dS w | | j| j	 | jjd| j q)zQAn actual timer running on the event loop.

        This is a coroutine.
        Tr   gMbP?zsleeping %rNztimer %d cancelledztimer %r callback ended)
rU   r   r$   r%   asynciosleepCancelledErrorr   r   r   r   rU   r   r   r   _timer   s    

zTimeoutCallback._timerrU   c                 C   s   || _ | j dkr#| jdu r#| jjd| j t|  | jjd| _dS | j dk r@| jdurB| jjd| j | j	  d| _dS dS dS )z-Start or the timer, possibly updating timeoutr   Nztimer %r startrE   ztimer %r stop)
rU   rV   r   r$   r%   r   r   r[   rE   cancelrZ   r   r   r   rJ      s   

zTimeoutCallback.updatec                    s   | j dd tt|   dS )z#Stop the timer and call ff callbackrT   rU   N)rJ   r   rS   r'   r"   r   r   r   r'     s   zTimeoutCallback.closer(   )r!   r)   r*   r+   r   r   r/   r#   rW   	coroutiner   r[   r.   rJ   r'   r0   r   r   r   r   rS      s    rS   c                
   @   s<  e Zd ZdZd+dejddfddZdefddZd,d	d
Z	d,ddZ
d-ddZdededdfddZejdededdfddZejdeeddf fddZdefddZdededejdedef
ddZdededdfdd Zdedefd!d"Zd#edejdedefd$d%Zd&ed#eddfd'd(Zd&edefd)d*ZdS ).r
   zLibvirt event adapter to asyncio.

    :param loop: asyncio's event loop

    If *loop* is not specified, the current (or default) event loop is used.
    NrE   r   c                 C   sP   |pt  | _i | _t| | _t| jj	| _
d| _t j|d| _| j  d S )Nr   r\   )rW   get_event_looprE   r3   rO   descriptorslogging	getLoggerr   r!   r$   _pendingEvent	_finishedset)r   rE   r   r   r   r     s   
zvirEventAsyncIOImpl.__init__c                 C   s   d t| j| j| jS )Nz <{} callbacks={} descriptors={}>)r    typer!   r3   ra   r"   r   r   r   r#      s   zvirEventAsyncIOImpl.__repr__c                 C   s   |  j d7  _ | j  dS )z;Increase the count of pending affairs. Do not use directly.   N)rd   rf   clearr"   r   r   r   _pending_inc$  s   z virEventAsyncIOImpl._pending_incc                 C   s8   | j dksJ |  j d8  _ | j dkr| j  dS dS )z;Decrease the count of pending affairs. Do not use directly.r   ri   N)rd   rf   rg   r"   r   r   r   _pending_dec)  s
   
z virEventAsyncIOImpl._pending_decc                 C   s0   | j d t| j| j| j| j| j| j	 | S )z3Register this instance as event loop implementationz
register())
r$   r%   r9   virEventRegisterImpl_add_handle_update_handle_remove_handle_add_timeout_update_timeout_remove_timeoutr"   r   r   r   register0  s   zvirEventAsyncIOImpl.registerr   r   c                 C   s   t | ||| jd dS )z8Schedule a ff callback from one of the handles or timersr\   N)r   _ff_callbackrE   r   r   r   r   r   r   r&   9  s   z(virEventAsyncIOImpl.schedule_ff_callbackc                 C   s$   | j d| t| |   dS )zFDirectly free the opaque object

        This is a coroutine.
        z ff_callback(iden=%d, opaque=...)N)r$   r%   r9   virEventInvokeFreeCallbackrl   rv   r   r   r   ru   =  s   
z virEventAsyncIOImpl._ff_callbackc                 c   s4    | j d | jr| j E dH  | j d dS )zRWait for the implementation to become idle.

        This is a coroutine.
        zdrain()Nzdrain ended)r$   r%   rd   rf   waitr"   r   r   r   drainG  s
   zvirEventAsyncIOImpl.drainc                 C   s   | j  o| j S )zReturns False if there are leftovers from a connection

        Those may happen if there are sematical problems while closing
        a connection. For example, not deregistered events before .close().
        )r3   rd   r"   r   r   r   is_idleR  s   zvirEventAsyncIOImpl.is_idler2   r4   r   c                 C   sf   t | ||| j| |d}|j| jvsJ | jd|||j || j|j< | j| | |   |jS )a  Register a callback for monitoring file handle events

        :param int fd: file descriptor to listen on
        :param int event: bitset of events on which to fire the callback
        :param cb: the callback to be called when an event occurrs
        :param opaque: user data to pass to the callback
        :rtype: int
        :returns: handle watch number to be used for updating and unregistering for events

        .. seealso::
            https://libvirt.org/html/libvirt-libvirt-event.html#virEventAddHandleFuncFunc
        )rP   r4   z4add_handle(fd=%d, event=%d, cb=..., opaque=...) = %d)rK   ra   r   r3   r$   r%   rL   rk   )r   r2   r4   r   r   r7   r   r   r   rn   Z  s   
zvirEventAsyncIOImpl._add_handlewatchc                 C   8   | j d|| | j| }t|tsJ |j|d dS )a  Change event set for a monitored file handle

        :param int watch: file descriptor watch to modify
        :param int event: new events to listen on

        .. seealso::
            https://libvirt.org/html/libvirt-libvirt-event.html#virEventUpdateHandleFunc
        z!update_handle(watch=%d, event=%d))r4   N)r$   r%   r3   
isinstancerK   rJ   )r   r{   r4   r7   r   r   r   ro   r     	
z"virEventAsyncIOImpl._update_handlec              
   C   s   | j d| z| j|}W n ty, } z| j d|jd  W Y d}~dS d}~ww t|ts4J |j	j
}|| j| |u sDJ t| j| jdkrR| j|= |  dS )a  Unregister a callback from a file handle.

        :param int watch: file descriptor watch to stop listening on
        :returns: -1 on error, 0 on success

        .. seealso::
            https://libvirt.org/html/libvirt-libvirt-event.html#virEventRemoveHandleFunc
        zremove_handle(watch=%d)z#remove_handle(): no such handle: %rr   NrT   )r$   r%   r3   rM   KeyErrorwarningr   r}   rK   rP   r2   ra   rN   lenr'   )r   r{   r7   errr2   r   r   r   rp     s   	z"virEventAsyncIOImpl._remove_handlerU   c                 C   sT   t | ||}|j| jvsJ | jd||j || j|j< |j|d |   |jS )a}  Register a callback for a timer event

        :param int timeout: the timeout to monitor
        :param cb: the callback to call when timeout has expired
        :param opaque: user data to pass to the callback
        :rtype: int
        :returns: a timer value

        .. seealso::
            https://libvirt.org/html/libvirt-libvirt-event.html#virEventAddTimeoutFunc
        z0add_timeout(timeout=%d, cb=..., opaque=...) = %dr^   )rS   r   r3   r$   r%   rJ   rk   )r   rU   r   r   r7   r   r   r   rq     s   z virEventAsyncIOImpl._add_timeouttimerc                 C   r|   )zChange frequency for a timer

        :param int timer: the timer to modify
        :param int timeout: the new timeout value in ms

        .. seealso::
            https://libvirt.org/html/libvirt-libvirt-event.html#virEventUpdateTimeoutFunc
        z$update_timeout(timer=%d, timeout=%d)r^   N)r$   r%   r3   r}   rS   rJ   )r   r   rU   r7   r   r   r   rr     r~   z#virEventAsyncIOImpl._update_timeoutc              
   C   sf   | j d| z| j|}W n ty, } z| j d|jd  W Y d}~dS d}~ww |  dS )zUnregister a callback for a timer

        :param int timer: the timer to remove
        :returns: -1 on error, 0 on success

        .. seealso::
            https://libvirt.org/html/libvirt-libvirt-event.html#virEventRemoveTimeoutFunc
        zremove_timeout(timer=%d)z%remove_timeout(): no such timeout: %rr   NrT   )r$   r%   r3   rM   r   r   r   r'   )r   r   r7   r   r   r   r   rs     s   	z#virEventAsyncIOImpl._remove_timeoutr   r(   )r   r
   )r!   r)   r*   r+   rW   AbstractEventLoopr   r/   r#   rk   rl   rt   r.   r   r&   r_   ru   r   r   ry   boolrz   r9   _EventCBrn   ro   rp   _TimerCBrq   rr   rs   r   r   r   r   r
     s&    


		
 r
   r   c                   C   s   t S )z@Return the current implementation, or None if not yet registered)_current_implr   r   r   r   r	     s   r	   rE   c                 C   s   t | d atS )zArrange for libvirt's callbacks to be dispatched via asyncio event loop

    The implementation object is returned, but in normal usage it can safely be
    discarded.
    r\   )r
   rt   r   r\   r   r   r   r     s   r   r   )r+   rW   r,   rb   rB   r9   typingr   r   r   r   r   r   r   
__author____license____all__getattrr   objectr   r1   dictrO   rK   rS   r
   r   r	   r   r   r   r   r   r   <module>   s0    

P: B