Bestannen fan Google Drive distribúsje mei nginx

prehistoarje

It barde krekt dat ik earne mear dan 1.5 TB oan gegevens opslaan moast, en ek de mooglikheid foar gewoane brûkers leverje om it fia in direkte keppeling te downloaden. Sûnt tradisjoneel sokke bedraggen fan ûnthâld gean nei VDS, de kosten fan it hieren dy't is net hiel folle opnommen yn it projekt budzjet út de "neat te dwaan" kategory, en út de boarne gegevens ik hie in VPS 400GB SSD, dêr't, sels as ik woe, Ik koe net sette 1.5TB fan bylden sûnder lossless kompresje it sil slagje.

En doe herinnerde ik my dat as ik junk wiskje fan Google Drive, lykas programma's dy't allinich sille rinne op Windows XP, en oare dingen dy't fan it iene apparaat nei it oare binne ferpleatst sûnt de dagen dat it ynternet hielendal net sa fluch wie, net ûnbeheind ( bygelyks, dy 10-20 ferzjes fan de firtuele doaze wiene net wierskynlik te hawwen oare wearde as nostalgysk), dan alles moat passe hiel goed. Net earder sein as dien. En sa, troch de limyt te brekken op it oantal oanfragen oan 'e api (troch de manier, technyske stipe sûnder problemen ferhege it kwota fan oanfragen per brûker nei 100 yn 10 sekonden), streamden de gegevens fluch nei it plak fan har fierdere ynset .

Alles liket goed te wêzen, mar no moat it oerbrocht wurde oan de einbrûker. Boppedat, sûnder trochferwizings nei oare boarnen, en sa dat de persoan gewoan drukt op de "Download" knop en wurdt de lokkige eigner fan de dierbere triem.

Hjir, by God, gie ik yn allerhanne problemen. Earst wie it in skript yn AmPHP, mar ik wie net tefreden mei de lading dy't it makke (in skerpe sprong by it begjin nei 100% kearnkonsumpsje). Doe kaam de krulwrapper foar ReactPHP yn it spul, dy't goed paste yn myn winsken yn termen fan it oantal konsumearre CPU-syklusen, mar joech de snelheid hielendal net wat ik woe (it die bliken dat jo it ynterval foar oproppen gewoan kinne ferminderje curl_multi_select, mar dan hawwe wy deselde gluttony as de earste opsje ). Ik sels besocht te skriuwen in lytse tsjinst yn Rust, en it wurke frij fluch (it is ferrassend dat it wurke, jûn myn kennis), mar ik woe mear, en it wie ien of oare manier dreech om te passen it. Derneist hawwe al dizze oplossingen it antwurd op ien of oare manier nuver buffered, en ik woe it momint folgje dat de download fan bestân mei de grutste krektens einige.

Oer it algemien stie it in skoft krom, mar it slagge. Oant op in dei kaam ik mei in idee dat opmerklik wie yn syn gek: nginx kin yn teory dwaan wat ik wol, fluch wurkje en sels allerhanne perversjes mei konfiguraasje tastean. Wy moatte besykje - wat as it wurket? En nei in heale dei fan oanhâldend sykjen, waard in oplossing berne dy't al ferskate moannen stabyl wurke en foldie oan al myn easken.

It ynstellen fan NGINX

# Первым делом создадим в конфигах нашего сайта отдельную локацию.
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;
}

In koarte ferzje sûnder opmerkings is te sjen ûnder de spoiler

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;
}

Wy skriuwe in skript om al dit lok te behearjen

It foarbyld sil wêze yn PHP en bewust skreaun mei in minimum fan fluff. Ik tink dat elkenien dy't ûnderfining hat mei in oare taal dizze seksje kin yntegrearje mei myn foarbyld.

<?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));

Resultaten

Yn 't algemien makket dizze metoade it frij maklik om de distribúsje fan bestannen nei brûkers te organisearjen fan elke wolk opslach. Ja, sels fan telegram of VK, (foarsafier't de triemgrutte net grutter is as de tastiene grutte fan dizze opslach). Ik hie in idee gelyk oan dit, mar spitigernôch ik kom oer triemmen oant 2GB, en ik haw noch net fûn in metoade of module foar gluing antwurden út streamop, en it skriuwen fan in soarte fan wrappers foar dit projekt is ûnferstannich arbeidsintensyf.

Tank foar jo oandacht. Ik hoopje dat myn ferhaal teminsten in bytsje ynteressant as nuttich wie foar jo.

Boarne: www.habr.com

Add a comment