「HTTP APIへのFTPインターフェイス」として最もよく記述できるものを実装しようとしています。基本的には、サイトのユーザーファイルを管理するために使用できる既存のREST APIがあります。このAPIをFTPサーバーとして再公開するメディエータサーバーを構築しています。したがって、Filezillaなどでログインしてファイルを一覧表示したり、新しいファイルをアップロードしたり、古いファイルを削除したりすることができます。大きなファイルをTwisted、FTP、 "streaming"する
(FTP)サーバではtwisted.protocols.ftp
、HTTPクライアントではtwisted.web.client
。
私が対抗しているのは、ユーザーがファイルをダウンロードしようとすると、そのファイルをHTTP応答からFTP応答に「ストリーミング」することです。アップロードと同様です。
最も簡単なアプローチは、HTTPサーバーからファイル全体をダウンロードしてから、内容を変更してユーザーに送信することです。この問題は、任意のファイルが何ギガバイトも大きくなることがある(ドライブイメージ、ISOファイルなどを考える)ことがあります。しかし、このアプローチでは、ファイルの内容は、APIからダウンロードしてからユーザーに送信するまでの間にメモリに保持されます。
私の解決策は、APIのHTTPレスポンスからデータのチャンクを取得するときに、そのチャンクをFTPユーザーに送信したいだけです。 と思われます。
私の「カスタムFTP機能」については、ftp.FTPShell
のサブクラスを使用しています。この読み取りメソッドopenForReading
は、実装がIReadFile
のDeferredを返します。
以下は、「ストリーミングHTTP」用の私の(初期の、単純な)実装です。私はfetch
関数を使ってHTTPリクエストを設定し、私が渡すコールバックはレスポンスから取得した各チャンクで呼び出されます。
私は、バッファオブジェクトをftp._FileReader
で必要とされるファイルのようなオブジェクトとして使用して、HTTPとFTPの間でチャンクを転送するために何らかの2端バッファオブジェクトを使用できると思っていましたが、 send
コールからの消費者は、すぐにバッファを閉じます(空の文字列を返すため、読み込むデータがないなど)。したがって、HTTP応答チャンクの受信を開始する前に空のファイルを「送信」しています。
私は閉じていますが、何か不足していますか?私は間違った道を歩いていますか?私は何をしたいのですか本当に(私はそれが大変疑わしいですか)?サイドノートとして
from twisted.web import client
import urlparse
class HTTPStreamer(client.HTTPPageGetter):
def __init__(self):
self.callbacks = []
def addHandleResponsePartCallback(self, callback):
self.callbacks.append(callback)
def handleResponsePart(self, data):
for cb in self.callbacks:
cb(data)
client.HTTPPageGetter.handleResponsePart(self, data)
class HTTPStreamerFactory(client.HTTPClientFactory):
protocol = HTTPStreamer
def __init__(self, *args, **kwargs):
client.HTTPClientFactory.__init__(self, *args, **kwargs)
self.callbacks = []
def addChunkCallback(self, callback):
self.callbacks.append(callback)
def buildProtocol(self, addr):
p = client.HTTPClientFactory.buildProtocol(self, addr)
for cb in self.callbacks:
p.addHandleResponsePartCallback(cb)
return p
def fetch(url, callback):
parsed = urlparse.urlsplit(url)
f = HTTPStreamerFactory(parsed.path)
f.addChunkCallback(callback)
from twisted.internet import reactor
reactor.connectTCP(parsed.hostname, parsed.port or 80, f)
、これが唯一のツイストと私の二日目です - 私はツイストの古いバージョンに基づいていても、偉大な出発点となっているデイブPeticolas' Twisted Introduction、通読昨日の大半を費やし。
つまり、私はかもしれません。は間違っていると言います。
あなたは正しく、私は 'IPushProducer'を実装する必要がありました。私はあなたが言及した "高速HTTP"シナリオのための保護手段をまだ持っていませんが、かなりうまくいきます。ありがとう! – eternicode