12

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

我想问是否有人愿意分享使用 Twisted 出色的异步传输功能和 SUDS 的经验。似乎插入自定义的 Twisted 传输将很自然地适合 SUDS' Client.options.transport,我只是很难把头绕在它周围。

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

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

# 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()调用的返回推迟到完成,而不是阻塞。但正如我所说,感觉不对。

提前感谢任何帮助、指导、反馈、批评、侮辱或整体解决方案。

更新:我发现的唯一解决方案是twisted-suds,它是 Suds 的一个分支,经过修改后可以与 Twisted 一起使用。

4

1 回答 1

13

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

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

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

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

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

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

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

于 2010-04-20T00:48:02.780 回答