Все было хорошо, пока пользователи не захотели скачивать понравившиеся альбомы целиком на свои компьютеры.
Под катом раскажу как мы реализовали это.
Первое решение, которое приходит в голову — создавать архив каждого альбома и отдавать его пользователю.
Главная причина по которой мы отказались от этого варианта: у нас много музыки и создание архива для каждого альбома означает, что количество дискового пространства нужно умножить на два — пока мы себе этого позволить не можем.
Нам показалось, что идеально было бы формировать архив альбома по запросу и на лету. Если при создании архива отключить сжатие, то накладные расходы должны быть небольшими, ну и сами расходы для нас не особо критичны — на данный момент у нас большой запас по процессорному времени и оперативной памяти, в отличие от постоянного хранилища.
Поиск модуля для nginx, или каких-то других готовых решений, результата не дал — будем реализовывать сами — задача не сложная.
Для архивации будем использовать стандартную программу zip, без сжатия и данные не будем писать в файл, а направим сразу в stdout. Для такой цели логичнее было бы использовать tar, но у нас обычные пользователи и для многих будет загадкой что делать с tar или tar.gz архивом.
Теперь нам надо как-то передать сжатые данные nginx-у, который отдаст их пользователю.
Для этих целей на шелле был написан простенький cgi-скрипт:
#!/bin/bash # Корневая директория, от нее будут идти пути в архиве и внутри нее хранятся все альбомы homeDir="/storage/media/audio" # Имя скачиваемой директории передается в строке запроса, строку запроса надо декодировать downloadDir=$(echo $QUERY_STRING | sed -f urldecode.sed) # Переходим в корневую директорию pushd "$homeDir" > /dev/null # Если директория существует - на лету упаковываем ее в zip без сжатия и возвращаем в качестве тела ответа if [ -d $downloadDir ] && [ ! -z $downloadDir ] then echo "Content-Type: application/octet-stream" echo "Content-Disposition: attachment; filename=$downloadDir.zip" echo "" /usr/bin/zip -r -0 - "$downloadDir" else echo "Status: 404 Not Found" echo "Content-Type: text/html" echo "" echo "<h1>404 File not found!</h1>" fi # Возвращаемся в начальную директорию popd > /dev/null
Скрипт прост, думаю дополнительно его комментировать будет излишне.
Так как имя директории приходит url-кодированное, мы его раскодируем, для этого используем sed и небольшой скрипт для него, скрипт берем здесь и кладём рядом с нашим cgi-скриптом.
Все знают, что nginx поддерживает FastCGI и не поддерживает CGI, чтобы наш скрипт все таки работал будем использовать Fcgiwrap.
Ставим:
apt-get install fcgiwrap
И конфигурируем:
# support for cgi scripts (require fcgiwrap) location ~ \.cgi$ { gzip off; try_files $uri =404; # pass scripts to fcgiwrap fastcgi_pass unix:/var/run/fcgiwrap.socket; # Используем стандартные параметры include /etc/nginx/fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_ignore_client_abort off; }
Перезапускаем nginx и можно пользоваться: /download.cgi? имя_директории_для скачивания
ссылка на оригинал статьи http://habrahabr.ru/post/194904/
Добавить комментарий