问题描述
我有一个基于Twisted的项目,与网络设备通信,我正在添加对新设备的支持API为SOAP的供应商( Citrix NetScaler ).不幸的是在Twisted中对SOAP的支持仍然依赖于SOAPpy
,这是非常糟糕的日期.实际上,就这个问题而言(我刚刚检查过), twisted.web.soap
甚至在21个月内都没有更新!
I have a project that is based on Twisted used tocommunicate with network devices and I am adding support for a newvendor (Citrix NetScaler) whose API is SOAP. Unfortunately thesupport for SOAP in Twisted still relies on SOAPpy
, which is badly outof 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 willingto share with utilizing Twisted's superb asynchronous transportfunctionality with SUDS. It seems like plugging in a custom Twistedtransport would be a natural fit in SUDS' Client.options.transport
, I'm just havinga 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 SUDSasynchronously 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 '\tgot result: %s' % (result,)
results.append(result)
def handleError(err):
sys.stderr.write('\tgot 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 untilit is complete, instead of blocking. But as I said, it doesn't feelright.
在此先感谢您的帮助,指导,反馈,批评,侮辱或整体解决方案.
Thanks in advance for any help, guidance, feedback, criticism,insults, or total solutions.
更新:我找到的唯一解决方案是 twisted-suds ,这是经过修改以与Twisted一起使用的Suds的分支.
Update: The only solution I've found is twisted-suds, which is a fork of Suds modified to work with Twisted.
推荐答案
在Twisted上下文中, transport 的默认解释可能是twisted.internet.interfaces.ITransport
的实现.在这一层,您基本上要处理通过某种套接字发送和接收的原始字节(UDP,TCP和SSL是最常用的三种).这并不是SUDS/Twisted集成库真正感兴趣的.相反,您想要的是一个HTTP客户端,SUDS可以使用该HTTP客户端发出必要的请求,并显示所有响应数据,以便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的客户端部分)的实现,您会发现它实际上并没有做很多事情.将SOAPpy
粘贴到twisted.web.client.getPage
的大约20行代码.也就是说,它就是按照我上面描述的方式将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.buildSOAP
和SOAPpy.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 Client提供第三段代码,并让它们协调交互.
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
(aka回调)公开事件的事实并不意味着这是它只能工作的 方式.通过使用第三方库(例如greenlet
),可以提供基于协程的API,其中对异步操作的请求涉及将执行从一个协程切换到另一个协程,并且通过切换回原始协程来传递事件. .有一个名为 corotwine 的项目可以做到这一点.可以使用 为SUDS提供所需的HTTP客户端API.但是,不能保证.这取决于在上下文开关突然插入之前没有的情况下,SUDS是否不中断.这是SUDS的非常微妙和脆弱的属性,在以后的发行版中,SUDS开发人员可以轻松地(无意间甚至更改)它,因此即使您可以使用它,它也不是 ideal 的理想解决方案现在就可以工作(除非您可以以承诺的形式从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替代品.有很多竞争者(涵盖其中的几个).如果一切顺利,尝试更新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的传输方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!