Python:如何使用 Twisted 作为 SUDS 的传输? [英] Python: How can I use Twisted as the transport for SUDS?

查看:26
本文介绍了Python:如何使用 Twisted 作为 SUDS 的传输?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基于 Twisted 的项目,用于与网络设备通信,我正在添加对新的支持API 为 SOAP 的供应商 (Citrix NetScaler).不幸的是Twisted 中对 SOAP 的支持仍然依赖于 SOAPpy,这已经很糟糕了日期.事实上,在这个问题(我刚刚检查过),twisted.web.soap本身甚至已经 21 个月没有更新了!

I have a project that is based on Twisted used to communicate with network devices and I am adding support for a new vendor (Citrix NetScaler) whose API is SOAP. Unfortunately the support for SOAP in Twisted still relies on SOAPpy, which is badly out of date. In fact as of this question (I just checked), twisted.web.soap itself hasn't even been updated in 21 months!

我想问一下是否有人有任何经验他们愿意与使用 Twisted 出色的异步传输共享SUDS 的功能.似乎插入了自定义的 Twisted运输将自然适合 SUDS 的 Client.options.transport,我只是有很难把我的头包围起来.

I would like to ask if anyone has any experience they would be willing to share with utilizing Twisted's superb asynchronous transport functionality with SUDS. It seems like plugging in a custom Twisted transport would be a natural fit in SUDS' Client.options.transport, I'm just having a hard time wrapping my head around it.

我确实想出了一种使用 SUDS 调用 SOAP 方法的方法通过使用 twisted.internet.threads.deferToThread() 异步,但这对我来说就像一个黑客.

I did come up with a way to call the SOAP method with SUDS asynchronously by utilizing twisted.internet.threads.deferToThread(), but this feels like a hack to me.

这是我所做的一个例子,给你一个想法:

Here is an example of what I've done, to give you an idea:

# netscaler is a module I wrote using suds to interface with NetScaler SOAP
# Source: http://bitbucket.org/jathanism/netscaler-api/src
import netscaler
import os
import sys
from twisted.internet import reactor, defer, threads

# netscaler.API is the class that sets up the suds.client.Client object
host = 'netscaler.local'
username = password = 'nsroot'
wsdl_url = 'file://' + os.path.join(os.getcwd(), 'NSUserAdmin.wsdl')
api = netscaler.API(host, username=username, password=password, wsdl_url=wsdl_url)

results = []
errors = []

def handleResult(result):
    print '	got result: %s' % (result,)
    results.append(result)

def handleError(err):
    sys.stderr.write('	got failure: %s' % (err,))
    errors.append(err)

# this converts the api.login() call to a Twisted thread.
# api.login() should return True and is is equivalent to:
# api.service.login(username=self.username, password=self.password)
deferred = threads.deferToThread(api.login)
deferred.addCallbacks(handleResult, handleError)

reactor.run()

这按预期工作并将 api.login() 调用的返回推迟到它是完整的,而不是阻塞.但正如我所说,它没有感觉对.

This works as expected and defers return of the api.login() call until it is complete, instead of blocking. But as I said, it doesn't feel right.

在此先感谢您的任何帮助、指导、反馈、批评,侮辱,或完整的解决方案.

Thanks in advance for any help, guidance, feedback, criticism, insults, or total solutions.

更新:我找到的唯一解决方案是twisted-suds,它是 Suds 的一个分支,修改后可以与 Twisted 一起使用.

Update: The only solution I've found is twisted-suds, which is a fork of Suds modified to work with Twisted.

推荐答案

transport 在 Twisted 上下文中的默认解释可能是 twisted.internet.interfaces.ITransport.在这一层,您基本上是在处理通过某种套接字(UDP、TCP 和 SSL 是最常用的三种)发送和接收的原始字节.这并不是 SUDS/Twisted 集成库真正感兴趣的内容.相反,您想要的是一个 HTTP 客户端,SUDS 可以使用它来发出必要的请求并提供所有响应数据,以便 SUDS 可以确定结果曾是.也就是说,SUDS 并不真正关心网络上的原始字节.它关心的是 HTTP 请求和响应.

The default interpretation of transport in the context of Twisted is probably an implementation of twisted.internet.interfaces.ITransport. At this layer, you're basically dealing with raw bytes being sent and received over a socket of some sort (UDP, TCP, and SSL being the most commonly used three). This isn't really what a SUDS/Twisted integration library is interested in. Instead, what you want is an HTTP client which SUDS can use to make the necessary requests and which presents all of the response data so that SUDS can determine what the result was. That is to say, SUDS doesn't really care about the raw bytes on the network. What it cares about is the HTTP requests and responses.

如果您检查 twisted.web.soap.Proxy(Twisted Web SOAP API 的客户端部分)的实现,您会发现它实际上并没有做太多事情.大约 20 行代码将 SOAPpy 粘合到 twisted.web.client.getPage.也就是说,它以我上面描述的方式将 SOAPpy 连接到 Twisted.

If you examine the implementation of twisted.web.soap.Proxy (the client part of the Twisted Web SOAP API), you'll see that it doesn't really do much. It's about 20 lines of code that glues SOAPpy to twisted.web.client.getPage. That is, it's hooking SOAPpy in to Twisted in just the way I described above.

理想情况下,SUDS 会提供一些类似于 SOAPpy.buildSOAPSOAPpy.parseSOAPRPC 的 API(也许 API 会更复杂一点,或者接受还有一些参数——我不是 SOAP 专家,所以我不知道 SOAPpy 的特定 API 是否缺少一些重要的东西——但基本思想应该是相同的).然后你可以基于 SUDS 编写类似 twisted.web.soap.Proxy 的东西.如果 twisted.web.client.getPage 没有提供对请求的足够控制或关于响应的足够信息,您也可以使用 twisted.web.client.Agent 代替,这是最近推出的,并提供了对整个请求/响应过程的更多控制.但同样,这与当前基于 getPage 的代码的想法完全相同,只是一种更灵活/更具表现力的实现.

Ideally, SUDS would provide some kind of API along the lines of SOAPpy.buildSOAP and SOAPpy.parseSOAPRPC (perhaps the APIs would be a bit more complicated, or accept a few more parameters - I'm not a SOAP expert, so I don't know if SOAPpy's particular APIs are missing something important - but the basic idea should be the same). Then you could write something like twisted.web.soap.Proxy based on SUDS instead. If twisted.web.client.getPage doesn't offer enough control over the requests or enough information about the responses, you could also use twisted.web.client.Agent instead, which is more recently introduced and offers much more control over the whole request/response process. But again, that's really the same idea as the current getPage-based code, just a more flexible/expressive implementation.

刚刚查看了 Client.options.transport 的 API 文档,听起来 SUDS 传输基本上是一个 HTTP 客户端.这种集成的问题在于 SUDS 想要发送请求,然后能够立即获得响应.由于 Twisted 主要基于回调,因此基于 Twisted 的 HTTP 客户端 API 无法立即向 SUDS 返回响应.它只能返回 Deferred(或等效的).

Having just looked at the API documentation for Client.options.transport, it sounds like a SUDS transport is basically an HTTP client. The problem with this kind of integration is that SUDS wants to send a request and then be able to immediately get the response. Since Twisted is largely based on callbacks, a Twisted-based HTTP client API can't immediately return a response to SUDS. It can only return a Deferred (or equivalent).

这就是为什么如果关系颠倒,事情会更好的原因.与其给 SUDS 一个 HTTP 客户端来玩,不如给 SUDS 和一个 HTTP 客户端给第三段代码,让它协调交互.

This is why things work better if the relationship is inverted. Instead of giving SUDS an HTTP client to play with, give SUDS and an HTTP client to a third piece of code and let it orchestrate the interactions.

不过,通过创建基于 Twisted 的 SUDS 传输(又名 HTTP 客户端)来使事情正常运行可能并非不可能.Twisted 主要使用Deferred(又名回调)来公开事件这一事实并不意味着这是它唯一可以工作的方式.通过使用greenlet等第三方库,可以提供基于协程的API,异步操作的请求涉及从一个协程执行切换到另一个协程,事件通过切换传递回到原来的协程.有一个名为 corotwine 的项目可以做到这一点. 可以使用它来为 SUDS 提供它想要的那种 HTTP 客户端 API;但是,这并不能保证.当上下文切换突然插入之前没有的位置时,这取决于 SUDS 不会中断.这是 SUDS 的一个非常微妙和脆弱的属性,在未来的版本中很容易被 SUDS 开发人员更改(甚至是无意的),所以它可能不是理想的解决方案,即使你能得到它立即开始工作(除非您可以以承诺在这种配置中测试他们的代码以确保其继续工作的形式获得 SUDS 维护人员的合作).

It may not be impossible to have things work by creating a Twisted-based SUDS transport (aka HTTP client), though. The fact that Twisted primarily uses Deferred (aka callbacks) to expose events doesn't mean that this is the only way it can work. By using a third-party library such as greenlet, it's possible to provide a coroutine-based API, where a request for an asynchronous operation involves switching execution from one coroutine to another, and events are delivered by switching back to the original coroutine. There is a project called corotwine which can do just this. It may be possible to use this to provide SUDS with the kind of HTTP client API it wants; however, it's not guaranteed. It depends on SUDS not breaking when a context switch is suddenly inserted where previously there was none. This is a very subtle and fragile property of SUDS and can easily be changed (unintentionally, even) by the SUDS developers in a future release, so it's probably not the ideal solution, even if you can get it to work now (unless you can get cooperation from the SUDS maintainers in the form of a promise to test their code in this kind of configuration to ensure it continues to work).

顺便说一句,Twisted Web 的 SOAP 支持仍然基于 SOAPpy 并且近两年没有修改的原因是没有明确的 SOAPpy 替代品出现.有很多竞争者(Python 有哪些 SOAP 客户端库,它们的文档在哪里? 涵盖了其中的几个).如果事情稳定下来,尝试更新 Twisted 的内置 SOAP 支持可能是有意义的.在那之前,我认为分开做这些集成库更有意义,这样它们可以更容易地更新,所以 Twisted 本身不会以一大堆没人想要的不同的 SOAP 集成( 比目前的情况更糟糕,那里只有一个没人想要的 SOAP 集成模块).

As an aside, the reason Twisted Web's SOAP support is still based on SOAPpy and hasn't been modified for nearly two years is that no clear replacement for SOAPpy has ever shown up. There have been many contenders (What SOAP client libraries exist for Python, and where is the documentation for them? covers several of them). If things ever settle down, it may make sense to try to update Twisted's built-in SOAP support. Until then, I think it makes more sense to do these integration libraries separately, so they can be updated more easily and so Twisted itself doesn't end up with a big pile of different SOAP integration that no one wants (which would be worse than the current situation, where there's just one SOAP integration module that no one wants).

这篇关于Python:如何使用 Twisted 作为 SUDS 的传输?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆