Дистрибуција датотека са Гоогле диска помоћу нгинк-а

praistorija

Десило се да сам морао негде да ускладиштим више од 1.5 ТБ података, а такође и да омогућим обичним корисницима да их преузму путем директне везе. Пошто традиционално такве количине меморије иду на ВДС, цена изнајмљивања која није много укључена у буџет пројекта из категорије „ништа да се ради“, а према изворним подацима имао сам ВПС 400ГБ ССД, где, чак и ако сам желео, нисам могао да ставим 1.5 ТБ слика без компресије без губитака, успеће.

А онда сам се сетио да ако избришем смеће са Гугл диска, као што су програми који ће радити само на Виндовс КСП-у, и друге ствари које се селе са једног уређаја на други још од дана када Интернет уопште није био тако брз, није неограничен ( на пример, тих 10-20 верзија виртуелне кутије вероватно неће имати никакву вредност осим носталгичне), онда би све требало веома добро да се уклопи. Не пре речено него учињено. И тако, пробијајући ограничење броја захтева ка АПИ-ју (успут, техничка подршка је без проблема повећала квоту захтева по кориснику на 100 за 10 секунди), подаци су брзо текли до места његовог даљег постављања .

Чини се да је све добро, али сада то треба пренети до крајњег корисника. Штавише, без икаквих преусмеравања на друге ресурсе, већ тако да особа једноставно притисне дугме „Преузми“ и постане срећан власник драгоцене датотеке.

Ето, богами, ушао сам у свакакве невоље. У почетку је то била скрипта у АмПХП-у, али нисам био задовољан оптерећењем које је створио (оштар скок на почетку на 100% потрошње језгра). Затим је у игру ушао цурл омот за РеацтПХП, који се сасвим уклапао у моје жеље у смислу броја потрошених ЦПУ циклуса, али уопште није дао брзину какву сам желео (испоставило се да можете једноставно смањити интервал позивања цурл_мулти_селецт, али онда имамо прождрљивост сличну првој опцији). Чак сам покушао да напишем малу услугу у Русту, и то је функционисало прилично брзо (изненађујуће је да је функционисало, с обзиром на моје знање), али сам желео више, и било је некако тешко прилагодити га. Поред тога, сва ова решења су некако чудно баферовала одзив, а желео сам да са највећом тачношћу пратим тренутак када се преузимање датотеке завршило.

Уопште, неко време је било криво, али је успело. Све док једног дана нисам дошао на идеју која је била изузетна по својој лудости: нгинк, у теорији, може да ради шта хоћу, да ради брзо, па чак и да дозвољава све врсте перверзија са конфигурацијом. Морамо да покушамо - шта ако успе? И након пола дана упорног тражења, настало је решење које је стабилно радило неколико месеци и испуњавало све моје захтеве.

Подешавање НГИНКС-а

# Первым делом создадим в конфигах нашего сайта отдельную локацию.
location ~* ^/google_drive/(.+)$ {

    # И закроем её от посторонних глаз (рук, ног и прочих частей тела).
    internal;

    # Ограничим пользователям скорость до разумных пределов (я за равноправие).
    limit_rate 1m;

    # А чтоб nginx мог найти сервера google drive укажем ему адрес резолвера.
    resolver 8.8.8.8;

    # Cоберем путь к нашему файлу (мы потом передадим его заголовками).
    set $download_url https://www.googleapis.com/drive/v3/files/$upstream_http_file_id?alt=media;

    # А так же Content-Disposition заголовок, имя файла мы передадим опять же в заголовках.
    set $content_disposition 'attachment; filename="$upstream_http_filename"';

    # Запретим буфферизировать ответ на диск.
    proxy_max_temp_file_size 0;

    # И, что немаловажно, передадим заголовок с токеном (не знаю почему, но в заголовках из $http_upstream токен передать не получилось. Вернее передать получилось, но скорей всего его где-то нужно экранировать, потому что гугл отдает ошибку авторизации).
    proxy_set_header Authorization 'Bearer $1';

    # И все, осталось отправить запрос гуглу по ранее собранному нами адресу.
    proxy_pass $download_url;

    # А чтоб у пользователя при скачивании отобразилось правильное имя файла мы добавим соответствующий заголовок.
    add_header Content-Disposition $content_disposition;

    # Опционально можно поубирать ненужные нам заголовки от гугла.
    proxy_hide_header Content-Disposition;
    proxy_hide_header Alt-Svc;
    proxy_hide_header Expires;
    proxy_hide_header Cache-Control;
    proxy_hide_header Vary;
    proxy_hide_header X-Goog-Hash;
    proxy_hide_header X-GUploader-UploadID;
}

Кратка верзија без коментара се може видети испод спојлера

location ~* ^/google_drive/(.+)$ {
    internal;
    limit_rate 1m;
    resolver 8.8.8.8;
    
    set $download_url https://www.googleapis.com/drive/v3/files/$upstream_http_file_id?alt=media;
    set $content_disposition 'attachment; filename="$upstream_http_filename"';
    
    proxy_max_temp_file_size 0;
    proxy_set_header Authorization 'Bearer $1';
    proxy_pass $download_url;
    
    add_header Content-Disposition $content_disposition;
    
    proxy_hide_header Content-Disposition;
    proxy_hide_header Alt-Svc;
    proxy_hide_header Expires;
    proxy_hide_header Cache-Control;
    proxy_hide_header Vary;
    proxy_hide_header X-Goog-Hash;
    proxy_hide_header X-GUploader-UploadID;
}

Пишемо сценарио да управљамо свом овом срећом

Пример ће бити у ПХП-у и намерно написан са минималним комплетом. Мислим да ће свако ко има искуства са било којим другим језиком моћи да интегрише овај одељак користећи мој пример.

<?php

# Токен для Google Drive Api.
define('TOKEN', '*****');

# ID файла на гугл диске
$fileId = 'abcdefghijklmnopqrstuvwxyz1234567890';

# Опционально, но так как мы не передаем никаких данных - почему бы и нет?
http_response_code(204);

# Зададим заголовок c ID файла (в конфигах nginx мы потом получим его как $upstream_http_file_id).
header('File-Id: ' . $fileId);
# И заголовок с именем файла (соответственно $upstream_http_filename).
header('Filename: ' . 'test.zip');
# Внутренний редирект. А еще в адресе мы передадим токен, тот самый, что мы получаем из $1 в nginx.
header('X-Accel-Redirect: ' . rawurlencode('/google_drive/' . TOKEN));

Резултати

Генерално, овај метод прилично олакшава организацију дистрибуције датотека корисницима из било ког складишта у облаку. Да, чак и из телеграма или ВК-а, (под условом да величина датотеке не прелази дозвољену величину овог складишта). Имао сам сличну идеју ово, али нажалост наилазим на фајлове до 2ГБ, и још нисам нашао метод или модул за лепљење одговора од упстреама, а писање неке врсте омота за овај пројекат је неразумно напорно.

Хвала на пажњи. Надам се да вам је моја прича била бар мало занимљива или корисна.

Извор: ввв.хабр.цом

Додај коментар