Exemplo n.º 1
0
class TwistedSUDSClient:

    def __init__(self, wsdl, timeout=DEFAULT_TIMEOUT, ctx_factory=None):

        self.options = Options()
        self.options.transport = FileTransport()

        reader = DefinitionsReader(self.options, Definitions)

        self.wsdl = reader.open(wsdl)
        self.type_factory = Factory(self.wsdl)

        self.timeout = timeout
        self.ctx_factory = ctx_factory


    def createType(self, type_name):
        """
        @args typename: type to create. QNames are specified with {namespace}element syntax.
        """
        return self.type_factory.create(type_name)


    def invoke(self, url, method_name, *args):
        """
        Invoke a SOAP/WSDL action. No getattr/getitem magic, sorry.

        @args url: URL/Endpoint to POST SOAP at.
        @args method_name: SOAP Method to invoke.
        @args *args Argument for SOAP method.
        """
        def invokeError(err, url, soap_action):
            if isinstance(err.value, ConnectionDone):
                pass # these are pretty common when the remote shuts down
            else:
                # response body is in err.value.response
                action = soap_action[1:-1].split('/')[-1]
                log.msg('SOAP method invocation failed: %s. Message: %s. URL: %s. Action: %s' % \
                        (err.getErrorMessage(), err.value.response, url, action), system=LOG_SYSTEM)
            return err

        method = self._getMethod(method_name)

        # build envelope and get action
        soap_envelope = method.binding.input.get_message(method, args, {})
        soap_envelope = soap_envelope.str().encode('utf-8')
        soap_action = str(method.soap.action)

        short_action = soap_action[1:-1].split('/')[-1]
        log.msg('SOAP Dispatch: URL: %s. Action: %s. Length %s' % (url, short_action, len(soap_envelope)), system=LOG_SYSTEM, debug=True)

        # dispatch
        d, factory = _httpRequest(url, soap_action, soap_envelope, timeout=self.timeout, ctx_factory=self.ctx_factory)
        d.addCallbacks(self._parseResponse, invokeError,
                       callbackArgs=(factory, method, short_action), errbackArgs=(url, soap_action))
        return d


    def _getMethod(self, method_name):
        # one service and port should be enough for everybody
        assert len(self.wsdl.services) == 1, 'TwistedSUDSClient can only handle one service'
        service = self.wsdl.services[0]

        assert len(service.ports) == 1, 'TwistedSUDSClient can only handle port'
        port = service.ports[0]

        # print port.methods.keys()
        method = port.methods[method_name]
        return method


    def _parseResponse(self, response, factory, method, short_action):

        log.msg('Received SOAP response for %s' % short_action, debug=True, system=LOG_SYSTEM)
        if factory.status == '200':
            # Note: This can raise suds.WebFault, but it is the responsibility of the caller to handle that
            _, result = method.binding.input.get_reply(method, response)
            return result

        else:
            raise RequestError('Got a non-200 response from the service. Message:\n----\n' + response + '\n----\n')