U
    [e :                     @   s  d dl Z d dlmZ d dlZd dlmZ d dlZd dlmZ zd dlm	Z	 W n  e
k
rl   d dlm	Z	 Y nX d dlmZmZ d dl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 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( e)e*Z+dddgZ,edd Z-G dd deZ.d$dde.dddZ/G dd de%Z0G dd dZ1G d d! d!Z2G d"d deZ3e	d%ddd#dZ4dS )&    N)contextmanager)count)Optional)asynccontextmanager)ValueError)Channel)AuthenticatorBEGIN)get_bus)FileDescriptorfds_buf_size)ParserMessageTypeMessage)	ProxyBase
unwrap_msg)message_bus   )MessageFiltersFilterHandleReplyMatcherRouterClosedcheck_replyableopen_dbus_connectionopen_dbus_routerProxyc               
   c   sd   z
d V  W nT t k
r^ }  z6| jtjtjhkr<tdd ntd| | W 5 d } ~ X Y nX d S )Nzthis socket was already closedzsocket connection broken: {})OSErrorerrnoEBADFENOTSOCKtrioClosedResourceErrorZBrokenResourceErrorformat)exc r%   Q/var/www/html/services/stratfitenv/lib/python3.8/site-packages/jeepney/io/trio.py)_translate_socket_errors_to_stream_errors0   s    
r'   c                   @   s~   e Zd ZdZdddZddeddd	Zed
ddZde	d
ddZ
edddZdd Zdd Zdd Zedd ZdS )DBusConnectiona  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`.

    Implements trio's channel interface for Message objects.
    Fc                 C   sD   || _ || _t | _tdd| _d | _t | _	t | _
d | _d S )Nr   )start)socket
enable_fdsr   parserr   outgoing_serialunique_namer!   Lock	send_lock	recv_lock_leftover_to_send)selfr*   r+   r%   r%   r&   __init__I   s    

zDBusConnection.__init__Nserial)messagec             
      sj   | j 4 I dH L |dkr"t| j}| jr2tdnd}|j||d}| ||I dH  W 5 Q I dH R X dS )z.Serialise and send a :class:`~.Message` objectNi)fds)r0   nextr-   r+   arrayZ	serialise
_send_data)r3   r7   r6   r9   datar%   r%   r&   sendS   s    
zDBusConnection.send)r=   c              
      s   | j jrtdt  | jr2| | jI d H  t|V}|rh| j |gtj j	tj j
|fgI d H }n| j |I d H }| ||I d H  W 5 Q R X W 5 Q R X d S )Nz!can't send data after sending EOF)r*   Zdid_shutdown_SHUT_WRr!   r"   r'   r2   _send_remainder
memoryviewsendmsg
SOL_SOCKET
SCM_RIGHTSr>   )r3   r=   r9   sentr%   r%   r&   r<   ^   s    


  zDBusConnection._send_datar   c              	      sv   zJ|t |k rB||d  }| j|I d H }W 5 Q R X ||7 }qd | _W n& tjk
rp   ||d  | _ Y nX d S N)lenr*   r>   r2   r!   Z	Cancelled)r3   r=   Zalready_sent	remainingrD   r%   r%   r&   r?   q   s    

zDBusConnection._send_remainderreturnc                    s|   | j 4 I dH ^ | j }|dk	r8|W  5 Q I dH R  S |  I dH \}}|sXtd| j|| qW 5 Q I dH R X dS )z5Return the next available message from the connectionNzSocket closed at the other end)r1   r,   Zget_next_message
_read_datar!   ZEndOfChannelZadd_data)r3   msgbr9   r%   r%   r&   receive   s    

zDBusConnection.receivec              	      s   | j rp| j }t $ | j|t I d H \}}}}W 5 Q R X |ttjdd@ rb| 	  t
d|t|fS t  | jdI d H }W 5 Q R X |g fS d S )N
MSG_CTRUNCr   z&Unable to receive all file descriptorsi   )r+   r,   Zbytes_desiredr'   r*   recvmsgr   getattrr!   _closeRuntimeErrorr   Zfrom_ancdatarecv)r3   nbytesr=   Zancdataflags_r%   r%   r&   rJ      s    
 zDBusConnection._read_datac                 C   s   | j   d | _d S rE   )r*   closer2   r3   r%   r%   r&   rQ      s    
zDBusConnection._closec                    s   |    dS )zClose the D-Bus connectionN)rQ   rX   r%   r%   r&   aclose   s    zDBusConnection.aclosec              
   C  sZ   t  4 I dH :}t| }||I dH  z
|V  W 5 | I dH  X W 5 Q I dH R X dS )aY  Temporarily wrap this connection as a :class:`DBusRouter`

        To be used like::

            async with conn.router() as req:
                reply = await req.send_and_get_reply(msg)

        While the router is running, you shouldn't use :meth:`receive`.
        Once the router is closed, you can use the plain connection again.
        N)r!   Zopen_nursery
DBusRouterr)   rY   )r3   nurseryrouterr%   r%   r&   r\      s    
zDBusConnection.router)F)r   )__name__
__module____qualname____doc__r4   r   r>   bytesr<   r@   r?   rM   rJ   rQ   rY   r   r\   r%   r%   r%   r&   r(   ?   s   	

r(   SESSIONFr+   rH   c          	   
      s   t | }t|I dH }t|d}|D ](}||I dH  || I dH  q&|tI dH  t|j	|d}|
 4 I dH &}|t I dH }|jd |_W 5 Q I dH R X |S )zHOpen a plain D-Bus connection

    :return: :class:`DBusConnection`
    Nrc   r   )r   r!   Zopen_unix_socketr	   Zsend_allfeedZreceive_somer
   r(   r*   r\   send_and_get_replyr   ZHellobodyr.   )	busr+   Zbus_addrsockZauthrZreq_dataconnr\   replyr%   r%   r&   r      s    
c                       sF   e Zd Zed fddZedd Zdd Zdd	 Zd
d Z	  Z
S )TrioFilterHandle)filtersc                    s   t  ||| || _d S rE   )superr4   send_channel)r3   rl   ruleZsend_chnZrecv_chn	__class__r%   r&   r4      s    zTrioFilterHandle.__init__c                 C   s   | j S rE   queuerX   r%   r%   r&   receive_channel   s    z TrioFilterHandle.receive_channelc                    s   |    | j I d H  d S rE   )rW   rn   rY   rX   r%   r%   r&   rY      s    zTrioFilterHandle.aclosec                    s   | j S rE   rr   rX   r%   r%   r&   
__aenter__   s    zTrioFilterHandle.__aenter__c                    s   |   I d H  d S rE   )rY   )r3   exc_typeexc_valexc_tbr%   r%   r&   	__aexit__   s    zTrioFilterHandle.__aexit__)r]   r^   r_   r   r4   propertyrt   rY   ru   ry   __classcell__r%   r%   rp   r&   rk      s   
rk   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )Futurez4A very simple Future for trio based on `trio.Event`.c                 C   s   d | _ t | _d S rE   )_outcomer!   Event_eventrX   r%   r%   r&   r4      s    zFuture.__init__c                 C   s   t || _| j  d S rE   )r   r}   r   set)r3   resultr%   r%   r&   
set_result   s    
zFuture.set_resultc                 C   s   t || _| j  d S rE   )r   r}   r   r   )r3   r$   r%   r%   r&   set_exception   s    
zFuture.set_exceptionc                    s   | j  I d H  | j S rE   )r   waitr}   unwraprX   r%   r%   r&   get   s    z
Future.getN)r]   r^   r_   r`   r4   r   r   r   r%   r%   r%   r&   r|      s
   r|   c                   @   s   e Zd ZdZdZdZedddZedd Z	ddd	d
Z
edddZdddeej dddZejdddZdd ZedddZejfddZdS )rZ   zA client D-Bus connection which can wait for replies.

    This runs a separate receiver task and dispatches received messages.
    N)ri   c                 C   s   || _ t | _t | _d S rE   )_connr   _repliesr   _filters)r3   ri   r%   r%   r&   r4     s    zDBusRouter.__init__c                 C   s   | j jS rE   )r   r.   rX   r%   r%   r&   r.     s    zDBusRouter.unique_namer5   c                   s   | j j||dI dH  dS )z/Send a message, don't wait for a reply
        r5   N)r   r>   )r3   r7   r6   r%   r%   r&   r>     s    zDBusRouter.sendrH   c              
      sp   t | | jdkrtdt| jj}| j|t 0}| j	||dI dH  |
 I dH W  5 Q R  S Q R X dS )zSend a method call message and wait for the reply

        Returns the reply message (method return or error message type).
        NzThis DBusRouter has stoppedr5   )r   _rcv_cancel_scoper   r:   r   r-   r   Zcatchr|   r>   r   )r3   r7   r6   Z	reply_futr%   r%   r&   re     s    
zDBusRouter.send_and_get_replyr   )channelbufsize)r   c                C   s,   |dkrt |\}}nd}t| j|||S )a  Create a filter for incoming messages

        Usage::

            async with router.filter(rule) as receive_channel:
                matching_msg = await receive_channel.receive()

            # OR:
            send_chan, recv_chan = trio.open_memory_channel(1)
            async with router.filter(rule, channel=send_chan):
                matching_msg = await recv_chan.receive()

        If the channel fills up,
        The sending end of the channel is closed when leaving the ``async with``
        block, whether or not it was passed in.

        :param jeepney.MatchRule rule: Catch messages matching this rule
        :param trio.MemorySendChannel channel: Send matching messages here
        :param int bufsize: If no channel is passed in, create one with this size
        N)r!   Zopen_memory_channelrk   r   )r3   ro   r   r   Zrecv_channelr%   r%   r&   filter#  s    zDBusRouter.filter)r[   c                    s*   | j d k	rtd|| jI d H | _ d S )Nz+DBusRouter receiver task is already running)r   rR   r)   	_receiver)r3   r[   r%   r%   r&   r)   @  s    
zDBusRouter.startc                    s.   | j dk	r| j   d| _ tdI dH  dS )z Stop the sender & receiver tasksNr   )r   cancelr!   sleeprX   r%   r%   r&   rY   E  s    

zDBusRouter.aclose)rK   c              	   C   sN   | j |rdS | j|D ],}z|j| W q tjk
rF   Y qX qdS )zHandle one received messageN)r   dispatchr   matchesrn   Zsend_nowaitr!   Z
WouldBlock)r3   rK   r   r%   r%   r&   	_dispatchR  s    zDBusRouter._dispatchc                    s   t  }d| _|| z | j I dH }| | qW 5 d| _| j  t d.}| jj	 D ]}d|_
|j I dH  qdW 5 Q R X X W 5 Q R X dS )z'Receiver loop - runs in a separate taskTF   N)r!   ZCancelScope
is_runningstartedr   Zdrop_allZmove_on_afterr   rl   valuesshieldrn   rY   r   rM   r   )r3   Ztask_statusZcscopeZcleanup_scoper   rK   r%   r%   r&   r   ]  s    


zDBusRouter._receiver)r]   r^   r_   r`   Z_nursery_mgrr   r(   r4   rz   r.   r>   r   re   r   r!   ZMemorySendChannelr   ZNurseryr)   rY   r   ZTASK_STATUS_IGNOREDr   r%   r%   r%   r&   rZ      s   
rZ   c                       s(   e Zd ZdZ fddZdd Z  ZS )r   a  A trio 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 ~trio.DBusRouter router: Router to send and receive messages.
    c                    s(   t  | t|tstd|| _d S )Nz)Proxy can only be used with DBusRequester)rm   r4   
isinstancerZ   	TypeError_router)r3   Zmsggenr\   rp   r%   r&   r4   ~  s    
zProxy.__init__c                    s    fdd}|S )Nc                     s6    | |}|j jtjkstj|I d H }t|S rE   )headerZmessage_typer   method_callAssertionErrorr   re   r   )argskwargsrK   rj   make_msgr3   r%   r&   inner  s    
z!Proxy._method_call.<locals>.innerr%   )r3   r   r   r%   r   r&   _method_call  s    zProxy._method_call)r]   r^   r_   r`   r4   r   r{   r%   r%   rp   r&   r   s  s   
c                C  s\   t | |dI dH }|4 I dH . | 4 I dH }|V  W 5 Q I dH R X W 5 Q I dH R X dS )a  Open a D-Bus 'router' to send and receive messages.

    Use as an async context manager::

        async with open_dbus_router() as req:
            ...

    :param str bus: 'SESSION' or 'SYSTEM' or a supported address.
    :return: :class:`DBusRouter`

    This is a shortcut for::

        conn = await open_dbus_connection()
        async with conn:
            async with conn.router() as req:
                ...
    rc   N)r   r\   )rg   r+   ri   Zrtrr%   r%   r&   r     s    )rb   )rb   )5r;   
contextlibr   r   	itertoolsr   loggingtypingr   r   ImportErrorasync_generatoroutcomer   r   r!   Ztrio.abcr   Zjeepney.authr	   r
   Zjeepney.busr   Zjeepney.fdsr   r   Zjeepney.low_levelr   r   r   Zjeepney.wrappersr   r   Zjeepney.bus_messagesr   commonr   r   r   r   r   	getLoggerr]   log__all__r'   r(   r   rk   r|   rZ   r   r   r%   r%   r%   r&   <module>   sD   

~u