ϪfzdZddlmZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z ddlmZdd lmZmZmZmZmZmZmZmZmZmZdd lmZmZdd lmZm Z m!Z!dd l"m#Z#m$Z$m%Z%dd l&m'Z'ddl(m)Z)ddl*m+Z+ddl,m-Z-m.Z.ddl/m0Z0m1Z1ddl2m3Z4m5Z6ddl7m8Z8ddl9m:Z:ddl;mZ?e?jr ddlAmBZBmCZCmDZDmEZEndZ>e?Z>gdZGededeHfZIdZJdZKdZLdZMd ZNd!ZOd"ZPd#ZQd$ZRd%ZSGd&d'eZTGd(d)eZUGd*d+eZVGd,d-eZWGd.d/eXZYGd0d1eXZZGd2d3eYZ[Gd4d5eYZ\Gd6d7eYZ]Gd8d9eYZ^Gd:d;eYZ_Gd<d=eYZ`Gd>d?e`ZaGd@dAeYZbGdBdCeYZcGdDdEeYZdeQeciZeGdFdGeefeffZgegZhGdHdIegZiGdJdKegZjeeVGdLdMZkGdNdOelZmeeWGdPdQemRZneeWGdSdTZogdUZpdVZqeeTGdWdXZrGdYdZerZsGd[d\erZtGd]d^erZuGd_d`erZvGdadbetZwGdcddewZxGdedferZyGdgdherZzGdidjesZ{edkZ|GdldmelZ}Gdndoe}RZ~GdpdqZGdrdsegZGdtduetZGdvdwe~ZGdxdye~Zee'Gdzd{ZeeUGd|d}e.e-eZGd~deekeneoZGddZejZejZdZdZGdderZGdderZy#eF$rdZ>YwxYw)a This module implements AMP, the Asynchronous Messaging Protocol. AMP is a protocol for sending multiple asynchronous request/response pairs over the same connection. Requests and responses are both collections of key/value pairs. AMP is a very simple protocol which is not an application. This module is a "protocol construction kit" of sorts; it attempts to be the simplest wire-level implementation of Deferreds. AMP provides the following base-level features: - Asynchronous request/response handling (hence the name) - Requests and responses are both key/value pairs - Binary transfer of all data: all data is length-prefixed. Your application will never need to worry about quoting. - Command dispatching (like HTTP Verbs): the protocol is extensible, and multiple AMP sub-protocols can be grouped together easily. The protocol implementation also provides a few additional features which are not part of the core wire protocol, but are nevertheless very useful: - Tight TLS integration, with an included StartTLS command. - Handshaking to other protocols: because AMP has well-defined message boundaries and maintains all incoming and outgoing requests for you, you can start a connection over AMP and then switch to another protocol. This makes it ideal for firewall-traversal applications where you may have only one forwarded port but multiple applications that want to use it. Using AMP with Twisted is simple. Each message is a command, with a response. You begin by defining a command type. Commands specify their input and output in terms of the types that they expect to see in the request and response key-value pairs. Here's an example of a command that adds two integers, 'a' and 'b':: class Sum(amp.Command): arguments = [('a', amp.Integer()), ('b', amp.Integer())] response = [('total', amp.Integer())] Once you have specified a command, you need to make it part of a protocol, and define a responder for it. Here's a 'JustSum' protocol that includes a responder for our 'Sum' command:: class JustSum(amp.AMP): def sum(self, a, b): total = a + b print 'Did a sum: %d + %d = %d' % (a, b, total) return {'total': total} Sum.responder(sum) Later, when you want to actually do a sum, the following expression will return a L{Deferred} which will fire with the result:: ClientCreator(reactor, amp.AMP).connectTCP(...).addCallback( lambda p: p.callRemote(Sum, a=13, b=81)).addCallback( lambda result: result['total']) Command responders may also return Deferreds, causing the response to be sent only once the Deferred fires:: class DelayedSum(amp.AMP): def slowSum(self, a, b): total = a + b result = defer.Deferred() reactor.callLater(3, result.callback, {'total': total}) return result Sum.responder(slowSum) This is transparent to the caller. You can also define the propagation of specific errors in AMP. For example, for the slightly more complicated case of division, we might have to deal with division by zero:: class Divide(amp.Command): arguments = [('numerator', amp.Integer()), ('denominator', amp.Integer())] response = [('result', amp.Float())] errors = {ZeroDivisionError: 'ZERO_DIVISION'} The 'errors' mapping here tells AMP that if a responder to Divide emits a L{ZeroDivisionError}, then the other side should be informed that an error of the type 'ZERO_DIVISION' has occurred. Writing a responder which takes advantage of this is very simple - just raise your exception normally:: class JustDivide(amp.AMP): def divide(self, numerator, denominator): result = numerator / denominator print 'Divided: %d / %d = %d' % (numerator, denominator, total) return {'result': result} Divide.responder(divide) On the client side, the errors mapping will be used to determine what the 'ZERO_DIVISION' error means, and translated into an asynchronous exception, which can be handled normally as any L{Deferred} would be:: def trapZero(result): result.trap(ZeroDivisionError) print "Divided by zero: returning INF" return 1e1000 ClientCreator(reactor, amp.AMP).connectTCP(...).addCallback( lambda p: p.callRemote(Divide, numerator=1234, denominator=0) ).addErrback(trapZero) For a complete, runnable example of both of these commands, see the files in the Twisted repository:: doc/core/examples/ampserver.py doc/core/examples/ampclient.py On the wire, AMP is a protocol which uses 2-byte lengths to prefix keys and values, and empty keys to separate messages:: <2-byte length><2-byte length> <2-byte length><2-byte length> ... <2-byte length><2-byte length> # Empty Key == End of Message And so on. Because it's tedious to refer to lengths and NULs constantly, the documentation will refer to packets as if they were newline delimited, like so:: C: _command: sum C: _ask: ef639e5c892ccb54 C: a: 13 C: b: 81 S: _answer: ef639e5c892ccb54 S: total: 94 Notes: In general, the order of keys is arbitrary. Specific uses of AMP may impose an ordering requirement, but unless this is specified explicitly, any ordering may be generated and any ordering must be accepted. This applies to the command-related keys I{_command} and I{_ask} as well as any other keys. Values are limited to the maximum encodable size in a 16-bit length, 65535 bytes. Keys are limited to the maximum encodable size in a 8-bit length, 255 bytes. Note that we still use 2-byte lengths to encode keys. This small redundancy has several features: - If an implementation becomes confused and starts emitting corrupt data, or gets keys confused with values, many common errors will be signalled immediately instead of delivering obviously corrupt packets. - A single NUL will separate every key, and a double NUL separates messages. This provides some redundancy when debugging traffic dumps. - NULs will be present at regular intervals along the protocol, providing some padding for otherwise braindead C implementations of the protocol, so that string functions will see the NUL and stop. - This makes it possible to run an AMP server on a port also used by a plain-text protocol, and easily distinguish between non-AMP clients (like web browsers) which issue non-NUL as the first byte, and AMP clients, which always issue NUL as the first byte. @var MAX_VALUE_LENGTH: The maximum length of a message. @type MAX_VALUE_LENGTH: L{int} @var ASK: Marker for an Ask packet. @type ASK: L{bytes} @var ANSWER: Marker for an Answer packet. @type ANSWER: L{bytes} @var COMMAND: Marker for a Command packet. @type COMMAND: L{bytes} @var ERROR: Marker for an AMP box of error type. @type ERROR: L{bytes} @var ERROR_CODE: Marker for an AMP box containing the code of an error. @type ERROR_CODE: L{bytes} @var ERROR_DESCRIPTION: Marker for an AMP box containing the description of the error. @type ERROR_DESCRIPTION: L{bytes} ) annotationsN)partial)BytesIO)count)pack) MethodType) AnyCallableClassVarDictListOptionalTupleTypeTypeVarUnion) Interface implementer)Deferredfail maybeDeferred)ConnectionClosedConnectionLostPeerVerifyError)IFileDescriptorReceiver)CONNECTION_LOST)Protocol)Int16StringReceiverStatefulStringProtocol)filepathlog)UTCFixedOffsetTimeZone) nativeString)Failure)accumulateClassDict)ssl)DN CertificateCertificateOptionsKeyPair)5AMPANSWERASKAmpBoxAmpErrorAmpListArgumentBadLocalReturnBinaryBoxProtocolBooleanBox BoxDispatcherCOMMANDCommandCommandLocatorDecimal DescriptorERROR ERROR_CODEERROR_DESCRIPTIONFloat IArgumentType IBoxReceiver IBoxSenderIResponderLocatorIncompatibleVersionsIntegerInvalidSignatureListOfMAX_KEY_LENGTHMAX_VALUE_LENGTHMalformedAmpBox NoEmptyBoxes OnlyOneTLSPROTOCOL_ERRORSPYTHON_KEYWORDSPathProtocolSwitchCommandProtocolSwitchedQuitBoxRemoteAmpErrorSimpleStringLocatorStartTLSStringTooLongUNHANDLED_ERROR_CODEUNKNOWN_ERROR_CODEUnhandledCommandutcUnicodeUnknownRemoteErrorparse parseString _T_Callable.)bounds_asks_answers_commands_errors _error_codes_error_descriptionsUNKNOWNs UNHANDLEDceZdZdZdZdZy)rAz An L{IArgumentType} can serialize a Python object into an AMP box and deserialize information from an AMP box back into a Python object. @since: 9.0 cy)a Given an argument name and an AMP box containing serialized values, extract one or more Python objects and add them to the C{objects} dictionary. @param name: The name associated with this argument. Most commonly this is the key which can be used to find a serialized value in C{strings}. @type name: C{bytes} @param strings: The AMP box from which to extract one or more values. @type strings: C{dict} @param objects: The output dictionary to populate with the value for this argument. The key used will be derived from C{name}. It may differ; in Python 3, for example, the key will be a Unicode/native string. See L{_wireNameToPythonIdentifier}. @type objects: C{dict} @param proto: The protocol instance which received the AMP box being interpreted. Most likely this is an instance of L{AMP}, but this is not guaranteed. @return: L{None} Nnamestringsobjectsprotos 7/usr/lib/python3/dist-packages/twisted/protocols/amp.pyfromBoxzIArgumentType.fromBoxIcy)a= Given an argument name and a dictionary containing structured Python objects, serialize values into one or more strings and add them to the C{strings} dictionary. @param name: The name associated with this argument. Most commonly this is the key in C{strings} to associate with a C{bytes} giving the serialized form of that object. @type name: C{bytes} @param strings: The AMP box into which to insert one or more strings. @type strings: C{dict} @param objects: The input dictionary from which to extract Python objects to serialize. The key used will be derived from C{name}. It may differ; in Python 3, for example, the key will be a Unicode/native string. See L{_wireNameToPythonIdentifier}. @type objects: C{dict} @param proto: The protocol instance which will send the AMP box once it is fully populated. Most likely this is an instance of L{AMP}, but this is not guaranteed. @return: L{None} Nrgrhs rmtoBoxzIArgumentType.toBoxerorpN)__name__ __module__ __qualname____doc__rnrrrgrprmrArAAs 8 rprAceZdZdZdZdZy)rCz7 A transport which can send L{AmpBox} objects. cy)z Send an L{AmpBox}. @raise ProtocolSwitched: if the underlying protocol has been switched. @raise ConnectionLost: if the underlying connection has already been lost. Nrgboxs rmsendBoxzIBoxSender.sendBoxrorpcy)z An unhandled error occurred in response to a box. Log it appropriately. @param failure: a L{Failure} describing the error that occurred. Nrg)failures rmunhandledErrorzIBoxSender.unhandledErrorrorpN)rsrtrurvr{r~rgrprmrCrCs   rprCc"eZdZdZdZdZdZy)rBzh An application object which can receive L{AmpBox} objects and dispatch them appropriately. cy)z The L{IBoxReceiver.ampBoxReceived} method will start being called; boxes may be responded to by responding to the given L{IBoxSender}. @param boxSender: an L{IBoxSender} provider. Nrg boxSenders rmstartReceivingBoxesz IBoxReceiver.startReceivingBoxesrorpcy)zS A box was received from the transport; dispatch it appropriately. Nrgrys rmampBoxReceivedzIBoxReceiver.ampBoxReceivedrorpcy)zi No further boxes will be received on this connection. @type reason: L{Failure} Nrg)reasons rmstopReceivingBoxeszIBoxReceiver.stopReceivingBoxesrorpN)rsrtrurvrrrrgrprmrBrBs    rprBceZdZdZdZy)rDze An application object which can look up appropriate responder methods for AMP commands. cy)a Locate a responder method appropriate for the named command. @param name: the wire-level name (commandName) of the AMP command to be responded to. @type name: C{bytes} @return: a 1-argument callable that takes an L{AmpBox} with argument values for the given command, and returns an L{AmpBox} containing argument values for the named command, or a L{Deferred} that fires the same. Nrg)ris rmlocateResponderz!IResponderLocator.locateResponderrorpN)rsrtrurvrrgrprmrDrDs   rprDceZdZdZy)r0z3 Base class of all Amp-related exceptions. Nrsrtrurvrgrprmr0r0rpr0ceZdZdZy)rRz Connections which have been switched to other protocols can no longer accept traffic at the AMP level. This is raised when you try to send it. NrrgrprmrRrRrprRceZdZdZy)rMz` This is an implementation limitation; TLS may only be started once per connection. NrrgrprmrMrMrrprMceZdZdZy)rLzt You can't have empty boxes on the connection. This is raised when you receive or attempt to send one. NrrgrprmrLrLrrprLceZdZdZy)rGz5 You didn't pass all the required arguments. NrrgrprmrGrGrrprGc eZdZdZddZddZy)rXa One of the protocol's length limitations was violated. @ivar isKey: true if the string being encoded in a key position, false if it was in a value position. @ivar isLocal: Was the string encoded locally, or received too long from the network? (It's only physically possible to encode "too long" values on the network for keys.) @ivar value: The string that was too long. @ivar keyName: If the string being encoded was in a value position, what key was it being encoded for? Ncftj|||_||_||_||_yN)r0__init__isKeyisLocalvaluekeyName)selfrrrrs rmrzTooLong.__init__s,$    rpc|jxrdxsd}|js|dt|jzz }|jxrdxsd}d||t |j fzS)Nkeyr localremotez%s %s too long: %d)rreprrrlenr)rhdrlcls rm__repr__zTooLong.__repr__sajj"U-gzz 3dll++ +Cll&w2(#sCTZZ&AAArprreturnstr)rsrtrurvrrrgrprmrXrXs BrprXc$eZdZdZddZddZeZy)r3zU A bad value was returned from a local command; we were unable to coerce it. cJtj|||_||_yr)r0rmessageenclosed)rrrs rmrzBadLocalReturn.__init__s$   rpcV|jdz|jjzS)Nr)rrgetBriefTracebackrs rmrzBadLocalReturn.__repr__s#||c!DMM$C$C$EEErpN)rrrr%rNoner)rsrtrurvrr__str__rgrprmr3r3 s! FGrpr3c$eZdZdZdfd ZxZS)rTz This error indicates that something went wrong on the remote end of the connection, and the error was serialized and transmitted to you. c|rd}|j}nd}d}djd|D}|rdj||||}ndj|||}t ||||_||_||_||_y)aCreate a remote error with an error code and description. @param errorCode: the AMP error code of this error. @type errorCode: C{bytes} @param description: some text to show to the user. @type description: C{str} @param fatal: a boolean, true if this error should terminate the connection. @param local: a local Failure, if one exists. z (local)c3HK|]}|dk\rd|dn t|yw)z\x2xN)chr).0cs rm z*RemoteAmpError.__init__..8s,& 67AIc!BL3q6 1& s "zCode<{}>{}: {} {}zCode<{}>{}: {}N) rjoinformatsuperrr errorCode descriptionfatal) rrrrr localwhatothertberrorCodeForMessager __class__s rmrzRemoteAmpError.__init__!s "I--/GIG!gg& ;D&   *11# G'--#Y G ! "& rp)FN)rsrtrurvr __classcell__rs@rmrTrTs ++rprTceZdZdZdZy)r^zc This means that an error whose type we can't identify was raised from the other side. c>t}tj|||yr)rZrTr)rrrs rmrzUnknownRemoteError.__init__Us& i=rpN)rsrtrurvrrgrprmr^r^Os  >rpr^ceZdZdZy)rKzJ This error indicates that the wire-level protocol was malformed. NrrgrprmrKrKZrrprKceZdZdZy)r[z= A command received via amp could not be dispatched. Nrrgrprmr[r[`rrpr[ceZdZdZy)rEzw It was impossible to negotiate a compatible version of the protocol with the other end of the connection. NrrgrprmrErEfrrprEcLeZdZUdZgZded<fdZdZdZdZ d dZ xZ S) r/z\ I am a packet in the AMP protocol, much like a regular bytes:bytes dictionary. List[str] __slots__ct||i||Dcgc]}t|tr|}}|D]'}|j d}|j |||<)ycc}w)a  Initialize a new L{AmpBox}. In Python 3, keyword arguments MUST be Unicode/native strings whereas in Python 2 they could be either byte strings or Unicode strings. However, all keys of an L{AmpBox} MUST be byte strings, or possible to transparently coerce into byte strings (i.e. Python 2). In Python 3, therefore, native string keys are coerced to byte strings by encoding as ASCII. This can result in C{UnicodeEncodeError} being raised. @param args: See C{dict}, but all keys and values should be C{bytes}. On Python 3, native strings may be used as keys provided they contain only ASCII characters. @param kw: See C{dict}, but all keys and values should be C{bytes}. On Python 3, native strings may be used as keys provided they contain only ASCII characters. @raise UnicodeEncodeError: When a native string key cannot be coerced to an ASCII byte string (Python 3 only). asciiN)rr isinstancebytesencodepop)rargskwn nonByteNames nonByteNamebyteNamers rmrzAmpBox.__init__zsj2 $%"%#'Daz!U/CD D' 3K"))'2H!XXk2DN 3Es AAcH|j}|j||S)z5 Return another AmpBox just like me. )rupdate)rnewBoxs rmcopyz AmpBox.copys!! d rpc t|j}g}|j}|D]\}}t|tk(rt d|zt|tk(rt d|d|t |tkDrtdd|dt |tkDrtdd||||fD]%}|tdt |||'|tddd j|S) z Convert me into a wire-encoded string. @return: a C{bytes} encoded according to the rules described in the module docstring. zUnicode key not allowed: %rzUnicode value for key z not allowed: TNF!Hrrp) sorteditemsappendtyper TypeErrorrrIrXrJrr)riLwkvkvs rm serializezAmpBox.serializes 4::<   HH DAqAw#~ = ABBAw#~"8^A5 QRR1v&dD!T221v((eT1a00d $tSW%&"   $tQ-xx{rpc&|j|y)aW Serialize and send this box to an Amp instance. By the time it is being sent, several keys are required. I must have exactly ONE of:: _ask _answer _error If the '_ask' key is set, then the '_command' key must also be set. @param proto: an AMP instance. N)r{)rrls rm_sendTozAmpBox._sendTos  drpc4dtj|dS)NzAmpBox())dictrrs rmrzAmpBox.__repr__st,-Q//rpr) rsrtrurvr__annotations__rrrrrrrs@rmr/r/ps-Iy3>2 0rpr/c>eZdZUdZgZded<dfd ZfdZxZS)rSzJ I am an AmpBox that, upon being sent, terminates the connection. rrc(dt|dS)Nz QuitBox(**r)rr)rrs rmrzQuitBox.__repr__sEG,./q11rpcXt|||jjy)z@ Immediately call loseConnection after sending. N)rr transportloseConnectionrrlrs rmrzQuitBox._sendTos!  &&(rpr) rsrtrurvrrrrrrs@rmrSrSs#Iy2))rprSc4eZdZdZfdZddZfdZxZS) _SwitchBoxz| Implementation detail of ProtocolSwitchCommand: I am an AmpBox which sets up state for the protocol to switch. c 2t|di|||_y)z Create a _SwitchBox with the protocol to switch to after being sent. @param innerProto: the protocol instance to switch to. @type innerProto: an IProtocol provider. Nrg)rr innerProto)rrrrs rmrz_SwitchBox.__init__s 2$rpc`dj|jtj|S)Nz_SwitchBox({!r}, **{}))rrrrrs rmrz_SwitchBox.__repr__s('.. OO MM$   rpczt|||j|j|jy)z{ Send me; I am the last box on the connection. All further traffic will be over the new protocol. N)rr_lockForSwitch _switchTorrs rmrz_SwitchBox._sendTos-   (rpr)rsrtrurvrrrrrs@rmrrs% ))rprc~eZdZdZdZdZdZdZdZdZ dZ dZ dZ dd Z dd Zd Zd Zd ZdZdZdZdZdZy)r7a A L{BoxDispatcher} dispatches '_ask', '_answer', and '_error' L{AmpBox}es, both incoming and outgoing, to their appropriate destinations. Outgoing commands are converted into L{Deferred}s and outgoing boxes, and associated tracking state to fire those L{Deferred} when '_answer' boxes come back. Incoming '_answer' and '_error' boxes are converted into callbacks and errbacks on those L{Deferred}s, respectively. Incoming '_ask' boxes are converted into method calls on a supplied method locator. @ivar _outstandingRequests: a dictionary mapping request IDs to L{Deferred}s which were returned for those requests. @ivar locator: an object with a L{CommandLocator.locateResponder} method that locates a responder function that takes a Box and returns a result (either a Box or a Deferred which fires one). @ivar boxSender: an object which can send boxes, via the L{_sendBoxCommand} method, such as an L{AMP} instance. @type boxSender: L{IBoxSender} Nrc i|_||_yr)_outstandingRequestslocator)rrs rmrzBoxDispatcher.__init__&s$&! rpc||_y)z The given boxSender is going to start calling boxReceived on this L{BoxDispatcher}. @param boxSender: The L{IBoxSender} to send command responses to. Nr)rrs rmrz!BoxDispatcher.startReceivingBoxes*s #rpc&|j|y)z No further boxes will be received here. Terminate all currently outstanding command deferreds with the given reason. N)failAllOutgoingrrs rmrz BoxDispatcher.stopReceivingBoxes3s V$rpc||_|jj}d|_|D]\}}|j|y)z Call the errback on all outstanding requests awaiting responses. @param reason: the Failure instance to pass to those errbacks. N)_failAllReasonrrerrback)rrORrrs rmr zBoxDispatcher.failAllOutgoing:sG %  & & , , .$(! "JC MM& ! "rpcL|xjdz c_d|jfzS)z Generate protocol-local serial numbers for _ask keys. @return: a string that has not yet been used on this connection. s%x)_counterrs rm_nextTagzBoxDispatcher._nextTagFs$   '''rpc |j|rt|jSy||t<|j}|r ||t<|j |j |rtx}|j|<|Sd}|S)a Send a command across the wire with the given C{amp.Box}. Mutate the given box to give it any additional keys (_command, _ask) required for the command and request/response machinery, then send it. If requiresAnswer is True, returns a C{Deferred} which fires when a response is received. The C{Deferred} is fired with an C{amp.Box} on success, or with an C{amp.RemoteAmpError} if an error is received. If the Deferred fails and the error is not handled by the caller of this method, the failure will be logged and the connection dropped. @param command: a C{bytes}, the name of the command to issue. @param box: an AmpBox with the arguments for the command. @param requiresAnswer: a boolean. Defaults to True. If True, return a Deferred which will fire when the other side responds to this command. If False, return None and do not ask the other side for acknowledgement. @return: a Deferred which fires the AmpBox that holds the response to this command, or None, as specified by requiresAnswer. @raise ProtocolSwitched: if the protocol has been switched. N) r rr8rr.rrrr)rcommandrzrequiresAnswertagresults rm_sendBoxCommandzBoxDispatcher._sendBoxCommandOs6    *D//00G mmo CH DNN# 6>j @FT..s3 F rpc >t|}|j|||S)at This is a low-level API, designed only for optimizing simple messages for which the overhead of parsing is too great. @param command: a C{bytes} naming the command. @param kw: arguments to the amp box. @param requiresAnswer: a boolean. Defaults to True. If True, return a Deferred which will fire when the other side responds to this command. If False, return None and do not ask the other side for acknowledgement. @return: a Deferred which fires the AmpBox that holds the response to this command, or None, as specified by requiresAnswer. )r6r)rrrrrzs rmcallRemoteStringzBoxDispatcher.callRemoteStringzs" "g##GS.AArpch ||i|}|j|S#t$r tcYSwxYw)ah This is the primary high-level API for sending messages via AMP. Invoke it with a command and appropriate arguments to send a message to this connection's peer. @param commandType: a subclass of Command. @type commandType: L{type} @param a: Positional (special) parameters taken by the command. Positional parameters will typically not be sent over the wire. The only command included with AMP which uses positional parameters is L{ProtocolSwitchCommand}, which takes the protocol that will be switched to as its first argument. @param kw: Keyword arguments taken by the command. These are the arguments declared in the command's 'arguments' attribute. They will be encoded and sent to the peer as arguments for the L{commandType}. @return: If L{commandType} has a C{requiresAnswer} attribute set to L{False}, then return L{None}. Otherwise, return a L{Deferred} which fires with a dictionary of objects representing the result of this call. Additionally, this L{Deferred} may fail with an exception representing a connection failure, with L{UnknownRemoteError} if the other end of the connection fails for an unknown reason, or with any error specified as a key in L{commandType}'s C{errors} dictionary. ) BaseExceptionr _doCommand)r commandTypearcos rm callRemotezBoxDispatcher.callRemotes@J a&2&B}}T"" 6M s 11c8|jj|S)zy This is a terminal callback called after application code has had a chance to quash any errors. )rr~rr}s rmr~zBoxDispatcher.unhandledErrors ~~,,W55rpc|jj|t}|j|j|j |y)z An AMP box was received that answered a command previously sent with L{callRemote}. @param box: an AmpBox with a value for its L{ANSWER} key. N)rrr- addErrbackr~callback)rrzquestions rm_answerReceivedzBoxDispatcher._answerReceiveds@,,00V=D//0#rpcb|jj|t}|j|j|t }|t }t|tr|jdd}|tvrt|||}n t||}|jt|y)z An AMP box was received that answered a command previously sent with L{callRemote}, with an error. @param box: an L{AmpBox} with a value for its L{ERROR}, L{ERROR_CODE}, and L{ERROR_DESCRIPTION} keys. utf-8replaceN)rrr=r%r~r>r?rrdecoderNrTr r%)rrzr'rrexcs rm_errorReceivedzBoxDispatcher._errorReceiveds,,00U<D//0 O +, k5 )%,,Wi@K  '!),Y DC K8C&rpcfd}fd}|j}tvr-|j|||j|j|j |j y)zc @param box: an L{AmpBox} with a value for its L{COMMAND} and L{ASK} keys. c(t|t<|Sr)r.r-) answerBoxrzs rm formatAnswerz4BoxDispatcher._commandReceived..formatAnswers #CIf  rpc|jtrz|jj}|jj}t |t r|jdd}|jjr t}n2t}n't}tj|t}d}t|t<||t <||t"<|S)Nr*r+s Unknown Error)checkrTrrrrrrrrSr/r!errrZr.r=r?r>)errorcodedescerrorBoxrzs rm formatErrorz3BoxDispatcher._commandReceived..formatErrors{{>*{{,,{{..dC(;;w :D;;$$&yH%xH"9)'!#hHUO*.H& '#'HZ OrpN)dispatchCommandr. addCallbacks addCallback _safeEmitr%r~)rrzr2r:deferreds ` rm_commandReceivedzBoxDispatcher._commandReceiveds\   *'', #:  ! !, <   0D//0rpct|vr|j|yt|vr|j|yt|vr|j |yt |)a An AmpBox was received, representing a command, or an answer to a previously issued command (either successful or erroneous). Respond to it according to its contents. @param box: an AmpBox @raise NoEmptyBoxes: when a box is received that does not contain an '_answer', '_command' / '_ask', or '_error' key; i.e. one which does not fit into the command / response protocol defined by AMP. N)r-r(r=r.r8r@rLrrzs rmrzBoxDispatcher.ampBoxReceivedsN S=   % c\    $ ^  ! !# &s# #rpcf |j|jy#ttf$rYywxYw)z Emit a box, ignoring L{ProtocolSwitched} and L{ConnectionLost} errors which cannot be usefully handled. N)rrrRr)raBoxs rmr>zBoxDispatcher._safeEmits.   LL ( .1   s 00c |t}|jj|}|2d|}tt t |dt tSt||S)z A box with a _command key was received. Dispatch it to a local handler call it. @param box: an AmpBox to be dispatched. zUnhandled Command: Fr) r8rrrrTrYr%r[r)rrzcmd responderrs rmr;zBoxDispatcher.dispatchCommand"sl'lLL005  /w7K(!"2"45  Y,,rp)T)rsrtrurvr rrrrrrr rrrr!r~r(r.r@rr>r;rgrprmr7r7sm0NHI#% "()VB&)#V6 '(#1J$*-rpr7c&eZdZUdZgZded<dZy)_CommandLocatorMetaa This metaclass keeps track of all of the Command.responder-decorated methods defined since the last CommandLocator subclass was defined. It assumes (usually correctly, but unfortunately not necessarily so) that those commands responders were all declared as methods of the class being defined. Note that this list can be incorrect if users use the Command.responder decorator outside the context of a CommandLocator class declaration. Command responders defined on subclasses are given precedence over those inherited from a base class. The Command.responder decorator explicitly cooperates with this metaclass. z0'list[tuple[type[Command], Callable[..., Any]]]'_currentClassCommandsc|jdd}g|jddix}|d<tj||||}t|jdd}|j |D]}|j t|di |D]\} } | | f|| j<|r'|jtjk7r d} | |_ |S)N_commandDispatchrc\tjdtd|j|S)Nz-Override locateResponder, not lookupFunction.category stacklevel)warningswarnPendingDeprecationWarninglookupFunctionrris rmrz4_CommandLocatorMeta.__new__..locateResponderYs* C6  **400rp) rKr__new__list__mro__reversergetattr commandNamerVr:r) clsribasesattrscommandscdsubcls ancestorsancestor commandClass responderFuncrs rmrXz_CommandLocatorMeta.__new__Ls,,Q/')!!!$)++U% &c46+, ! AH IIgh(:B? @ A+3 I 'L-,8-+HB|'' ( I f++~/L/LL 1&5F " rpN)rsrtrurvrKrrXrgrprmrJrJ9s OQKPrprJc"eZdZdZdZdZdZy)r:z A L{CommandLocator} is a collection of responders to AMP L{Command}s, with the help of the L{Command.responder} decorator. cfd}|S)a< Wrap aCallable with its command's argument de-serialization and result serialization logic. @param aCallable: a callable with a 'command' attribute, designed to be called with keyword arguments. @param command: the command class whose serialization to use. @return: a 1-arg callable which, when invoked with an AmpBox, will deserialize the argument list and invoke appropriate user code for the callable's command, returning a Deferred which fires with the result or fails with an error. cj|}fd}fd}tfi|j|j|S)Nc|jj}j|}t|j}t t |||j v|S)NrF)trap allErrorsrrr%rT fatalErrors)r6rr7r8rs rmcheckKnownErrorszMCommandLocator._wrapWithSerialization..doit..checkKnownErrorss^ ejj'"3"34((-5;;'"4sg6I6I/IQVWrpc  j|S#t$r t}td|dd|wxYw)Nz returned  and z could not serialize it) makeResponserr%r3)rkoriginalFailure aCallablerrs rmmakeResponseForzLCommandLocator._wrapWithSerialization..doit..makeResponseForsM "//>>$&-iO($gw8's)>)parseArgumentsrr=r%)rzrrorurtrrs rmdoitz3CommandLocator._wrapWithSerialization..doit|sH''T2B  i.2._-,- rprg)rrtrrws``` rm_wrapWithSerializationz%CommandLocator._wrapWithSerializationls  : rpc|jjtjk7rtj||St j dt d|j|S)zJ Deprecated synonym for L{CommandLocator.locateResponder} z)Call locateResponder, not lookupFunction.rOrP)rrVr:rrSrTrUrWs rmrVzCommandLocator.lookupFunctionsW >> ( (N,I,I I!11$= = MM;2  ##D))rpcp|j}||vr&||\}}t||}|j||Sy)a Locate a callable to invoke when executing the named command. @param name: the normalized name (from the wire) of the command. @type name: C{bytes} @return: a 1-argument function that takes a Box and returns a box or a Deferred which fires a Box, for handling the command identified by the given name, or None, if no appropriate responder can be found. N)rMrrx)rrirbrfrgresponderMethods rmrzCommandLocator.locateRespondersH " " 2:*,T( 'L-(=O.. M M rpN)rsrtrurvrxrVrrgrprmr:r:es -^ *Nrpr:) metaclassceZdZdZdZdZy)rUz^ Implement the L{AMP.locateResponder} method to do simple, string-based dispatch. samp_cht|j|jz}t||dS)a Locate a callable to invoke when executing the named command. @return: a function with the name C{"amp_" + name} on the same instance, or None if no such function exists. This function will then be called with the L{AmpBox} itself as an argument. @param name: the normalized name (from the wire) of the command. @type name: C{bytes} N)r$baseDispatchPrefixupperr\)rrifNames rmrz#SimpleStringLocator.locateResponders.T44tzz|CDtUD))rpN)rsrtrurvrrrgrprmrUrUs ! *rprU)anddelforisraiseasserteliffromlambdarbreakelseglobalnottryclassexceptiforwhilecontinueexecimportpassyielddeffinallyinprintclt|jdd}|tvr|jS|S)a| (Private) Normalize an argument name from the wire for use with Python code. If the return value is going to be a python keyword it will be capitalized. If it contains any dashes they will be replaced with underscores. The rationale behind this method is that AMP should be an inherently multi-language protocol, so message keys may contain all manner of bizarre bytes. This is not a complete solution; there are still forms of arguments that this implementation will be unable to parse. However, Python identifiers share a huge raft of properties with identifiers from many other languages, so this is a 'good enough' effort for now. We deal explicitly with dashes because that is the most likely departure: Lisps commonly use dashes to separate method names, so protocols initially implemented in a lisp amp dialect may use dashes in argument or command names. @param key: a C{bytes}, looking something like 'foo-bar-baz' or 'from' @type key: C{bytes} @return: a native string which is a valid python identifier, looking something like 'foo_bar_baz' or 'From'. -_)r$r+rOtitle)rlkeys rm_wireNameToPythonIdentifierrs20  D$/ 0D zz| KrpcFeZdZdZdZd dZdZdZdZdZ dZ d Z d Z y ) r2a Base-class of all objects that take values from Amp packets and convert them into objects for Python functions. This implementation of L{IArgumentType} provides several higher-level hooks for subclasses to override. See L{toString} and L{fromString} which will be used to define the behavior of L{IArgumentType.toBox} and L{IArgumentType.fromBox}, respectively. Fc||_y)z Create an Argument. @param optional: a boolean indicating whether this argument can be omitted in the protocol. Noptional)rrs rmrzArgument.__init__#s ! rpcp|jr|j|}|||=|S|j|}|S)a/ Retrieve the given key from the given dictionary, removing it if found. @param d: a dictionary. @param name: a key in I{d}. @param proto: an instance of an AMP. @raise KeyError: if I am not optional and no value was found. @return: d[name]. )rgetr)rdrirlrs rmretrievezArgument.retrieve,s@ ==EE$KE dG EE$KE rpc|j|||}t|}|jr|d||<y|j||||<y)aG Populate an 'out' dictionary with mapping names to Python values decoded from an 'in' AmpBox mapping strings to string values. @param name: the argument name to retrieve @type name: C{bytes} @param strings: The AmpBox to read string(s) from, a mapping of argument names to string values. @type strings: AmpBox @param objects: The dictionary to write object(s) to, a mapping of names to Python objects. Keys will be native strings. @type objects: dict @param proto: an AMP instance. N)rrrfromStringProto)rrirjrkrlstnks rmrnzArgument.fromBoxBsJ$]]7D% 0 ( . ==RZGBK..r59GBKrpc|j|t||}|jr|y|j||||<y)a] Populate an 'out' AmpBox with strings encoded from an 'in' dictionary mapping names to Python values. @param name: the argument name to retrieve @type name: C{bytes} @param strings: The AmpBox to write string(s) to, a mapping of argument names to string values. @type strings: AmpBox @param objects: The dictionary to read object(s) from, a mapping of names to Python objects. Keys should be native strings. @type objects: dict @param proto: the protocol we are converting for. @type proto: AMP N)rrr toStringProto)rrirjrkrlobjs rmrrzArgument.toBox[s@(mmG%@%FN ==S[  ..sE:GDMrpc$|j|S)z Convert a string to a Python value. @param inString: the string to convert. @type inString: C{bytes} @param proto: the protocol we are converting for. @type proto: AMP @return: a Python object. ) fromStringrinStringrls rmrzArgument.fromStringProtovsx((rpc$|j|S)z Convert a Python object to a string. @param inObject: the object to convert. @param proto: the protocol we are converting for. @type proto: AMP )toString)rinObjectrls rmrzArgument.toStringProtos}}X&&rpcy)z Convert a string to a Python object. Subclasses must implement this. @param inString: the string to convert. @type inString: C{bytes} @return: the decoded value from C{inString} Nrgrrs rmrzArgument.fromStringrorpcy)a Convert a Python object into a string for passing over the network. @param inObject: an object of the type that this Argument is intended to deal with. @return: the wire encoding of inObject @rtype: C{bytes} Nrgrrs rmrzArgument.toStringrorpNF) rsrtrurvrrrrnrrrrrrrgrprmr2r2s6H!,:2;6 ) '   rpr2ceZdZdZeZdZy)rFz Encode any integer values of any size on the wire as the string representation. Example: C{123} becomes C{"123"} cd|fzS)Ns%drgrs rmrzInteger.toStrings{""rpN)rsrtrurvintrrrgrprmrFrFsJ#rprFceZdZdZdZdZy)rWzB Don't do any conversion at all; just pass through 'str'. c|Srrgrs rmrzString.toStringrpc|Srrgrs rmrzString.fromStringrrpNrsrtrurvrrrgrprmrWrWsrprWceZdZdZeZdZy)r@zA Encode floating-point values on the wire as their repr. crt|tstd|t|j dS)NzBad float value r)rfloat ValueErrorrrrs rmrzFloat.toStrings4(E*/|<= =8}##G,,rpN)rsrtrurvrrrrgrprmr@r@sJ-rpr@ceZdZdZdZdZy)r5z@ Encode True or False as "True" or "False" on the wire. c6|dk(ry|dk(rytd|)NTrueTFalseFzBad boolean value: )rrs rmrzBoolean.fromStrings+ w   !1(>? ?rpc |ryy)Nrrrgrs rmrzBoolean.toStrings rpNrsrtrurvrrrgrprmr5r5s@rpr5ceZdZdZdZdZy)r]z7 Encode a unicode string on the wire as UTF-8. cLtj||jdSNr*)rWrrrs rmrzUnicode.toStringstX__W%=>>rpcLtj||jdSr)rWrr,rs rmrzUnicode.fromStrings   x077@@rpNrrgrprmr]r]s?Arpr]ceZdZdZdZdZy)rPaY Encode and decode L{filepath.FilePath} instances as paths on the wire. This is really intended for use with subprocess communication tools: exchanging pathnames on different machines over a network is not generally meaningful, but neither is it disallowed; you can use this to communicate about NFS paths, for example. cTtjtj||Sr)r FilePathr]rrs rmrzPath.fromStrings   !3!3D(!CDDrpc^tj||jjSr)r]r asTextModepathrs rmrz Path.toStrings$h&9&9&;&@&@AArpNrrgrprmrPrPsEBrprPc$eZdZdZddZdZdZy)rHa Encode and decode lists of instances of a single other argument type. For example, if you want to pass:: [3, 7, 9, 15] You can create an argument like this:: ListOf(Integer()) The serialized form of the entire list is subject to the limit imposed by L{MAX_VALUE_LENGTH}. List elements are represented as 16-bit length prefixed strings. The argument type passed to the L{ListOf} initializer is responsible for producing the serialized form of each element. @ivar elementType: The L{Argument} instance used to encode and decode list elements (note, not an arbitrary L{IArgumentType} implementation: arguments must be implemented using only the C{fromString} and C{toString} methods, not the C{fromBox} and C{toBox} methods). @param optional: a boolean indicating whether this argument can be omitted in the protocol. @since: 10.0 c>||_tj||yr) elementTyper2r)rrrs rmrzListOf.__init__s&$)rpcg}t}|j|_|j||jj }|Dcgc] }|| c}Scc}w)zn Convert the serialized form of a list of instances of some type back into that list. )rrstringReceived dataReceivedrr)rrrjparserelementFromStringstrings rmrzListOf.fromStringsW $& 'H% ,,778?@f!&)@@@s Ac g}|D]R}|jj|}|jtdt ||j|Tdj |S)zI Serialize the given list of objects to a single string. rrp)rrrrrr)rrrjr serializeds rmrzListOf.toString)sb 'C))2237J NN4c*o6 7 NN: & 'xx  rpNr)rsrtrurvrrrrgrprmrHrHs6* A !rprHc$eZdZdZddZdZdZy)r1aI Convert a list of dictionaries into a list of AMP boxes on the wire. For example, if you want to pass:: [{'a': 7, 'b': u'hello'}, {'a': 9, 'b': u'goodbye'}] You might use an AmpList like this in your arguments or response list:: AmpList([('a', Integer()), ('b', Unicode())]) cvtd|Ds Jd|||_tj||y)ag Create an AmpList. @param subargs: a list of 2-tuples of ('name', argument) describing the schema of the dictionaries in the sequence of amp boxes. @type subargs: A C{list} of (C{bytes}, L{Argument}) tuples. @param optional: a boolean indicating whether this argument can be omitted in the protocol. c3BK|]\}}t|tywr)rr)rri_s rmrz#AmpList.__init__..NsBwtQ:dE*BszeAmpList should be defined with a list of (name, argument) tuples where `name' is a byte string, got: N)allsubargsr2r)rrrs rmrzAmpList.__init__CsAB'BB ?F I B $)rpcnt|}|Dcgc]}t||j|}}|Scc}wr)r`_stringsToObjectsr)rrrlboxesrzvaluess rmrzAmpList.fromStringProtoUs8H%INO##Cu=OO Ps2c dj|Dcgc]0}t||jt|j 2c}Scc}w)Nrp)r_objectsToStringsrr6r)rrrlrks rmrzAmpList.toStringProtoZsJxx ( "'4<<FPPR    s5A Nr)rsrtrurvrrrrgrprmr1r15s *$  rpr1ceZdZdZdZdZy)r<aO Encode and decode file descriptors for exchange over a UNIX domain socket. This argument type requires an AMP connection set up over an L{IUNIXTransport} provider (for example, the kind of connection created by L{IReactorUNIX.connectUNIX} and L{UNIXClientEndpoint}). There is no correspondence between the integer value of the file descriptor on the sending and receiving sides, therefore an alternate approach is taken to matching up received descriptors with particular L{Descriptor} parameters. The argument is encoded to an ordinal (unique per connection) for inclusion in the AMP command or response box. The descriptor itself is sent using L{IUNIXTransport.sendFileDescriptor}. The receiver uses the order in which file descriptors are received and the ordinal value to come up with the received copy of the descriptor. c6|jt|S)a Take a unique identifier associated with a file descriptor which must have been received by now and use it to look up that descriptor in a dictionary where they are kept. @param inString: The base representation (as a byte string) of an ordinal indicating which file descriptor corresponds to this usage of this argument. @type inString: C{str} @param proto: The protocol used to receive this descriptor. This protocol must be connected via a transport providing L{IUNIXTransport}. @type proto: L{BinaryBoxProtocol} @return: The file descriptor represented by C{inString}. @rtype: C{int} )_getDescriptorrrs rmrzDescriptor.fromStringProtoxs&##CM22rpcV|j|}tj|||}|S)a Send C{inObject}, an integer file descriptor, over C{proto}'s connection and return a unique identifier which will allow the receiver to associate the file descriptor with this argument. @param inObject: A file descriptor to duplicate over an AMP connection as the value for this argument. @type inObject: C{int} @param proto: The protocol which will be used to send this descriptor. This protocol must be connected via a transport providing L{IUNIXTransport}. @return: A byte string which can be used by the receiver to reconstruct the file descriptor. @rtype: C{bytes} )_sendFileDescriptorrFr)rrrl identifier outStrings rmrzDescriptor.toStringProtos.$..x8 ))$ EB rpN)rsrtrurvrrrgrprmr<r<cs(3*rpr<_Selfc,eZdZdZ ddZy) _CommandMetazh Metaclass hack to establish reverse-mappings for 'errors' and 'fatalErrors' as class vars. cZix}|d<ix}|d<d|vr|jd|d<tj||||}t|jt s$t dj|j|jD]#\}}t|t rt d||jD]#\}}t|t rt d|i} i} t|d| t|d | t|jtst|j|_ t|jtst|j|_ | jD]\} } | || <| || <| jD]\} } | || <| || <|jjD]#\}}t|t rt d ||jjD]#\}}t|t rt d ||S) N reverseErrorsrmr]rz-Command names must be byte strings, got: {!r}z*Argument names must be byte strings, got: z*Response names must be byte strings, got: errorsrnz'Error names must be byte strings, got: z-Fatal error names must be byte strings, got: )rrrXrr]rrr argumentsresponser&rrrnr) r^rir_r`rernewtypebnamerrrnrrs rmrXz_CommandMeta.__new__sH243 o."$$U;   %#';;w#7E- !%c4!F'--u5?FF''   )) XHE1eU+"LUI VWW X (( XHE1eU+"LUI VWW X0246 GXv6G]K@'..$/!'..1GN'--t4"&w':':";G LLN DAq M! BqE  %%' DAq M! BqE  ,,. UHAueU+"I% STT U ++113 HAueU+CE9M  rpN) r^z type[_Self]rirr_z tuple[type]r`zdict[str, object]rz Type[Command])rsrtrurvrXrgrprmrrs4 0 0 #0,70@Q0 0rprceZdZUdZded<gZded<gZded<gZded<iZd ed <iZ d ed <e Z d ed <e Z ded<dZ dZedZedZedZedZeddZdZy)r9a Subclass me to specify an AMP Command. @cvar arguments: A list of 2-tuples of (name, Argument-subclass-instance), specifying the names and values of the parameters which are required for this command. @cvar response: A list like L{arguments}, but instead used for the return value. @cvar errors: A mapping of subclasses of L{Exception} to wire-protocol tags for errors represented as L{str}s. Responders which raise keys from this dictionary will have the error translated to the corresponding tag on the wire. Invokers which receive Deferreds from invoking this command with L{BoxDispatcher.callRemote} will potentially receive Failures with keys from this mapping as their value. This mapping is inherited; if you declare a command which handles C{FooError} as 'FOO_ERROR', then subclass it and specify C{BarError} as 'BAR_ERROR', responders to the subclass may raise either C{FooError} or C{BarError}, and invokers must be able to deal with either of those exceptions. @cvar fatalErrors: like 'errors', but errors in this list will always terminate the connection, despite being of a recognizable error type. @cvar commandType: The type of Box used to issue commands; useful only for protocol-modifying behavior like startTLS or protocol switching. Defaults to a plain vanilla L{Box}. @cvar responseType: The type of Box used to respond to this command; only useful for protocol-modifying behavior like startTLS or protocol switching. Defaults to a plain vanilla L{Box}. @ivar requiresAnswer: a boolean; defaults to True. Set it to False on your subclass if you want callRemote to return None. Note: this is a hint only to the client side of the protocol. The return-type of a command responder method must always be a dictionary adhering to the contract specified by L{response}, because clients are always free to request a response if they want one. zClassVar[bytes]r]z&ClassVar[List[Tuple[bytes, Argument]]]rrzClassVar[List[Any]]extraz&ClassVar[Dict[Type[Exception], bytes]]rrnz+'ClassVar[Union[Type[Command], Type[Box]]]'rzClassVar[Type[AmpBox]] responseTypeTc ||_g}|jD]=\}}t|}||jvs |jr-|j |?|r4t dj dj||jg}y)a5 Create an instance of this command with specified values for its parameters. In Python 3, keyword arguments MUST be Unicode/native strings whereas in Python 2 they could be either byte strings or Unicode strings. A L{Command}'s arguments are defined in its schema using C{bytes} names. The values for those arguments are plucked from the keyword arguments using the name returned from L{_wireNameToPythonIdentifier}. In other words, keyword arguments should be named using the Python-side equivalent of the on-wire (C{bytes}) name. @param kw: a dict containing an appropriate value for each name specified in the L{arguments} attribute of my class. @raise InvalidSignature: if you forgot any required arguments. zforgot {} for {}z, N) structuredrrrrrGrrr])rr forgottenriarg pythonNames rmrzCommand.__init__s&  -ID#4T:J0  , - ""))$))I*>@P@PQ  rpc |j}t||j||S#t$r tcYSwxYw)a` Serialize a mapping of arguments using this L{Command}'s response schema. @param objects: a dict with keys matching the names specified in self.response, having values of the types that the Argument objects in self.response can format. @param proto: an L{AMP}. @return: an L{AmpBox}. )rrrrr)r^rkrlrs rmrrzCommand.makeResponse6sD ++-L!#,, eLL 6M s*AAct}|jD]\}}|jt|!|D]}||vst |dt ||j|j |S)a Serialize a mapping of arguments using this L{Command}'s argument schema. @param objects: a dict with keys similar to the names specified in self.arguments, having values of the types that the Argument objects in self.arguments can parse. @param proto: an L{AMP}. @return: An instance of this L{Command}'s C{commandType}. z is not a valid argument)setraddrrGrr)r^rkrl allowedNamesargNameignored intendedArgs rm makeArgumentszCommand.makeArgumentsJsu #  C GW   8A B C# QK,.&+6N'OPP Q!#--9JERRrpc0t||j|S)aZ Parse a mapping of serialized arguments using this L{Command}'s response schema. @param box: A mapping of response-argument names to the serialized forms of those arguments. @param protocol: The L{AMP} protocol. @return: A mapping of response-argument names to the parsed forms. )rrr^rzprotocols rm parseResponsezCommand.parseResponseas!cllH==rpc0t||j|S)a? Parse a mapping of serialized arguments using this L{Command}'s argument schema. @param box: A mapping of argument names to the seralized forms of those arguments. @param protocol: The L{AMP} protocol. @return: A mapping of argument names to the parsed forms. )rrrs rmrvzCommand.parseArgumentsps!cmmX>>rpcHtjj||f|S)a Declare a method to be a responder for a particular command. This is a decorator. Use like so:: class MyCommand(Command): arguments = [('a', ...), ('b', ...)] class MyProto(AMP): def myFunMethod(self, a, b): ... MyCommand.responder(myFunMethod) Notes: Although decorator syntax is not used within Twisted, this function returns its argument and is therefore safe to use with decorator syntax. This is not thread safe. Don't declare AMP subclasses in other threads. Don't declare responders outside the scope of AMP subclasses; the behavior is undefined. @param methodfunc: A function which will later become a method, which has a keyword signature compatible with this command's L{arguments} list and returns a dictionary with a set of keys compatible with this command's L{response} list. @return: the methodfunc parameter. )r:rKr)r^ methodfuncs rmrHzCommand.responder~s$@ ,,33S*4EFrpcfd}|jjjj|j}jr-|j j ||j||S)aL Encode and send this Command to the given protocol. @param proto: an AMP, representing the connection to send to. @return: a Deferred which will fire or error appropriately when the other side responds to the command (or error if the connection is lost before it is responded to). c|jt|j}jj |j t }t||jSr) rlrTrrrrr^r%r)r6rje errorTypers rm _massageErrorz)Command._doCommand.._massageErrorsI JJ~ &++C**..s}}>PQI9S__56 6rp)rr]rrrr=rr%)rrlr rs` rmrzCommand._doCommandsp 7  ! !      t 6        MM$,,e 4 LL 'rpN)rrarra)rsrtrurvrrrrrrnr6rrrr classmethodrrrrrvrHrrgrprmr9r9s(T! 8:I5:79H49!#E #57F 27:MM&SS, > > ? ?  Frpr9ceZdZdZdZdZy)_NoCertificatea This is for peers which don't want to use a local certificate. Used by AMP because AMP's internal language is all about certificates and this duck-types in the appropriate place; this API isn't really stable though, so it's not exposed anywhere public. For clients, it will use ephemeral DH keys, or whatever the default is for certificate-less clients in OpenSSL. For servers, it will generate a temporary self-signed certificate with garbage values in the DN and use that. c||_y)aT Create a _NoCertificate which either is or isn't for the client side of the connection. @param client: True if we are a client and should truly have no certificate and be anonymous, False if we are a server and actually have to generate a temporary certificate. @type client: bool N)client)rr%s rmrz_NoCertificate.__init__s  rpc |jsftd}tj}|j |}|j ||dd}|j |}|j|St}|r5|jtdd|Dcgc]}|jc}tdi|} | Scc}w)zT Behaves like L{twisted.internet.ssl.PrivateCertificate.options}(). zTEMPORARY CERTIFICATE)CNcyNTrg)dns rmz(_NoCertificate.options..rorprT)verifyrequireCertificatecaCertsrg) r%r(r+generatecertificateRequestsignCertificateRequestnewCertificateoptionsrroriginalr*) r authoritiessharedDNrcrsscrdcertr3authoccos rmr3z_NoCertificate.optionss{{45H""$C''1B..x_aPE%%e,D4<<- -&  NN'+7BCtT]]C ",G, DsCN)rsrtrurvrr3rgrprmr#r#s  rpr#cLeZdZUdZgZded<dZedZedZ dZ y) _TLSBoxzK I am an AmpBox that, upon being sent, initiates a TLS connection. rrcRt tddtj|y)Ns TLS_ERRORzTLS not available)r'rTr/rrs rmrz_TLSBox.__init__s! ; /BC Crpc8|jdtdS)Ntls_localCertificateF)rr#rs rm certificatez_TLSBox.certificatesxx/1FGGrpc&|jddS)Ntls_verifyAuthorities)rrs rmr,z_TLSBox.verifysxx0$77rpct|}dD]}|j|d|j||j|j|j y)zK Send my encoded value to the protocol, then initiate TLS. )r@rCN)r/rr _startTLSrAr,)rrlabrs rmrz_TLSBox._sendTo sMD\D A FF1dO  5 (($++6rpN) rsrtrurvrrrpropertyrAr,rrgrprmr=r=sGIy HH887rpr=ceZdZdZdZy)_LocalArgumentz Local arguments are never actually relayed across the wire. This is just a shim so that StartTLS can pretend to have some arguments: if arguments acquire documentation properties, replace this with something nicer later. cyrrg)rrirjrkrls rmrnz_LocalArgument.fromBoxs rpN)rsrtrurvrnrgrprmrIrIs   rprIceZdZdZdedfdedfgZdedfdedfgZeZddddZ d Z y) rVaz Use, or subclass, me to implement a command that starts TLS. Callers of StartTLS may pass several special arguments, which affect the TLS negotiation: - tls_localCertificate: This is a twisted.internet.ssl.PrivateCertificate which will be used to secure the side of the connection it is returned on. - tls_verifyAuthorities: This is a list of twisted.internet.ssl.Certificate objects that will be used as the certificate authorities to verify our peer's certificate. Each of those special parameters may also be present as a key in the response dictionary. r@TrrCN)tls_localCertificatetls_verifyAuthoritiesc t td| tdn||_||_t j |fi|y)a Create a StartTLS command. (This is private. Use AMP.callRemote.) @param tls_localCertificate: the PrivateCertificate object to use to secure the connection. If it's L{None}, or unspecified, an ephemeral DH key is used instead. @param tls_verifyAuthorities: a list of Certificate objects which represent root certificates to verify our peer with. NzTLS not available.T)r' RuntimeErrorr#rAr5r9r)rrLrMrs rmrzStartTLS.__init__AsO ;34 4$+ 4 %  1$$rpctj}jjjfd}|j ||S)z When a StartTLS command is sent, prepare to start TLS, but don't actually do it; wait for the acknowledgement, then initiate the TLS handshake. cTjjj|Sr)rErAr5)rrlrs rm actuallystartz*StartTLS._doCommand..actuallystart_s" OOD,,d.>.> ?Orp)r9r _prepareTLSrAr5r=)rrlrrRs`` rmrzStartTLS._doCommandVsK   tU + $**D,<,<=  m$rp) rsrtrurvrIrrr=rrrrgrprmrVrV"sc& !.$"?@ !>4#@AI !.$"?@ !>4#@AH L/34%*rprVc<eZdZdZfdZedZfdZxZS)rQa Use this command to switch from something Amp-derived to a different protocol mid-connection. This can be useful to use amp as the connection-startup negotiation phase. Since TLS is a different layer entirely, you can use Amp to negotiate the security parameters of your connection, then switch to a different protocol, and the connection will remain secured. c 2||_t|di|y)a Create a ProtocolSwitchCommand. @param _protoToSwitchToFactory: a ProtocolFactory which will generate the Protocol to switch to. @param kw: Keyword arguments, encoded and handled normally as L{Command} would. Nrg)protoToSwitchToFactoryrr)r_protoToSwitchToFactoryrrs rmrzProtocolSwitchCommand.__init__qs'># 2rpct|Sr)r)r^rrls rmrrz"ProtocolSwitchCommand.makeResponses *%%rpct}jfd}fd}|j||S)z When we emit a ProtocolSwitchCommand, lock the protocol, but don't actually switch to the new protocol unless an acknowledgement is received. If an error is received, switch back. cjjjj}j |j|Sr)rV buildProtocolrgetPeerr)ignrrlrs rm switchNowz3ProtocolSwitchCommand._doCommand..switchNowsD44BB'')J OOJ(C(C DJrpczjjjdtt|Sr)_unlockFromSwitchrVclientConnectionFailedr%r)r]rlrs rmhandlez0ProtocolSwitchCommand._doCommand..handles4  # # %  ' ' > >go. Jrp)rrrr<)rrlrr^rbrs`` rmrz ProtocolSwitchCommand._doCommands= G u %   ~~i00rp) rsrtrurvrr!rrrrrs@rmrQrQgs+ &&11rprQc"eZdZdZdZdZdZy)_DescriptorExchangera L{_DescriptorExchanger} is a mixin for L{BinaryBoxProtocol} which adds support for receiving file descriptors, a feature offered by L{IUNIXTransport}. @ivar _descriptors: Temporary storage for all file descriptors received. Values in this dictionary are the file descriptors (as integers). Keys in this dictionary are ordinals giving the order in which each descriptor was received. The ordering information is used to allow L{Descriptor} to determine which is the correct descriptor for any particular usage of that argument type. @type _descriptors: C{dict} @ivar _sendingDescriptorCounter: A no-argument callable which returns the ordinals, starting from 0. This is used to construct values for C{_sendFileDescriptor}. @ivar _receivingDescriptorCounter: A no-argument callable which returns the ordinals, starting from 0. This is used to construct values for C{fileDescriptorReceived}. ci|_|jj|_ttt |_ttt |_yr) _descriptorsrrrnextr_sendingDescriptorCounter_receivingDescriptorCounterrs rmrz_DescriptorExchanger.__init__s@"//33)0uw)?&+24+A(rpcX|jj||jS)z Assign and return the next ordinal to the given descriptor after sending the descriptor over this protocol's transport. )rsendFileDescriptorrhr descriptors rmrz(_DescriptorExchanger._sendFileDescriptors% ))*5--//rpc>||j|j<y)z Collect received file descriptors to be claimed later by L{Descriptor}. @param descriptor: The received file descriptor. @type descriptor: C{int} N)rfrirls rmfileDescriptorReceivedz+_DescriptorExchanger.fileDescriptorReceivedsAK$::<=rpN)rsrtrurvrrrorgrprmrdrds,B 0KrprdceZdZUdZdZdZdZdZdZdZ dZ dZ dZ de d<dZdZddZdZd Zd Zd Zd Zd ZeZdZdZdZdZdZdZdZdZe dZ!dZ"dZ#e$jKe#y)r4a A protocol for receiving L{AmpBox}es - key/value pairs - via length-prefixed strings. A box is composed of: - any number of key-value pairs, described by: - a 2-byte network-endian packed key length (of which the first byte must be null, and the second must be non-null: i.e. the value of the length must be 1-255) - a key, comprised of that many bytes - a 2-byte network-endian unsigned value length (up to the maximum of 65535) - a value, comprised of that many bytes - 2 null bytes In other words, an even number of strings prefixed with packed unsigned 16-bit integers, and then a 0-length string to indicate the end of the box. This protocol also implements 2 extra private bits of functionality related to the byte boundaries between messages; it can start TLS between two given boxes or switch to an entirely different protocol. However, due to some tricky elements of the implementation, the public interface to this functionality is L{ProtocolSwitchCommand} and L{StartTLS}. @ivar _keyLengthLimitExceeded: A flag which is only true when the connection is being closed because a key length prefix which was longer than allowed by the protocol was received. @ivar boxReceiver: an L{IBoxReceiver} provider, whose L{IBoxReceiver.ampBoxReceived} method will be invoked for each L{AmpBox} that is received. FNzOptional[Protocol] innerProtocolc<tj|||_yr)rdr boxReceiver)rrss rmrzBinaryBoxProtocol.__init__s%%d+&rpc|j}d|_||_||_|j|j|r|j |yy)a Switch this BinaryBoxProtocol's transport to a new protocol. You need to do this 'simultaneously' on both ends of a connection; the easiest way to do this is to use a subclass of ProtocolSwitchCommand. @param newProto: the new protocol instance to switch to. @param clientFactory: the ClientFactory to send the L{twisted.internet.protocol.ClientFactory.clientConnectionLost} notification to. rN)recvdrqinnerProtocolClientFactorymakeConnectionrr)rnewProto clientFactory newProtoDatas rmrzBinaryBoxProtocol._switchTo sPzz  &*7'/   ! !, / rpc|jr td|j t|j|jj |y|jj |jy)a/ Send a amp.Box to my peer. Note: transport.write is never called outside of this method. @param box: an AmpBox. @raise ProtocolSwitched: if the protocol has previously been switched. @raise ConnectionLost: if the connection has previously been lost. z5This connection has switched: no AMP traffic allowed.N)_lockedrRrr_startingTLSBufferrwriterrBs rmr{zBinaryBoxProtocol.sendBox sh <<"G  >> ! " "  " " .  # # * *3 / NN  1rpch||_|jj||jy)z Notify L{boxReceiver} that it is about to receive boxes from this protocol by invoking L{IBoxReceiver.startReceivingBoxes}. N)rrsrconnectionMaderrs rmrwz BinaryBoxProtocol.makeConnection6 s+ # ,,T2 rpc|jrd|_|j|jj|ytj||S)zg Either parse incoming data as L{AmpBox}es or relay it to our nested protocol. FN)_justStartedTLSrqrr)rdatas rmrzBinaryBoxProtocol.dataReceived? sM   #(D     )    + +D 1 "//d;;rpc~|jC|jj||j|jjd||jrt t dddd}n/|jtr|jr td}n|}|jj|y)zF The connection was lost; notify any nested protocol. NTFz4Peer rejected our certificate for an unknown reason.) rqconnectionLostrvclientConnectionLost_keyLengthLimitExceededr%rXr4rrrrsr)rr failReasons rmrz BinaryBoxProtocol.connectionLostM s    )    - -f 5..://DDT6R  ' ' udD!ABJ \\* +0D0D )FJ J ++J7rprcrdcBt|_|j|S)z6 String received in the 'init' state. )r/ _currentBox proto_keyrrs rm proto_initzBinaryBoxProtocol.proto_initm s"8~~f%%rpc|r||_|j|_y|jj |j d|_y)zu String received in the 'key' state. If the key is empty, a complete box has been received. rNinit) _currentKey_MAX_VALUE_LENGTH MAX_LENGTHrsrrrs rmrzBinaryBoxProtocol.proto_keyt sD %D "44DO    + +D,<,< =#D rpcf||j|j<d|_|j|_y)z7 String received in the 'value' state. Nr)rr_MAX_KEY_LENGTHrrs rm proto_valuezBinaryBoxProtocol.proto_value s2.4))*..rpcFd|_|jjy)z The key length limit was exceeded. Disconnect the transport and make sure a meaningful exception is reported. TN)rrr)rlengths rmlengthLimitExceededz%BinaryBoxProtocol.lengthLimitExceeded s (,$ %%'rpcd|_y)a Lock this binary protocol so that no further boxes may be sent. This is used when sending a request to switch underlying protocols. You probably want to subclass ProtocolSwitchCommand rather than calling this directly. TN)r|rs rmrz BinaryBoxProtocol._lockForSwitch s  rpc@|j tdd|_y)z Unlock this locked binary protocol so that further boxes may be sent again. This is used after an attempt to switch protocols has failed for some reason. Nz*Protocol already switched. Cannot unlock.F)rqrRr|rs rmr`z#BinaryBoxProtocol._unlockFromSwitch s#    )"#OP P rpc ~g|_|j*td|jd|jd||fy)z Used by StartTLSCommand to put us into the state where we don't actually send things that get sent, instead we buffer them. see L{_sendBoxCommand}. Nz,Previously authenticated connection between rqz is trying to re-establish as )r}hostCertificaterMpeerCertificate)rrAverifyAuthoritiess rmrSzBinaryBoxProtocol._prepareTLS sL #%    +(((( "34   ,rpc||_d|_|d}|jj|j||j }| d|_|D]}|j |yy)a< Used by TLSBox to initiate the SSL handshake. @param certificate: a L{twisted.internet.ssl.PrivateCertificate} for use locally. @param verifyAuthorities: L{twisted.internet.ssl.Certificate} instances representing certificate authorities which will verify our peer. TNrg)rrrstartTLSr3r}r{)rrArstlsbrzs rmrEzBinaryBoxProtocol._startTLS sz +#  $ "   3 3 35F GH''  &*D # " S! " rpcZ|jrytj|jSr)noPeerCertificater)peerFromTransportrrs rmrz!BinaryBoxProtocol.peerCertificate s#  ! !,,T^^<> % NN ) ) + &rpciS)aX The default TLS responder doesn't specify any certificate or anything. From a security perspective, it's little better than a plain-text connection - but it is still a *bit* better, so it's included for convenience. You probably want to override this by providing your own StartTLS.responder. rgrs rm_defaultStartTLSResponderz+BinaryBoxProtocol._defaultStartTLSResponder s  rpr)&rsrtrurvrr}r|rrrrrrqrrvrrr{rwrrrrrrrrrrr`rSrErGrr~rrVrHrgrprmr4r4s@OGKK#O(,M%,!%'0:2. <8.O!J& ($"*== ,  01rpr4c6eZdZdZdZd dZdZd dZdZdZ y) r,za This protocol is an AMP connection. See the module docstring for protocol details. FNczd|_||}||}tj||tj||yr))_ampInitializedr7rr4)rrsrs rmrz AMP.__init__ sA $  K ?GtW-""45rpcftj||}||Stj||}|S)z Unify the implementations of L{CommandLocator} and L{SimpleStringLocator} to perform both kinds of dispatch, preferring L{CommandLocator}. @type name: C{bytes} )r:rrU)rrifirstRespondersecondResponders rmrzAMP.locateResponder s:(77dC  %! !-==dDIrpc|jd|j}nd}d|jj|dt|ddS)zo A verbose string representation which gives us information about this AMP connection. z inner r)rqrrsid)r innerReprs rmrz AMP.__repr__ sR    )!$"4"4!78II4>>**+I;fRXaLJJrpcR|jstj||j|_|j |_tj|jjd|j d|jdtj||y)zI Emit a helpful log message when the connection is made. z connection established (HOST: PEER:rN) rr,rr\_transportPeergetHost_transportHostr!msgrrsr4rwrs rmrwzAMP.makeConnection s~## LL '//1'//1 ~~&&(;(;T=P=P R  ((y9rpctj|jjd|jd|j dt j||d|_y)zI Emit a helpful log message when the connection is lost. z connection lost (HOST:rrN) r!rrrsrrr4rrr s rmrzAMP.connectionLost1 sL ~~&&(;(;T=P=P R  ((v6rp)NNr) rsrtrurvrrrrrwrrgrprmr,r, s( O 6  K:" rpr,cReZdZdZdZdZdZdZdZdZ e dZ e d Z y ) _ParserHelperz: A box receiver which records all boxes received. cg|_yr)rrs rmrz_ParserHelper.__init__B s  rpcyNrrgrs rmr\z_ParserHelper.getPeerE rpcyrrgrs rmrz_ParserHelper.getHostH rrpFcy)z0 No initialization is required. Nrg)rsenders rmrz!_ParserHelper.startReceivingBoxesM rorpc:|jj|yr)rrrBs rmrz_ParserHelper.ampBoxReceivedR s #rpc|}t|}|j||j|j|jS)z Parse some amp data stored in a file. @param fileObj: a file-like object. @return: a list of AmpBoxes encoded in the given file. )rs)r4rwrreadr)r^fileObj parserHelperbbps rmr_z_ParserHelper.parseV sCu L9 <( (!!!rpc6|jt|S)z Parse some amp data stored in a string. @param data: a str holding some amp-encoded data. @return: a list of AmpBoxes encoded in the given string. )r_r)r^rs rmr`z_ParserHelper.parseStringe syy''rpN) rsrtrurvrr\r disconnectingrrr!r_r`rgrprmrr= sOM  " "((rprcfi}|j}|D]\}}|j|||||S)a~ Convert an AmpBox to a dictionary of python objects, converting through a given arglist. @param strings: an AmpBox (or dict of strings) @param arglist: a list of 2-tuples of strings and Argument objects, as described in L{Command.arguments}. @param proto: an L{AMP} instance. @return: the converted dictionary mapping names to argument objects. )rrn)rjarglistrlrk myStringsargname argparsers rmrru sAG I%>'9gu=> Nrpcb|j}|D]\}}|j|||||S)a- Convert a dictionary of python objects to an AmpBox, converting through a given arglist. @param objects: a dict mapping names to python objects @param arglist: a list of 2-tuples of strings and Argument objects, as described in L{Command.arguments}. @param strings: [OUT PARAMETER] An object providing the L{dict} interface which will be populated with serialized data. @param proto: an L{AMP} instance. @return: The converted dictionary mapping names to encoded argument strings (identical to C{strings}). )rrr)rkrrjrl myObjectsrrs rmrr s:$ I%<)U;< NrpceZdZdZdZdZy)r;a Encodes C{decimal.Decimal} instances. There are several ways in which a decimal value might be encoded. Special values are encoded as special strings:: - Positive infinity is encoded as C{"Infinity"} - Negative infinity is encoded as C{"-Infinity"} - Quiet not-a-number is encoded as either C{"NaN"} or C{"-NaN"} - Signalling not-a-number is encoded as either C{"sNaN"} or C{"-sNaN"} Normal values are encoded using the base ten string representation, using engineering notation to indicate magnitude without precision, and "normal" digits to indicate precision. For example:: - C{"1"} represents the value I{1} with precision to one place. - C{"-1"} represents the value I{-1} with precision to one place. - C{"1.0"} represents the value I{1} with precision to two places. - C{"10"} represents the value I{10} with precision to two places. - C{"1E+2"} represents the value I{10} with precision to one place. - C{"1E-1"} represents the value I{0.1} with precision to one place. - C{"1.5E+2"} represents the value I{15} with precision to two places. U{http://speleotrove.com/decimal/} should be considered the authoritative specification for the format. cBt|}tj|Sr)r$decimalr;rs rmrzDecimal.fromString s)x((rpct|tjrt|j dSt d)zW Serialize a C{decimal.Decimal} instance to the specified wire format. rz8amp.Decimal can only encode instances of decimal.Decimal)rrr;rrrrs rmrzDecimal.toString s3 h 0x=''0 0STTrpNrrgrprmr;r; s8)Urpr;c eZdZdZeddeddeddedd ed d ed d eddeddeddg ZdZdZy)DateTimeaO Encodes C{datetime.datetime} instances. Wire format: '%04i-%02i-%02iT%02i:%02i:%02i.%06i%s%02i:%02i'. Fields in order are: year, month, day, hour, minute, second, microsecond, timezone direction (+ or -), timezone hour, timezone minute. Encoded string is always exactly 32 characters long. This format is compatible with ISO 8601, but that does not mean all ISO 8601 dates can be accepted. Also, note that the datetime module's notion of a "timezone" can be complex, but the wire format includes only a fixed offset, so the conversion is not lossless. A lossless transmission of a C{datetime} instance is not feasible since the receiving end would require a Python interpreter. @ivar _positions: A sequence of slices giving the positions of various interesting parts of the wire format. r  ct|}t|dk7rtd||jDcgc]}t ||}}|d}t j |g|dd}|g|ddtj|Scc}w)z| Parse a string containing a date and time in the wire format into a C{datetime.datetime} instance. rzinvalid date format rrN)r$rr _positionsr_FixedOffsetTZInfofromSignHoursMinutesdatetime)rsprsigntimezones rmrzDateTime.fromString s O q6R<3A59: :%)__5#ad)55u%::4M&*MZqr   &)) 6sBc |j}| td|jdz|jzdz}|dkDrd}nd}d|j|j |j |j|j|j|j|t|dzt|dzf z}|jdS) zm Serialize a C{datetime.datetime} instance to a string in the specified wire format. zUamp.DateTime cannot serialize naive datetime instances. You may find amp.utc useful.iQ<r+-z-%04i-%02i-%02iT%02i:%02i:%02i.%06i%s%02i:%02ir) utcoffsetrdayssecondsyearmonthdayhourminutesecond microsecondabsr)rroffset minutesOffsetrpackeds rmrzDateTime.toString s  >/   u,v~~="D 1 DDA FF GG EE FF HH HH MM   " $   # D  }}W%%rpN)rsrtrurvslicerrrrgrprmrr sk& a  a  a  b"  b"  b"  b"  b"  b"  J* %&rpr)rv __future__rrrrS functoolsrior itertoolsrstructrtypesrtypingr r r r r rrrrrzope.interfacerrtwisted.internet.deferrrrtwisted.internet.errorrrrtwisted.internet.interfacesrtwisted.internet.mainrtwisted.internet.protocolrtwisted.protocols.basicrrtwisted.pythonr r!twisted.python._tzhelperr"r\r#rtwisted.python.compatr$twisted.python.failurer%twisted.python.reflectr&twisted.internetr'_ssl supportedtwisted.internet.sslr(r)r*r+ ImportError__all__objectrar.r-r8r=r>r?rZrYrIrJrArCrBrD Exceptionr0rRrMrLrGrXr3rTr^rKr[rErNrr/r6rSrr7rrJr:rUrOrr2rFrWr@r5r]rPrHr1r<rrr9r#r=rIrVrQrdr4r,rr_r`rrr;rrgrprmr"s1 |z#   2@@TT?1.O(/*6 , ~~UU C6 rm8CK+@A     )#= I= @  2 9 6  *y y8x BhB@ X  1X1h>>h x 8()9:[0T%, [0@ )f)$))D \n-n-n-b )$)X TN2TN TNn ** *0B< ]L L L ^ #h # X  -H -h( Af AB7B"5!X5!p+ h+ \>>B 646r] ]@55p7f7> V BwBJ31G31l $%,K,K&,K^ Z_2/1E_2_2D J ]N