o `:@sddlZddlmZddlZddlmZddlZddlmZzddlm Z Wne y5ddl m Z Ynwddl m Z mZddlZddlmZddlmZmZdd lmZdd lmZmZdd lmZmZmZdd lmZm Z dd l!m"Z"ddl#m$Z$m%Z%m&Z&m'Z'm(Z(e)e*Z+gdZ,eddZ-GdddeZ.d%ddde.fddZ/Gddde%Z0GdddZ1Gdd d Z2Gd!d"d"eZ3e d%ddd#d$Z4dS)&N)contextmanager)count)Optional)asynccontextmanager)ValueError)Channel) AuthenticatorBEGIN)get_bus)FileDescriptor fds_buf_size)Parser MessageTypeMessage) ProxyBase unwrap_msg) message_bus)MessageFilters FilterHandle ReplyMatcher RouterClosedcheck_replyable)open_dbus_connectionopen_dbus_routerProxyc csXzdVWdSty+}z|jtjtjhvrtddtd||d}~ww)Nzthis socket was already closedzsocket connection broken: {})OSErrorerrnoEBADFENOTSOCKtrioClosedResourceErrorBrokenResourceErrorformat)excr&1/usr/lib/python3/dist-packages/jeepney/io/trio.py)_translate_socket_errors_to_stream_errors0s  r(c@s~eZdZdZdddZdddefdd Zd efd d Zdd e fddZ defddZ ddZ ddZ ddZeddZdS)DBusConnectionaA 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. FcCsD||_||_t|_tdd|_d|_t|_ t|_ d|_ dS)Nr)start) socket enable_fdsrparserroutgoing_serial unique_namer!Lock send_lock recv_lock_leftover_to_send)selfr+r,r&r&r'__init__Is    zDBusConnection.__init__Nserialmessagec s|j4IdH/|durt|j}|jrtdnd}|j||d}|||IdHWdIdHdS1IdHs=wYdS)z.Serialise and send a :class:`~.Message` objectNi)fds)r1nextr.r,array serialise _send_data)r4r8r7r:datar&r&r'sendSs .zDBusConnection.sendr?c s|jjr tdtY|jr||jIdHt|0}|r5|j|gtjj tjj |fgIdH}n |j |IdH}|||IdHWdn1sQwYWddSWddS1siwYdS)Nz!can't send data after sending EOF) r+did_shutdown_SHUT_WRr!r"r(r3_send_remainder memoryviewsendmsg SOL_SOCKET SCM_RIGHTSr@)r4r?r:sentr&r&r'r>^s"   "zDBusConnection._send_datarcsz5|t|kr1||d}|j|IdH}Wdn1s"wY||7}|t|ksd|_WdStjyF||d|_wN)lenr+r@r3r! Cancelled)r4r? already_sent remainingrGr&r&r'rBqs  zDBusConnection._send_remainderreturnc s|j4IdH/ |j}|dur|WdIdHS|IdH\}}|s/td|j||q 1IdHs=wYdS)z5Return the next available message from the connectionNTzSocket closed at the other end)r2r-get_next_message _read_datar! EndOfChanneladd_data)r4msgbr:r&r&r'receives  zDBusConnection.receivecs|jrC|j}t|j|tIdH\}}}}Wdn1s&wY|ttjdd@r<| t d|t |fSt|j dIdH}Wd|gfS1s]wY|gfS)N MSG_CTRUNCrz&Unable to receive all file descriptorsi)r,r- bytes_desiredr(r+recvmsgr getattrr!_close RuntimeErrorr from_ancdatarecv)r4nbytesr?ancdataflags_r&r&r'rOs$  zDBusConnection._read_datacCs|jd|_dSrH)r+closer3r4r&r&r'rYs  zDBusConnection._closecs|dS)zClose the D-Bus connectionN)rYrbr&r&r'acloses zDBusConnection.aclosec Cst4IdH-}t|}||IdHz |VW|IdHn|IdHwWdIdHdS1IdHsrCrBrTrOrYrcrrgr&r&r&r'r)?s   r)SESSIONFr,rMc st|}t|IdH}t|d}|D]}||IdH||IdHq|tIdHt|j |d}| 4IdH}| t IdH}|jd|_WdIdH|S1IdHsbwY|S)zHOpen a plain D-Bus connection :return: :class:`DBusConnection` Nrnr)r r!open_unix_socketr send_allfeed receive_somer r)r+rgsend_and_get_replyrHellobodyr/) busr,bus_addrsockauthrreq_dataconnrgreplyr&r&r'rs  rcsFeZdZdeffdd ZeddZddZdd Zd d Z Z S) TrioFilterHandlefilterscst|||||_dSrH)superr5 send_channel)r4r~rulesend_chnrecv_chn __class__r&r'r5s zTrioFilterHandle.__init__cCs|jSrHqueuerbr&r&r'receive_channelsz TrioFilterHandle.receive_channelcs||jIdHdSrH)rarrcrbr&r&r'rcszTrioFilterHandle.aclosecs|jSrHrrbr&r&r' __aenter__szTrioFilterHandle.__aenter__cs|IdHdSrH)rc)r4exc_typeexc_valexc_tbr&r&r' __aexit__szTrioFilterHandle.__aexit__) rhrirjrr5propertyrrcrr __classcell__r&r&rr'r}s r}c@s0eZdZdZddZddZddZdd Zd S) Futurez4A very simple Future for trio based on `trio.Event`.cCsd|_t|_dSrH)_outcomer!Event_eventrbr&r&r'r5szFuture.__init__cCt||_|jdSrH)rrrset)r4resultr&r&r' set_result zFuture.set_resultcCrrH)rrrr)r4r%r&r&r' set_exceptionrzFuture.set_exceptioncs|jIdH|jSrH)rwaitrunwraprbr&r&r'gets z Future.getN)rhrirjrkr5rrrr&r&r&r'rs  rc@seZdZdZdZdZdefddZeddZ ddd d Z d e fd d Z dddde ejfddZdejfddZddZde fddZejfddZdS)rezA client D-Bus connection which can wait for replies. This runs a separate receiver task and dispatches received messages. Nr{cCs||_t|_t|_dSrH)_connr_repliesr_filters)r4r{r&r&r'r5s zDBusRouter.__init__cCs|jjSrH)rr/rbr&r&r'r/ szDBusRouter.unique_namer6cs|jj||dIdHdS)z/Send a message, don't wait for a reply r6N)rr@)r4r8r7r&r&r'r@szDBusRouter.sendrMcs~t||jdurtdt|jj}|j|t}|j ||dIdH| IdHWdS1s8wYdS)zSend a method call message and wait for the reply Returns the reply message (method return or error message type). NzThis DBusRouter has stoppedr6) r_rcv_cancel_scoperr;rr.rcatchrr@r)r4r8r7 reply_futr&r&r'rss   $zDBusRouter.send_and_get_replyr)channelbufsizercCs,|dur t|\}}nd}t|j|||S)aCreate 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!open_memory_channelr}r)r4rrr recv_channelr&r&r'filter#szDBusRouter.filterrfcs,|jdur td||jIdH|_dS)Nz+DBusRouter receiver task is already running)rrZr* _receiver)r4rfr&r&r'r*@s zDBusRouter.startcs0|jdur|jd|_tdIdHdS)z Stop the sender & receiver tasksNr)rcancelr!sleeprbr&r&r'rcEs   zDBusRouter.acloserRc CsJ|j|rdS|j|D]}z|j|Wqtjy"YqwdS)zHandle one received messageN)rdispatchrmatchesr send_nowaitr! WouldBlock)r4rRrr&r&r' _dispatchRs zDBusRouter._dispatchcstK}d|_||z |jIdH}||qd|_|jt d}|j j D] }d|_ |jIdHq2Wdw1sJwYw1sSwYdS)z'Receiver loop - runs in a separate taskTNF)r! CancelScope is_runningstartedrrTrrdrop_all move_on_afterrr~valuesshieldrrc)r4 task_statuscscoperR cleanup_scoperr&r&r'r]s$     zDBusRouter._receiver)rhrirjrk _nursery_mgrrr)r5rr/r@rrsrr!MemorySendChannelrNurseryr*rcrTASK_STATUS_IGNOREDrr&r&r&r'res   recs(eZdZdZfddZddZZS)raA 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. cs(t|t|tstd||_dS)Nz)Proxy can only be used with DBusRequester)rr5 isinstancere TypeError_router)r4msggenrgrr&r'r5~s   zProxy.__init__csfdd}|S)Ncs<|i|}|jjtjusJj|IdH}t|SrH)header message_typer method_callrrsr)argskwargsrRr|make_msgr4r&r'inners z!Proxy._method_call..innerr&)r4rrr&rr' _method_callszProxy._method_call)rhrirjrkr5rrr&r&rr'rss rc Cst||dIdH}|4IdH-|4IdH}|VWdIdHn 1IdHs-wYWdIdHdS1IdHsCwYdS)aOpen 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: ... rnN)rrg)rvr,r{rtrr&r&r'rs*.r)rm)5r< contextlibrr itertoolsrloggingtypingrr ImportErrorasync_generatoroutcomerrr!trio.abcr jeepney.authr r jeepney.busr jeepney.fdsr r jeepney.low_levelrrrjeepney.wrappersrrjeepney.bus_messagesrcommonrrrrr getLoggerrhlog__all__r(r)rr}rrerrr&r&r&r'sB         ~u