Python: как я могу использовать Twisted в качестве транспорта для SUDS?

У меня есть проект, основанный на Twisted, который используется для связи с сетевыми устройствами, и я добавляю поддержку нового поставщика (Citrix NetScaler), API которого является SOAP. К сожалению, поддержка SOAP в Twisted по-прежнему зависит от SOAPpy, который сильно устарел. На самом деле, что касается этого вопроса (я только что проверил), twisted.web.soap сама даже не обновлялась за 21 месяц!

Я хотел бы спросить, есть ли у кого-нибудь опыт использования превосходной функциональности асинхронного транспорта Twisted с SUDS. Кажется, что подключение пользовательского транспорта Twisted было бы естественным подходом к SUDS Client.options.transport, просто мне трудно обдумать это.

Я придумал способ асинхронно вызывать метод SOAP с SUDS, используя twisted.internet.threads.deferToThread(), но мне это кажется хаком.

Вот пример того, что я сделал, чтобы дать вам представление:

# 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.


person jathanism    schedule 19.04.2010    source источник


Ответы (1)


Интерпретация transport по умолчанию в контексте Twisted, вероятно, является реализацией twisted.internet.interfaces.ITransport. На этом уровне вы в основном имеете дело с необработанными байтами, отправляемыми и получаемыми через какой-либо сокет (UDP, TCP и SSL являются наиболее часто используемыми тремя). На самом деле это не то, что интересует библиотеку интеграции SUDS/Twisted. Вместо этого вам нужен HTTP-клиент, который SUDS может использовать для выполнения необходимых запросов и который представляет все данные ответа, чтобы SUDS мог определить, какой результат было. Другими словами, SUDS на самом деле не заботятся о необработанных байтах в сети. Что его волнует, так это HTTP-запросы и ответы.

Если вы изучите реализацию twisted.web.soap.Proxy (клиентская часть Twisted Web SOAP API), вы увидите, что на самом деле она мало что делает. Примерно 20 строк кода соединяют SOAPpy с twisted.web.client.getPage. То есть он подключает SOAPpy к Twisted именно так, как я описал выше.

В идеале SUDS должен предоставлять какой-то API типа SOAPpy.buildSOAP и SOAPpy.parseSOAPRPC (возможно, API-интерфейсы будут немного сложнее или будут принимать несколько дополнительных параметров — я не эксперт по SOAP, поэтому я не знаю, в некоторых API отсутствует что-то важное, но основная идея должна быть той же). Тогда вы могли бы вместо этого написать что-то вроде twisted.web.soap.Proxy на основе SUDS. Если twisted.web.client.getPage не предлагает достаточного контроля над запросами или достаточной информации об ответах, вы также можете использовать вместо этого twisted.web.client.Agent, который появился совсем недавно и предлагает гораздо больший контроль над всем процессом запроса/ответа. Но опять же, это действительно та же идея, что и текущий код на основе getPage, просто более гибкая/выразительная реализация.

Только что просмотрев документацию по API для Client.options.transport, можно сказать, что транспорт SUDS — это в основном HTTP-клиент. Проблема с такой интеграцией заключается в том, что SUDS хочет отправить запрос, а затем сразу же получить ответ. Поскольку Twisted в значительной степени основан на обратных вызовах, HTTP-клиентский API на основе Twisted не может немедленно вернуть ответ на SUDS. Он может возвращать только Deferred (или эквивалент).

Вот почему все работает лучше, если отношения перевернуты. Вместо того, чтобы давать SUDS HTTP-клиент для игры, дайте SUDS и HTTP-клиенту третью часть кода и позвольте ему организовать взаимодействие.

Тем не менее, невозможно заставить все работать, создав транспорт SUDS на основе Twisted (он же HTTP-клиент). Тот факт, что Twisted в основном использует Deferred (также известные как обратные вызовы) для отображения событий, не означает, что это единственный способ, которым он может работать. Используя стороннюю библиотеку, такую ​​как greenlet, можно предоставить API на основе сопрограммы, где запрос на асинхронную операцию включает в себя переключение выполнения с одной сопрограммы на другую, а события доставляются путем переключения обратно на исходную сопрограмму. Существует проект под названием corotwine, который может сделать именно это. Возможно это можно использовать для предоставления SUDS нужного типа HTTP-клиентского API; однако это не гарантируется. Это зависит от того, не сломается ли SUDS, когда внезапно вставляется переключатель контекста там, где его раньше не было. Это очень тонкое и хрупкое свойство SUDS, которое может быть легко изменено (даже непреднамеренно) разработчиками SUDS в будущем выпуске, поэтому, вероятно, это не идеальное решение, даже если вы можете его получить. работать сейчас (если вы не можете получить сотрудничество от сопровождающих SUDS в виде обещания протестировать их код в такой конфигурации, чтобы убедиться, что он продолжает работать).

Кроме того, причина, по которой поддержка SOAP в Twisted Web по-прежнему основана на SOAPpy и не менялась почти два года, заключается в том, что до сих пор не появилось явной замены для SOAPpy. Было много претендентов (Какие клиентские библиотеки SOAP существуют для Python и где находится документация для них? охватывает некоторые из них). Если все когда-нибудь уляжется, возможно, имеет смысл попытаться обновить встроенную в Twisted поддержку SOAP. До тех пор, я думаю, имеет смысл делать эти библиотеки интеграции отдельно, чтобы их было легче обновлять, и чтобы сам Twisted не оказался с большой кучей различных SOAP-интеграций, которые никому не нужны (что было бы быть хуже, чем текущая ситуация, когда есть только один модуль интеграции SOAP, который никому не нужен).

person Jean-Paul Calderone    schedule 20.04.2010
comment
Спасибо за ваш продуманный ответ. Я определенно думаю, что подходил к этому не с того уровня. По умолчанию SUDS использует urllib2 в качестве клиента, поэтому, возможно, лучше всего начать с Twisted Agent. Обязательно посмотрю и на corotwine. Я должен буду поглотить эту информацию и последующие действия! Кроме того, я болезненно осведомлен о саге Twisted SOAP, хотя SUDS кажется самым сильным соперником в наши дни и, безусловно, моим фаворитом. - person jathanism; 20.04.2010
comment
Я продолжаю возвращаться к этому ответу, поэтому думаю, что я на правильном пути. Спасибо еще раз! - person jathanism; 21.04.2010
comment
@jathanism, ты нашел решение для этого? Я нахожусь в похожей ситуации (хотя с добавленной морщинкой обработчика аутентификации HTTP, модифицированного для обхода ошибки Microsoft NTLM, ошибочно обозначенной как SPNEGO). - person deltab; 25.09.2013
comment
В первом абзаце HTTP-клиент, который может использовать SUDS и т. д., описывает, что suds называет транспортом, который сильно отличается от транспорта Twisted. - person deltab; 25.09.2013