Докачка при аплоаде

Valery Kholodkov valery+nginxru на grid.net.ru
Сб Ноя 28 23:13:50 MSK 2009


Дмитрий Дедюхин пишет:
>> Да, возможна.
> 
> Валерий, я видел у вас в гите экспериментальную ветку с поддержкой дозакачки, но так и не сподобился посмотреть в код.
> Можете в двух словах рассказать, как это реализовано в аплоад-модуле?
> В браузере стандартный input type=file никак не может это реализовать, там нельзя начать загружать файл по смещению. Вы рассчитываете на плагины (Flash или Silverlight)?

Нет, загрузку файлов по частям можно реализовать используя Google Gears 
и Blob API. Приблизительно так:

var fileList = {};

function browse() {
     var desktop = google.gears.factory.create('beta.desktop');

     desktop.openFiles(function(files) {
         for (var i=0; i < files.length; i++) {
             if(!fileList[files[i].name]) {

                 fileList[files[i].name] = {
                     filename: files[i].name,
                     uploaded: 0,
                     length: files[i].blob.length,
                     blob: files[i].blob,
                     sessionkey: sessionkey(),
                 };
             }
         }
         $('#upload').html('<a href="#upload" onclick="return 
upload();">Upload</a>');
     });
}

function upload() {
     var chunkLength, chunk;

     for(file in mylist) {
         if((file.uploaded < file.length && !file.error)) {
             chunkLength = min(file.uploaded + CHUNK_BYTES, file.length);
             chunk = file.blob.slice(file.uploaded, (chunkLength - 
file.uploaded));
             sendChunk(file, chunk, file.uploaded, chunkLength, 
file.length, file.sessionkey);
         }
     }
}

function sendChunk(entry, chunk, start, end, total, sessionkey {

     var req = google.gears.factory.create('beta.httprequest');

     req.open('POST', '/upload');

     var headers = {
         'Content-Disposition': 'attachment; name="'+sessionkey+'"; 
filename="'+file+'"',
         'Content-Type': 'application/octet-stream',
         'Content-Range': 'bytes '+start+'-'+end+'/'+total
     };
     for(var h in headers) { if(headers.hasOwnProperty(h)) { 
req.setRequestHeader(h, headers[x]); } }

     req.onreadystatechange = function(){
         if(req.readyState == 4 && req.status == 205) {
             entry.uploaded = end;
             upload();
         }
     }
     req.send(chunk);
}

Далее:

<div>
     <a href="#select" onclick="return browse();">Select files</a>
     <span id="upload"></span>
</div>

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

На сервере нужен upload module из следующей ветки:

http://github.com/vkholodkov/nginx-upload-module/tree/partial-upload

Директива upload_state_store задает каталог, в котором модуль будет 
сохранять состояние загрузки. А именно, список сегментов файла, которые 
полностью загружены. Таким образом, загрузки возобновляемы между 
перезапусками nginx.

Принцип взаимодействия с бакэндом аналогичный.

Эта ветка экспериментальная, поэтому могут возникнуть всевозможные 
неожиданности.

-- 
Best regards,
Valery Kholodkov



Подробная информация о списке рассылки nginx-ru