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

У меня есть проект, основанный на 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 ответ

Решение

Интерпретация транспорта по умолчанию в контексте 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 (так называемые обратные вызовы) для выставления событий не означает, что это единственный способ, которым он может работать. Используя стороннюю библиотеку, такую ​​как greenletможно предоставить API на основе сопрограмм, в котором запрос асинхронной операции включает переключение выполнения с одной сопрограммы на другую, а события доставляются путем возврата к исходной сопрограмме. Есть проект под названием Corotwine, который может сделать именно это. Может быть возможно использовать это, чтобы предоставить SUDS тот тип API клиента HTTP, который он хочет; однако это не гарантировано. Это зависит от того, что SUDS не прерывается, когда контекстное переключение внезапно вставляется туда, где раньше его не было. Это очень тонкое и хрупкое свойство SUDS и может быть легко изменено (непреднамеренно даже) разработчиками SUDS в будущем выпуске, поэтому, вероятно, это не идеальное решение, даже если вы можете заставить его работать сейчас (если вы не можете получите поддержку от сопровождающих SUDS в форме обещания протестировать их код в такой конфигурации, чтобы убедиться, что он продолжает работать).

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

Другие вопросы по тегам