~e{WdZddlmZddlmZddlmZddlmZddlmZddlm Z ddl m Z dd l m Z dd l m Z dd l mZdd l mZdd l mZddl mZddlmZddlmZddlmZGdde ZGddeZGdde ZGdde ZGddeZGddZGdde ZGd d!e Z Gd"d#Z!Gd$d%e Z"Gd&d'eZ#y())a<Expose the methods of a remote object over AMP. This module implements an AMP-based protocol for performing remote procedure calls in a convenient and easy way. It's conceptually similar to DBus in that it supports exposing a Python object to a remote process, with communication happening over any Twisted-supported transport, e.g. Unix domain sockets. For example let's say we have a Python process "A" that creates an instance of this class:: class Greeter(object): def hello(self, name): return f"hi {name}!" greeter = Greeter() Process A can "publish" the greeter object by defining which methods are exposed remotely and opening a Unix socket for incoming connections:: factory = MethodCallServerFactory(greeter, ["hello"]) reactor.listenUNIX("/some/socket/path", factory) Then a second Python process "B" can connect to that socket and build a "remote" greeter object, i.e. a proxy that forwards method calls to the real greeter object living in process A:: factory = MethodCallClientFactory() reactor.connectUNIX("/some/socket/path", factory) def got_remote(remote_greeter): deferred = remote_greeter.hello("Ted") deferred.addCallback(lambda result: ... # result == "hi Ted!") factory.getRemoteObject().addCallback(got_remote) Note that when invoking a method via the remote proxy, the parameters are required to be serializable with bpickle, so they can be sent over the wire. See also:: http://twistedmatrix.com/documents/current/core/howto/amp.html for more details about the Twisted AMP protocol. )uuid4)Deferred) maybeDeferred)succeed)ReconnectingClientFactory) ServerFactory)AMP)Argument)Command)CommandLocator)Integer)MAX_VALUE_LENGTH)String)xrange)Failure)bpicklec,eZdZdZdZdZedZy)MethodCallArgumentzA bpickle-compatible argument.c,tj|S)zSerialize an argument.)rdumps)selfinobjects 3/usr/lib/python3/dist-packages/landscape/lib/amp.pytoStringzMethodCallArgument.toStringF}}X&&c,tj|S)zUnserialize an argument.)rloads)rinstrings r fromStringzMethodCallArgument.fromStringJrrc8t|tjvS)z%Check if an argument is serializable.)typer dumps_table)clsrs rcheckzMethodCallArgument.checkNsH~!4!444rN)__name__ __module__ __qualname____doc__rr classmethodr%rrrrCs#(''55rrceZdZdZy)MethodCallErrorz*Raised when a L{MethodCall} command fails.N)r&r'r(r)r+rrr-r-Ts4rr-c`eZdZdZdefdefdefgZdefgZe diZ y) MethodCallaCall a method on the object exposed by a L{MethodCallServerFactory}. The command arguments have the following semantics: - C{sequence}: An integer uniquely indentifying a the L{MethodCall} being issued. The name 'sequence' is a bit misleading because it's really a uuid, since its values in practice are not in sequential order, they are just random values. The name is kept just for backward compatibility. - C{method}: The name of the method to invoke on the remote object. - C{arguments}: A BPickled binary tuple of the form C{(args, kwargs)}, where C{args} are the positional arguments to be passed to the method and C{kwargs} the keyword ones. sequencesmethods argumentsresultMETHOD_CALL_ERRORN) r&r'r(r)r r argumentsrresponser-errorsr+rrr/r/XsL$ gi FH vx I .012H3 4Frr/cPeZdZdZdefdefgZdefgZediZ y)MethodCallChunkaSend a chunk of L{MethodCall} containing a portion of the arguments. When a the arguments of a L{MethodCall} are bigger than 64k, they get split in several L{MethodCallChunk}s that are buffered on the receiver side. The command arguments have the following semantics: - C{sequence}: The unique integer associated with the L{MethodCall} that this L{MethodCallChunk} is part of. - C{chunk}: A portion of the big BPickle C{arguments} string which is being split and buffered. r0schunkr1r2N) r&r'r(r)r rr3r4r-r5r+rrr7r7us; wy)Hfh+?@IGI&'H3 4Frr7cdeZdZdZdZej dZej dZ dZ y)MethodCallReceiverzExpose methods of a local object over AMP. @param obj: The Python object to be exposed. @param methods: The list of the object's methods that can be called remotely. cXtj|||_||_i|_yN)r __init___object_methods_pending_chunksrobjmethodss rr<zMethodCallReceiver.__init__s&%  !rcjj|d}|"|j|dj|}t j |d\}}|j d}|jvrtd|dtj|}fd}d } t|g|i|} | j|| j| | S) aCall an object's method with the given arguments. If a connected client sends a L{MethodCall} for method C{foo_bar}, then the actual method C{foo_bar} of the object associated with the protocol will be called with the given C{args} and C{kwargs} and its return value delivered back to the client as response to the command. @param sequence: The integer that uniquely identifies the L{MethodCall} being received. @param method: The name of the object's method to call. @param arguments: A bpickle'd binary tuple of (args, kwargs) to be passed to the method. In case this L{MethodCall} has been preceded by one or more L{MethodCallChunk}s, C{arguments} is the last chunk of data. NrT)as_isutf-8zForbidden method ''c*dj|iSNresult) _check_result)rIrs r handle_resultz=MethodCallReceiver.receive_method_call..handle_resultsd0089 9rc,t|jr;)r-value)failures rhandle_failurez>MethodCallReceiver.receive_method_call..handle_failures!'--0 0r)r?popappendjoinrrdecoder>r-getattrr=r addCallback addErrback) rsequencemethodr3chunksargskwargs method_funcrKrOdeferreds ` rreceive_method_callz&MethodCallReceiver.receive_method_calls"%%))(D9   MM) $(I}}Yd; fw'  &!$6vha"@A AdllF3  : 1!>t>v>]+N+rc`|jj|gj|d|iS)zReceive a part of a multi-chunk L{MethodCall}. Add the received C{chunk} to the buffer of the L{MethodCall} identified by C{sequence}. rI)r? setdefaultrQ)rrWchunks rreceive_method_call_chunkz,MethodCallReceiver.receive_method_call_chunks0 ''"5<.handle_responses(;;= KKM   h 'rc:jtdy)Ntimeout)errbackr-r]srhandle_timeoutzBMethodCallSender._call_remote_with_timeout..handle_timeouts   _Y7 8r)rrj callLaterruri callRemoteaddBoth)rcommandr[rsrxrIrrr]s @@r_call_remote_with_timeoutz*MethodCallSender._call_remote_with_timeouts^: ( 9{{$$T\\>B***7=f='rc tj||f}tj j dt dt |jDcgc]}|||jzc} t}t dkDr' ddD]}fd}|j| |!  fd} |j| |jd|jd|Scc}w) aSend a L{MethodCall} command with the given arguments. If a response from the server is not received within C{self.timeout} seconds, the returned deferred will errback with a L{MethodCallError}. @param method: The name of the remote method to invoke. @param args: The positional arguments to pass to the remote method. @param kwargs: The keyword arguments to pass to the remote method. @return: A C{Deferred} firing with the return value of the method invoked on the remote object. If the remote method itself returns a deferred, we fire with the callback value of such deferred. rErNcfd}|S)NcHjjtS)N)rWra)rirzr7)xrarrWs r send_chunkzPMethodCallSender.send_method_call..create_send_chunk..send_chunk&s(#~~88+%-"' 9 rr+)rWrarrs`` rcreate_send_chunkz.create_send_chunk%s&%rc@d}jt|S)Nr)rWrXr3)r}r/)ignoredrarYrXrrWs rsend_last_chunkz:MethodCallSender.send_method_call..send_last_chunk1s02JE11! 2 rc |dSrHr+)r4s rz3MethodCallSender.send_method_call..;s HX,>r) rrrintencoderlen _chunk_sizerrUrq) rrXrZr[r3irIrarrrYrWs `` @@rsend_method_callz!MethodCallSender.send_method_callsMM4.1 7;;w' As9~t/?/?@  a!d... /   v;? G&""#4Xu#EF G  ?+>? E s#C<N) r&r'r(r)rurrr<r}rr+rrrfrfs)G"K6-/r6rrfceZdZdZdZy)MethodCallServerProtocolzCReceive L{MethodCall} commands over the wire and send back results.cFtj|t||y)N)locator)r r<r9r@s rr<z!MethodCallServerProtocol.__init__Cs T#5c7#CDrN)r&r'r(r)r<r+rrrr@s MErrceZdZdZdZdZy)MethodCallClientProtocolzASend L{MethodCall} commands over the wire using the AMP protocol.NcT|j|jj|yy)z*Notify our factory that we're ready to go.N)factoryclientConnectionMade)rs rconnectionMadez'MethodCallClientProtocol.connectionMadeLs# << # LL - -d 3 $r)r&r'r(r)rrr+rrrrGsKG4rrcBeZdZdZdZdZd dZd dZ d dZdZ d Z y) RemoteObjectaAn object able to transparently call methods on a remote object. Any method call on a L{RemoteObject} instance will return a L{Deferred} resulting in the return value of the same method call performed on the remote object exposed by the peer. cxd|_i|_||_|jj|jy)z @param factory: The L{MethodCallClientFactory} used for connecting to the other peer. Look there if you need to tweak the behavior of this L{RemoteObject}. N)_sender_pending_requests_factorynotifyOnConnect_handle_connect)rrs rr<zRemoteObject.__init__Zs2  !#  %%d&:&:;rcfd}|S)a^Return a function sending a L{MethodCall} for the given C{method}. When the created function is called, it sends the an appropriate L{MethodCall} to the remote peer passing it the arguments and keyword arguments it was called with, and returning a L{Deferred} resulting in the L{MethodCall}'s response value. cDt}j||||Sr;)r_send_method_call)rZr[r]rXrs rrz2RemoteObject.__getattr__..send_method_callns#zH  " "64 BOrr+)rrXrs`` r __getattr__zRemoteObject.__getattr__es   rNc4|jj|||}|j|j|||j |j ||||||j j%|j jjyy)zASend a L{MethodCall} command, adding callbacks to handle retries.)rXrZr[rrN) rrrU_handle_resultrV_handle_failurerfake_connectionflush)rrXrZr[r]rrrIs rrzRemoteObject._send_method_callus../  4..tD        == ( ( 4 MM ) ) / / 1 5rcJ||j|j|y)a&Handles a successful C{send_method_call} result. @param response: The L{MethodCall} response. @param deferred: The deferred that was returned to the caller. @param call: If not C{None}, the scheduled timeout call associated with the given deferred. N)rprq)rrIr]rrs rrzRemoteObject._handle_results!   KKM&!rc  |jtu}|jjdu}|s|rM||jvr|jj ||r|j |j|y|jjr`|^ttd} |jjj|jj|j| ||||}||||f|j|<y)a+Called when a L{MethodCall} command fails. If a failure is due to a connection error and if C{retry_on_reconnect} is C{True}, we will try to perform the requested L{MethodCall} again as soon as a new connection becomes available, giving up after the specified C{timeout}, if any. @param failure: The L{Failure} raised by the requested L{MethodCall}. @param name: The method name associated with the failed L{MethodCall}. @param args: The positional arguments of the failed L{MethodCall}. @param kwargs: The keyword arguments of the failed L{MethodCall}. @param deferred: The deferred that was returned to the caller. @param call: If not C{None}, the scheduled timeout call associated with the given deferred. FNrurw) r"r-rretryOnReconnectrrPrprv retryTimeoutrrlryr) rrNrXrZr[r]rris_method_call_error dont_retryrus rrzRemoteObject._handle_failures0 '||>]]33u< : 4111&&**84   W %  == % %$,oi89G==&&00 **$$!1D-3D&$+Gx(rct||jj|_|jjr|j yy)zaHandles a reconnection. @param protocol: The newly connected protocol instance. N)rfrrlrr_retry)rrks rrzRemoteObject._handle_connects7 ($--2E2EF == ) ) KKM *rc|jj}|jj|r2|j\}\}}}}|j ||||||r1yy)z*Try to perform again requests that failed.rN)rcopyclearpopitemr)rrequestsr]rXrZr[rrs rrzRemoteObject._retrysg))..0 $$&5=5E5E5G 2H2vtVT  " "64 " Mrr;) r&r'r(r)r<rrrrrrr+rrrrRs2 < 20 "&5Hn Nrrc eZdZdZeZdZdZy)MethodCallServerFactoryz@Expose a Python object using L{MethodCall} commands over C{AMP}.c ||_||_y)a @param object: The object exposed by the L{MethodCallProtocol}s instances created by this factory. @param methods: A list of the names of the methods that remote peers are allowed to call on the C{object} that we publish. N)objectrBr@s rr<z MethodCallServerFactory.__init__s  rc`|j|j|j}||_|Sr;)rkrrBrraddrrks r buildProtocolz%MethodCallServerFactory.buildProtocols'==dll;rN)r&r'r(r)rrkr<rr+rrrrsJ'Hrrc\eZdZdZdZdZeZeZ dZ dZ dZ dZ dZdZd Zd Zd Zd Zd Zy)MethodCallClientFactorya Factory for L{MethodCallClientProtocol}s exposing an object or connecting to L{MethodCall} servers. When used to connect, if the connection fails or is lost the factory will keep retrying to establish it. @ivar factor: The time factor by which the delay between two subsequent connection retries will increase. @ivar maxDelay: Maximum number of seconds between connection attempts. @ivar protocol: The factory used to build protocol instances. @ivar remote: The factory used to build remote object instances. @ivar retryOnReconnect: If C{True}, the remote object returned by the C{getRemoteObject} method will retry requests that failed, as a result of a lost connection, as soon as a new connection is available. @param retryTimeout: A timeout for retrying requests, if the remote object can't perform them again successfully within this number of seconds, they will errback with a L{MethodCallError}. gw?FNc^||_|j|_g|_g|_d|_y)z @param object: The object exposed by the L{MethodCallProtocol}s instances created by this factory. @param reactor: The reactor used by the created protocols to schedule notifications and timeouts. N)rl initialDelaydelay _connects _requests_remote)rrls rr<z MethodCallClientFactory.__init__!s- &&  rc|jt|jSt}|jj ||S)zGet a L{RemoteObject} as soon as the connection is ready. @return: A C{Deferred} firing with a connected L{RemoteObject}. )rrrrrQ)rr]s rgetRemoteObjectz'MethodCallClientFactory.getRemoteObject.s; << #4<<( (: h'rc:|jj|y)zAInvoke the given C{callback} when a connection is re-established.N)rrQrrqs rrz'MethodCallClientFactory.notifyOnConnect9 h'rc:|jj|y)z,Remove the given C{callback} from listeners.N)rremovers rdontNotifyOnConnectz+MethodCallClientFactory.dontNotifyOnConnect=rrc|j|j||_|jD] }|| |j|jy)z2Called when a newly built protocol gets connected.N)rremoter_fire_requests)rrkrqs rrz,MethodCallClientFactory.clientConnectionMadeAsK << ;;t,DL H X   DLL)rcntj||||j|j|yy)z0Try to connect again or errback pending request.N)rclientConnectionFailed_callIDr)r connectorreasons rrz.MethodCallClientFactory.clientConnectionFailedMs8!88    <<     ' rcR|jtj||}|Sr;) resetDelayrrrs rrz%MethodCallClientFactory.buildProtocolXs# ,::4Frc`|jdd}g|_|D]}|j|y)zY Fire all pending L{getRemoteObject} deferreds with the given C{result}. N)rrq)rrIrr]s rrz&MethodCallClientFactory._fire_requests]s6>>!$  &H   f % &r)r&r'r(r)factormaxDelayrrkrrrrrr<rrrrrrrr+rrrrsW( FH'H FL O  (( * ( &rrN)$r)uuidrtwisted.internet.deferrrrtwisted.internet.protocolrrtwisted.protocols.ampr r r r r rrtwisted.python.compatrtwisted.python.failurer landscape.librr Exceptionr-r/r7r9rfrrrrrr+rrrs-\+0*?3%*)0)2((*!55"5i555:5g5,MM`bbJEsE4s4SNSNlm*h&7h&r