o
    a                     @   s   d dl Z d dlZd dlmZ d dlmZ d dlmZmZ d dl	m
Z
 d dlmZmZmZ d dlmZmZ d dlmZ d	d
lmZmZmZmZmZ G dd dZdddZG dd dZG dd dZG dd deZdS )    N)count)Optional)AuthenticatorBEGIN)get_bus)MessageMessageTypeParser)	ProxyBase
unwrap_msg)message_bus   )MessageFiltersFilterHandleReplyMatcherRouterClosedcheck_replyablec                   @   s`   e Zd ZdZdejdejfddZdddefd	d
Z	defddZ
dd Zdd Zdd ZdS )DBusConnectionaP  A plain D-Bus connection with no matching of replies.

    This doesn't run any separate tasks: sending and receiving are done in
    the task that calls those methods. It's suitable for implementing servers:
    several worker tasks can receive requests and send replies.
    For a typical client pattern, see :class:`DBusRouter`.
    readerwriterc                 C   s4   || _ || _t | _tdd| _d | _t | _	d S )Nr   )start)
r   r   r	   parserr   outgoing_serialunique_nameasyncioZLock	send_lock)selfr   r    r   4/usr/lib/python3/dist-packages/jeepney/io/asyncio.py__init__   s   zDBusConnection.__init__Nserialmessagec             	      sv   | j 4 I dH & |du rt| j}| j|| | j I dH  W d  I dH  dS 1 I dH s4w   Y  dS )z.Serialise and send a :class:`~.Message` objectN)r   nextr   r   writeZ	serialisedrainr   r"   r!   r   r   r   send    s   
.zDBusConnection.sendreturnc                    sB   	 | j  }|dur|S | jdI dH }|st| j | q)z5Return the next available message from the connectionTNi   )r   Zget_next_messager   readEOFErrorZadd_data)r   msgbr   r   r   receive(   s   
zDBusConnection.receivec                    s    | j   | j  I dH  dS )zClose the D-Bus connectionN)r   closeZwait_closedr   r   r   r   r.   4   s   
zDBusConnection.closec                       | S Nr   r/   r   r   r   
__aenter__9      zDBusConnection.__aenter__c                    s   |   I d H  d S r1   )r.   r   exc_typeZexc_valexc_tbr   r   r   	__aexit__<   s   zDBusConnection.__aexit__)__name__
__module____qualname____doc__r   StreamReaderStreamWriterr   r   r'   r-   r.   r2   r7   r   r   r   r   r      s    r   SESSIONc           
   	      s   t | }t|I dH \}}t }|D ]!}|| | I dH  |dI dH }|s0td|| q|t	 | I dH  t
||}t|4 I dH }ttt| dI dH }	|	d |_W d  I dH  |S 1 I dH stw   Y  |S )zHOpen a plain D-Bus connection

    :return: :class:`DBusConnection`
    Ni   z#Socket closed before authentication
   r   )r   r   Zopen_unix_connectionr   r$   r%   r)   r*   Zfeedr   r   
DBusRouterZwait_forProxyr   ZHellor   )
busZbus_addrr   r   ZauthrZreq_datar,   connrouterZ
reply_bodyr   r   r   open_dbus_connection@   s*   


rE   c                   @   s   e Zd ZdZdZdZdZdefddZe	dd Z
ddd	d
ZdefddZddddeej fddZdd Zdd ZdefddZdd ZdS )r@   zA 'client' D-Bus connection which can wait for a specific reply.

    This runs a background receiver task, and makes it possible to send a
    request and wait for the relevant reply.
    NrC   c                 C   s*   || _ t | _t | _t|  | _d S r1   )	_connr   _repliesr   _filtersr   Zcreate_task	_receiver	_rcv_task)r   rC   r   r   r   r   j   s   zDBusRouter.__init__c                 C   s   | j jS r1   )rF   r   r/   r   r   r   r   p   s   zDBusRouter.unique_namer    c                   s   | j j||dI dH  dS )z&Send a message, don't wait for a replyr    N)rF   r'   r&   r   r   r   r'   t   s   zDBusRouter.sendr(   c                    s|   t | | j rtdt| jj}| j|t	
 }| j||dI dH  |I dH W  d   S 1 s7w   Y  dS )zSend a method call message and wait for the reply

        Returns the reply message (method return or error message type).
        zThis DBusRouter has stoppedr    N)r   rJ   doner   r#   rF   r   rG   Zcatchr   ZFuturer'   )r   r"   r!   Z	reply_futr   r   r   send_and_get_replyx   s   
$zDBusRouter.send_and_get_replyr   )queuebufsizerM   c                C   s   t | j||p
t|S )ar  Create a filter for incoming messages

        Usage::

            with router.filter(rule) as queue:
                matching_msg = await queue.get()

        :param MatchRule rule: Catch messages matching this rule
        :param asyncio.Queue queue: Send matching messages here
        :param int bufsize: If no queue is passed in, create one with this size
        )r   rH   r   Queue)r   ZrulerM   rN   r   r   r   filter   s   zDBusRouter.filterc                    r0   r1   r   r/   r   r   r   r2      r3   zDBusRouter.__aenter__c                    sb   | j  r| j   dS | j   ttj | j I d H  W d    dS 1 s*w   Y  dS )NF)rJ   rK   resultZcancel
contextlibsuppressr   ZCancelledErrorr4   r   r   r   r7      s   



zDBusRouter.__aexit__r+   c              	   C   sN   | j |rdS t| j|D ]}z|j| W q tjy$   Y qw dS )zHandle one received messageN)	rG   dispatchlistrH   matchesrM   Z
put_nowaitr   Z	QueueFull)r   r+   rP   r   r   r   	_dispatch   s   zDBusRouter._dispatchc                    s.   z	 | j  I dH }| | q| j  w )z'Receiver loop - runs in a separate taskTN)rF   r-   rW   rG   Zdrop_all)r   r+   r   r   r   rI      s   
zDBusRouter._receiver)r8   r9   r:   r;   Z_nursery_mgrZ_send_cancel_scopeZ_rcv_cancel_scoper   r   propertyr   r'   r   rL   r   r   rO   rP   r2   r7   rW   rI   r   r   r   r   r@   `   s    
r@   c                   @   s2   e Zd ZdZdZdZd
ddZdd Zdd	 ZdS )open_dbus_routerzOpen a D-Bus 'router' to send and receive messages

    Use as an async context manager::

        async with open_dbus_router() as router:
            ...
    Nr>   c                 C   s
   || _ d S r1   )rB   )r   rB   r   r   r   r      s   
zopen_dbus_router.__init__c                    s0   t | jI d H | _t| j| _| j I d H S r1   )rE   rB   rC   r@   req_ctxr2   r/   r   r   r   r2      s   zopen_dbus_router.__aenter__c                    s,   | j |||I d H  | j I d H  d S r1   )rZ   r7   rC   r.   r4   r   r   r   r7      s   zopen_dbus_router.__aexit__r>   )	r8   r9   r:   r;   rC   rZ   r   r2   r7   r   r   r   r   rY      s    
rY   c                       s0   e Zd ZdZ fddZdd Zdd Z  ZS )rA   a  An asyncio proxy for calling D-Bus methods

    You can call methods on the proxy object, such as ``await bus_proxy.Hello()``
    to make a method call over D-Bus and wait for a reply. It will either
    return a tuple of returned data, or raise :exc:`.DBusErrorResponse`.
    The methods available are defined by the message generator you wrap.

    :param msggen: A message generator object.
    :param ~asyncio.DBusRouter router: Router to send and receive messages.
    c                    s   t  | || _d S r1   )superr   _router)r   ZmsggenrD   	__class__r   r   r      s   
zProxy.__init__c                 C   s   d | j| jS )NzProxy({}, {}))formatZ_msggenr]   r/   r   r   r   __repr__   s   zProxy.__repr__c                    s    fdd}|S )Nc                     s<    | i |}|j jtju sJ j|I d H }t|S r1   )headerZmessage_typer   Zmethod_callr]   rL   r   )argskwargsr+   Zreplymake_msgr   r   r   inner   s
   z!Proxy._method_call.<locals>.innerr   )r   rf   rg   r   re   r   _method_call   s   zProxy._method_call)r8   r9   r:   r;   r   ra   rh   __classcell__r   r   r^   r   rA      s
    
rA   r[   )r   rR   	itertoolsr   typingr   Zjeepney.authr   r   Zjeepney.busr   Zjeepneyr   r   r	   Zjeepney.wrappersr
   r   Zjeepney.bus_messagesr   commonr   r   r   r   r   r   rE   r@   rY   rA   r   r   r   r   <module>   s    
0 X