o
    `.                     @   s  d Z ddlZddlmZ ddlmZ ddlZddlmZ ddl	Z	ddl
mZmZ ddlZddlZddlmZ ddlmZ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 ddlmZm Z  ddl!m"Z" ddl#m$Z$ ddl%m&Z&m'Z'm(Z( g dZ)G dd dZ*dd Z+dd Z,G dd dZ-G dd de-Z.G dd deZ/dd Z0d+d"ejfd#d$Z1	&d,d"e.fd'd(Z2e3d)kre2 Z4e5d*e4j6 dS dS )-z'Synchronous IO wrappers around jeepney
    N)deque)
ECONNRESET)count)DefaultSelector
EVENT_READ)Optional)ParserMessageMessageTypeHeaderFields)AuthenticatorBEGIN)get_bus)FileDescriptorfds_buf_size)	ProxyBase
unwrap_msg)Router)message_bus   )MessageFiltersFilterHandlecheck_replyable)open_dbus_connectionDBusConnectionProxyc                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )_Futurec                 C   s
   d | _ d S N_resultself r"   5/usr/lib/python3/dist-packages/jeepney/io/blocking.py__init__      
z_Future.__init__c                 C   s
   t | jS r   )boolr   r    r"   r"   r#   done"   r%   z_Future.donec                 C      d|f| _ d S NFr   )r!   	exceptionr"   r"   r#   set_exception%      z_Future.set_exceptionc                 C   r(   )NTr   )r!   resultr"   r"   r#   
set_result(   r,   z_Future.set_resultc                 C   s   | j \}}|r	|S |r   r   )r!   successvaluer"   r"   r#   r-   +   s   
z_Future.resultN)__name__
__module____qualname__r$   r'   r+   r.   r-   r"   r"   r"   r#   r      s    r   c                 C   s   | d ur
t  |  S d S r   )time	monotonictimeoutr"   r"   r#   timeout_to_deadline2   s   r8   c                 C   s   | d urt | t  dS d S )Ng        )maxr4   r5   )deadliner"   r"   r#   deadline_to_timeout7   s   r;   c                   @   sx   e Zd ZdZddejfddZdd Zdd	 Zd
ede	e
ej ffddZdd Zdd ZdddZdd Zdd ZdS )DBusConnectionBasez8Connection machinery shared by this module and threadingFsockc                 C   sB   || _ || _t | _tdd| _t | _| j|t	| _
d | _d S )Nr   )start)r=   
enable_fdsr   parserr   outgoing_serialr   selectorregisterr   
select_keyunique_name)r!   r=   r?   r"   r"   r#   r$   ?   s   
zDBusConnectionBase.__init__c                 C   s   | S r   r"   r    r"   r"   r#   	__enter__H   s   zDBusConnectionBase.__enter__c                 C   s   |    dS r)   )close)r!   exc_typeexc_valexc_tbr"   r"   r#   __exit__K   s   zDBusConnectionBase.__exit__messagereturnc                 C   s<   |d u r	t | j}| jrtdnd }|j||d}||fS )Ni)serialfds)nextrA   r?   array	serialise)r!   rL   rO   rP   datar"   r"   r#   
_serialiseO   s
   
zDBusConnectionBase._serialisec                 C   sD   | j |gtjtj|fg}|t|k r | j ||d   d S d S r   )r=   sendmsgsocket
SOL_SOCKET
SCM_RIGHTSlensendall)r!   rT   rP   
bytes_sentr"   r"   r#   _send_with_fdsV   s   z!DBusConnectionBase._send_with_fdsc                 C   s>   	 | j  }|d ur|S | jt|d\}}| j j||d q)NTr6   )rP   )r@   get_next_message_read_some_datar;   add_data)r!   r:   msgbrP   r"   r"   r#   _receive_   s   
zDBusConnectionBase._receiveNc                 C   sN   | j |D ]\}}|| jkr$| jr|    S t| jdg f  S qt)Ni   )	rB   selectrD   r?   _read_with_fdsunwrap_readr=   recvTimeoutError)r!   r7   keyevr"   r"   r#   r_   h   s   
z"DBusConnectionBase._read_some_datac                 C   sT   | j  }| j|t \}}}}|ttdd@ r!|   tdt	|t
|fS )N
MSG_CTRUNCr   z&Unable to receive all file descriptors)r@   bytes_desiredr=   recvmsgr   getattrrW   rG   RuntimeErrorrf   r   from_ancdata)r!   nbytesrT   ancdataflags_r"   r"   r#   re   r   s   
z!DBusConnectionBase._read_with_fdsc                 C   s   | j   | j  dS )zClose the connectionN)rB   rG   r=   r    r"   r"   r#   rG   z   s   
zDBusConnectionBase.closeFr   )r1   r2   r3   __doc__rW   r$   rF   rK   r	   bytesr   rR   rU   r]   rc   r_   re   rG   r"   r"   r"   r#   r<   =   s    		
	
r<   c                       s   e Zd Zddejf fddZddefddZeZdd	d
efddZdd	ddZ	dddddZ
ddddee fddZdd	d
efddZ  ZS )r   Fr=   c                    sJ   t  || d| _tt| _t | _tt	| | _
| j
 }|d | _d S )NFr   )superr$   _unwrap_replyr   r   routerr   _filtersr   r   	bus_proxyHellorE   )r!   r=   r?   hello_reply	__class__r"   r#   r$      s   

zDBusConnection.__init__NrL   c                 C   s4   |  ||\}}|r| || dS | j| dS )z.Serialise and send a :class:`~.Message` objectN)rU   r]   r=   r[   )r!   rL   rO   rT   rP   r"   r"   r#   send   s   zDBusConnection.sendr6   rM   c                C   s   |  t|S )a+  Return the next available message from the connection

        If the data is ready, this will return immediately, even if timeout<=0.
        Otherwise, it will wait for up to timeout seconds, or indefinitely if
        timeout is None. If no message comes in time, it raises TimeoutError.
        )rc   r8   )r!   r7   r"   r"   r#   receive   s   zDBusConnection.receivec                C   s:   | j |d}| j| | j|D ]}|j| qdS )z\Receive one message and apply filters

        See :meth:`filter`. Returns nothing.
        r6   N)r   rz   incomingr{   matchesqueueappend)r!   r7   ra   filterr"   r"   r#   recv_messages   s
   zDBusConnection.recv_messagesr7   unwrapc          	      C   s   t | t|}|du r| j}t| j}| j||d 	 | jt|d}|jj	
tjd}||kr9|r7t|S |S | j| | j|D ]}|j| qEq)zSend a message, wait for the reply and return it

        Filters are applied to other messages received before the reply -
        see :meth:`add_filter`.
        N)rO   Tr6   )r   r8   ry   rQ   rA   send_messager   r;   headerfieldsgetr   reply_serialr   rz   r   r{   r   r   r   )	r!   rL   r7   r   r:   rO   msg_inreply_tor   r"   r"   r#   send_and_get_reply   s"   
z!DBusConnection.send_and_get_replyr   )r   bufsizer   c                C   s    |du r	t |d}t| j||S )a  Create a filter for incoming messages

        Usage::

            with conn.filter(rule) as matches:
                # matches is a deque containing matched messages
                matching_msg = conn.recv_until_filtered(matches)

        :param jeepney.MatchRule rule: Catch messages matching this rule
        :param collections.deque queue: Matched messages will be added to this
        :param int bufsize: If no deque is passed in, create one with this size
        N)maxlen)r   r   r{   )r!   ruler   r   r"   r"   r#   r      s   
zDBusConnection.filterc                C   s8   t |}t|dkr| jt|d t|dks
| S )aZ  Process incoming messages until one is filtered into queue

        Pops the message from queue and returns it, or raises TimeoutError if
        the optional timeout expires. Without a timeout, this is equivalent to::

            while len(queue) == 0:
                conn.recv_messages()
            return queue.popleft()

        In the other I/O modules, there is no need for this, because messages
        are placed in queues by a separate task.

        :param collections.deque queue: A deque connected by :meth:`filter`
        :param float timeout: Maximum time to wait in seconds
        r   r6   )r8   rZ   r   r;   popleft)r!   r   r7   r:   r"   r"   r#   recv_until_filtered   s
   z"DBusConnection.recv_until_filteredru   r   )r1   r2   r3   rW   r$   r	   r   r   r   r   r   r   r   r   r   __classcell__r"   r"   r   r#   r      s    	
r   c                       s6   e Zd ZdZdd fdd
Zdd Zdd	 Z  ZS )
r   aj  A blocking proxy for calling D-Bus methods

    You can call methods on the proxy object, such as ``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.

    You can set a time limit on a call by passing ``_timeout=`` in the method
    call, or set a default when creating the proxy. The ``_timeout`` argument
    is not passed to the message generator.
    All timeouts are in seconds, and :exc:`TimeoutErrror` is raised if it
    expires before a reply arrives.

    :param msggen: A message generator object
    :param ~blocking.DBusConnection connection: Connection to send and receive messages
    :param float timeout: Default seconds to wait for a reply, or None for no limit
    Nr6   c                   s   t  | || _|| _d S r   )rx   r$   _connection_timeout)r!   msggen
connectionr7   r   r"   r#   r$      s   
zProxy.__init__c                 C   s4   | j d u rdnd| j  }d| j d| j | dS )N z
, timeout=zProxy(z, ))r   _msggenr   )r!   extrar"   r"   r#   __repr__  s   zProxy.__repr__c                    s   t   fdd}|S )Nc                     s@   | dj} | i |}|jjtju sJ jj||ddS )Nr   Tr   )popr   r   message_typer
   method_callr   r   )argskwargsr7   ra   make_msgr!   r"   r#   inner	  s   z!Proxy._method_call.<locals>.inner)	functoolswraps)r!   r   r   r"   r   r#   _method_call  s   zProxy._method_call)r1   r2   r3   rv   r$   r   r   r   r"   r"   r   r#   r      s
    r   c                 C   s   | s
t ttt| S )zRaise ConnectionResetError from an empty read.

    Sometimes the socket raises an error itself, sometimes it gives no data.
    I haven't worked out when it behaves each way.
    )ConnectionResetErrorr   osstrerror)rb   r"   r"   r#   rf     s   rf   F       @rM   c              
      s   t j t jdt|  fdd}z)|j|  t|d}|D ]}|j| |t|jd q |jt	 W n! t j
yU } z  td| d|d}~w      d S )	z=Create a socket and authenticate ready to send D-Bus messages)familyc                    s    t  | | S r   )
settimeoutr;   )methr   r:   r=   r"   r#   with_sock_deadline(  s   z'prep_socket.<locals>.with_sock_deadline)r?   i   zDid not authenticate in z secondsN)rW   AF_UNIXr8   connectr   r[   feedrf   rg   r   r7   rG   rh   r   )addrr?   r7   r   authrreq_dataer"   r   r#   prep_socket   s&   

r   SESSION      ?c                 C   s$   t | }t|||d}t||}|S )a  Connect to a D-Bus message bus

    Pass ``enable_fds=True`` to allow sending & receiving file descriptors.
    An error will be raised if the bus does not allow this. For simplicity,
    it's advisable to leave this disabled unless you need it.

    D-Bus has an authentication step before sending or receiving messages.
    This takes < 1 ms in normal operation, but there is a timeout so that client
    code won't get stuck if the server doesn't reply. *auth_timeout* configures
    this timeout in seconds.
    r6   )r   r   r   )busr?   auth_timeoutbus_addrr=   connr"   r"   r#   r   >  s   
r   __main__zUnique name:)Fr   )r   Fr   )7rv   rR   collectionsr   errnor   r   	itertoolsr   r   	selectorsr   r   rW   r4   typingr   jeepneyr   r	   r
   r   jeepney.authr   r   jeepney.busr   jeepney.fdsr   r   jeepney.wrappersr   r   jeepney.routingr   jeepney.bus_messagesr   commonr   r   r   __all__r   r8   r;   r<   r   r   rf   r   r   r1   r   printrE   r"   r"   r"   r#   <module>   sH    Cm(
