o `$@s:dZddlmZddlmZddlZddlZddlmZddl Z ddl m Z m Z ddlmZmZddlmZdd lmZmZdd lmZdd lmZdd lmZmZd dlmZmZm Z m!Z!d dl"m#Z#m$Z$m%Z%m&Z&m'Z'gdZ(Gddde)Z*Gddde Z+d ddZ,GdddZ-GdddeZ.ed!ddZ/dS)"z+Synchronous IO wrappers with thread safety )Future)contextmanagerN) EVENT_READ)QueueFull)LockThread)Optional)Message MessageType)get_bus) message_bus) ProxyBase unwrap_msg) unwrap_read prep_socketDBusConnectionBasetimeout_to_deadline)MessageFilters FilterHandle ReplyMatcher RouterClosedcheck_replyable)open_dbus_connectionopen_dbus_routerDBusConnection DBusRouterProxyReceiveStoppedc@s eZdZdS)rN)__name__ __module__ __qualname__r#r#6/usr/lib/python3/dist-packages/jeepney/io/threading.pyr"srcspeZdZddejffdd ZddefddZdd d efd d Zdd dZddZ ddZ fddZ Z S)rFsockcsFtj||dt\|_|_|j|jt|_ t |_ t |_ dS)N) enable_fds) super__init__ospipe_stop_r_stop_wselectorregisterrstop_keyr send_lockrcv_lock)selfr%r& __class__r#r$r('s  zDBusConnection.__init__NmessagecCsj|||\}}|j |r|||n|j|WddSWddS1s.wYdS).Serialise and send a :class:`~.Message` objectN) _serialiser0_send_with_fdsr%sendall)r2r5serialdatafdsr#r#r$send.s"zDBusConnection.sendtimeoutreturncCsNt|}|jj|p ddstd|dz ||W|jS|jw)aReturn 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. If the connection is closed from another thread, this will raise ReceiveStopped. r>zDid not get receive lock in z seconds)rr1acquire TimeoutError_receiverelease)r2r?deadliner#r#r$receive7s   zDBusConnection.receivecCs`|j|D]'\}}||jkr$|jr|St|jdgfS||jkr-t dqt )Niz(DBus receive stopped from another thread) r-select select_keyr&_read_with_fdsrr%recvr/rrC)r2r?keyevr#r#r$_read_some_dataJs   zDBusConnection._read_some_datacCst|jddS)z;Make any threads waiting for a message raise ReceiveStoppedaN)r)writer,r2r#r#r$ interruptWszDBusConnection.interruptcCsF|jtf|jjddvr!t|jd|jtf|jjddvs dSdS)zAllow calls to .receive() again after .interrupt() To avoid race conditions, you should typically wait for threads to respond (e.g. by joining them) between interrupting and resetting. rr>iN)r/rr-rHr)readr+rQr#r#r$reset_interrupt[s zDBusConnection.reset_interruptcs|tdS)zClose the connectionN)rRr'closerQr3r#r$rUeszDBusConnection.close)FN) r r!r"socketr(r r=rGrNrRrTrU __classcell__r#r#r3r$r&s   rSESSIONF?cCsjt|}t|||d}t||}t|}tt|dd}|d|_Wd|S1s.wY|S)aROpen a plain D-Bus connection 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. :return: :class:`DBusConnection` r> rN)r rrrrr Hello unique_name)busr& auth_timeoutbus_addrr%connrouter reply_bodyr#r#r$rks     rc@seZdZdZdefddZeddZddd d Zdd d e d e fddZ ddZ ddZ ddZ ddddeefddZd e fddZddZdS)raUA client D-Bus connection which can wait for replies. This runs a separate receiver thread and dispatches received messages. It's possible to wrap a :class:`DBusConnection` in a router temporarily. Using the connection directly while it is wrapped is not supported, but you can use it again after the router is closed. racCs4||_t|_t|_t|jdd|_|jdS)NT)targetdaemon) rar_repliesr_filtersr _receiver _rcv_threadstart)r2rar#r#r$r(s zDBusRouter.__init__cCs|jjSrV)rar]rQr#r#r$r]szDBusRouter.unique_nameNr:cCs|jj||ddS)r6rkN)rar=)r2r5r:r#r#r$r=szDBusRouter.sendr>msgr@cCsvt||js tdt|jj}|j|t }|jj ||d|j |dWdS1s4wYdS)z7Send a method call message, wait for and return a replyzThis D-Bus router has stoppedrkr>N) rriis_alivernextraoutgoing_serialrfcatchrr=result)r2rlr?r: reply_futr#r#r$send_and_get_replys   $zDBusRouter.send_and_get_replycCs&|j|jjdd|jdS)zRClose this router This does not close the underlying connection. r[r>N)rarRrijoinrTrQr#r#r$rUs zDBusRouter.closecCs|SrVr#rQr#r#r$ __enter__szDBusRouter.__enter__cCs |dS)NF)rU)r2exc_typeexc_valexc_tbr#r#r$__exit__szDBusRouter.__exit__r)queuebufsizerzcCst|j||p t|dS)a}Create a filter for incoming messages Usage:: with router.filter(rule) as queue: matching_msg = queue.get() :param jeepney.MatchRule rule: Catch messages matching this rule :param queue.Queue queue: Matched messages will be added to this :param int bufsize: If no queue is passed in, create one with this size )maxsize)rrgr)r2rulerzr{r#r#r$filters zDBusRouter.filterc CsH|j|rdS|j|D]}z|j|Wqty!YqwdSrV)rfdispatchrgmatchesrz put_nowait QueueFull)r2rlr~r#r#r$ _dispatchs  zDBusRouter._dispatchcCsJzz |j}||qtyYnwW|jdS|jwrV)rarGrrrfdrop_all)r2rlr#r#r$rhs   zDBusRouter._receiver)r r!r"__doc__rr(propertyr]r=r rsrUruryr rr~rrhr#r#r#r$rs    rcs6eZdZdZddfdd ZddZdd ZZS) razA blocking proxy for calling D-Bus methods via a :class:`DBusRouter`. 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 ~threading.DBusRouter router: Router to send and receive messages :param float timeout: Default seconds to wait for a reply, or None for no limit Nr>cst|||_||_dSrV)r'r(_router_timeout)r2msggenrbr?r3r#r$r(s  zProxy.__init__cCs4|jdurdnd|j}d|jd|j|dS)Nz , timeout=zProxy(z, ))r_msggenr)r2extrar#r#r$__repr__szProxy.__repr__cstfdd}|S)NcsF|dj}|i|}|jjtjusJjj||d}t|S)Nrr>) poprheader message_typer method_callrrsr)argskwargsr?rlreplymake_msgr2r#r$inners z!Proxy._method_call..inner) functoolswraps)r2rrr#rr$ _method_callszProxy._method_call)r r!r"rr(rrrXr#r#r3r$rs rc csrt||d(}t| }|VWdn1swYWddSWddS1s2wYdS)aOpen a D-Bus 'router' to send and receive messages. Use as a context manager:: with open_dbus_router() as router: ... On leaving the ``with`` block, the connection will be closed. :param str bus: 'SESSION' or 'SYSTEM' or a supported address. :param bool enable_fds: Whether to enable passing file descriptors. :return: :class:`DBusRouter` )r^r&N)rr)r^r&rarbr#r#r$rs "r)rYFrZ)rYF)0rconcurrent.futuresr contextlibrrr) selectorsrrWrzrrr threadingrrtypingr jeepneyr r jeepney.busr jeepney.bus_messagesr jeepney.wrappersrrblockingrrrrcommonrrrrr__all__ Exceptionrrrrrrr#r#r#r$s0        EY&