Отправка файла Python HTTPConnection с httplib, получение прогресса - PullRequest
2 голосов
/ 21 июня 2011

В приложении django я использую сторонний Python script , чтобы позволить пользователям загружать файлы в blip.tv через httplib.HTTPConnection.send на экземпляре EC2. Поскольку эти файлы обычно имеют большой размер, я буду использовать очередь сообщений для асинхронной обработки загрузки (RabbitMQ / Celery) и сообщать о ходе работы пользователю во внешнем интерфейсе.

httpconnection и send выполняются в этой части скрипта:

host, selector = urlparts = urlparse.urlsplit(url)[1:3]
h = httplib.HTTPConnection(host)
h.putrequest("POST", selector)
h.putheader("content-type", content_type)
h.putheader("content-length", len(data))
h.endheaders()
h.send(data)    
response = h.getresponse()
return response.status, response.reason, response.read()  

Функция getresponse () возвращается после завершения передачи файла. Как мне записать ход выполнения (предположим, что-то с помощью stdout.write), чтобы я мог записать это значение в структуру кэша для отображения (djangosnippets 678/679)? В качестве альтернативы, если есть лучшая практика для этого, я весь слух!

EDIT:

Поскольку я использовал urllib2 и использовал подсказку из этого вопроса , чтобы переопределить read () файла, чтобы получить ход загрузки. Кроме того, я использую плакат для генерации многочастного urlencode. Вот последний код:

from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
def Upload(video_id, username, password, title, description, filename):

    class Progress(object):
        def __init__(self):
            self._seen = 0.0

        def update(self, total, size, name):
            self._seen += size
            pct = (self._seen / total) * 100.0
            print '%s progress: %.2f' % (name, pct)

    class file_with_callback(file):
        def __init__(self, path, mode, callback, *args):
            file.__init__(self, path, mode)
            self.seek(0, os.SEEK_END)
            self._total = self.tell()
            self.seek(0)
            self._callback = callback
            self._args = args

        def __len__(self):
            return self._total

        def read(self, size):
            data = file.read(self, size)
            self._callback(self._total, len(data), *self._args)
            return data

    progress = Progress()
    stream = file_with_callback(filename, 'rb', progress.update, filename)

    datagen, headers = multipart_encode({
                                        "post": "1",
                                        "skin": "xmlhttprequest",
                                        "userlogin": "%s" % username,
                                        "password": "%s" % password,
                                        "item_type": "file",
                                        "title": "%s" % title.encode("utf-8"),
                                        "description": "%s" % description.encode("utf-8"),                                             
                                         "file": stream
                                         })    

    opener = register_openers()

    req = urllib2.Request(UPLOAD_URL, datagen, headers)
    response = urllib2.urlopen(req)
    return response.read()

Это работает только для входных файловых путей, а не для InMemoryUploadedFile, который поступает из входных данных формы (request.FILES), так как он пытается прочитать файл, уже сохраненный в памяти, я полагаю, и я получаю TypeError в строке : "stream = file_with_callback (имя файла, 'rb', progress.update, имя файла)":

coercing to Unicode: need string or buffer, InMemoryUploadedFile found

Как я могу добиться того же отчета о проделанной работе с загруженным пользователем файлом? Кроме того, будет ли это занимать много памяти при чтении процесса, подобного этому, возможно, решение для загрузки этого процесса загрузки для urllib2 будет работать лучше, но как реализовать ... Справка ооочень приветствуется

1 Ответ

1 голос
/ 28 июня 2011

Оказывается, что библиотека poster имеет функцию обратного вызова в multipart_encode, которую можно использовать для получения прогресса (выгрузка или загрузка).Хорошие вещи ...

Хотя я полагаю, что я технически ответил на этот вопрос, я уверен, что есть другие способы скинуть эту кошку, поэтому я опубликую больше, если найду другие методы или детали для этого.

Вот код:

def prog_callback(param, current, total):
    pct = 100 - ((total - current ) *100 )/ (total) 
    print "Progress: %s " % pct    


datagen, headers = multipart_encode({
                                    "post": "1",
                                    "skin": "xmlhttprequest",
                                    "userlogin": "%s" % username,
                                    "password": "%s" % password,
                                    "item_type": "file",
                                    "title": "%s" % title.encode("utf-8"),
                                    "description": "%s" % description.encode("utf-8"),                                             
                                     "file": filename
                                     }, cb=prog_callback)    

opener = register_openers()

req = urllib2.Request(UPLOAD_URL, datagen, headers)
response = urllib2.urlopen(req)
return response.read()
...