Python: Как я могу использовать Twisted в качестве транспорта для SUDS? - PullRequest
12 голосов
/ 20 апреля 2010

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

Я хотел бы спросить, есть ли у кого-нибудь опыт, который онибыть готовым поделиться с использованием превосходной асинхронной транспортной функциональности Twisted с SUDS.Кажется, что подключение пользовательского скрученного транспорта было бы естественным подспорьем в 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.

1 Ответ

13 голосов
/ 20 апреля 2010

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

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

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

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

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

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

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

...