Failu izplatīšana no Google diska, izmantojot nginx

Aizvēsture

Sagadījās, ka man vajadzēja kaut kur uzglabāt vairāk nekā 1.5 TB datu, kā arī nodrošināt iespēju parastajiem lietotājiem tos lejupielādēt, izmantojot tiešu saiti. Tā kā tradicionāli šādi atmiņas apjomi aiziet uz VDS, tad īres izmaksas, kas nav īpaši iekļautas projekta budžetā no kategorijas “nav ko darīt” un no avota datiem man bija VPS 400GB SSD, kur, pat ja es gribēju, nevarēju ielikt 1.5TB attēlus bez bezzudumu kompresijas izdosies.

Un tad es atcerējos, ka, ja es izdzēšu nevēlamo saturu no Google diska, piemēram, programmas, kas darbosies tikai operētājsistēmā Windows XP, un citas lietas, kas pārvietojas no vienas ierīces uz otru kopš tiem laikiem, kad internets nemaz nebija tik ātrs, ne neierobežots ( piemēram, tām 10-20 virtuālās kastes versijām diez vai būtu cita vērtība kā tikai nostalģiska), tad visam vajadzētu ļoti labi iederēties. Ne ātrāk pateikts, kā izdarīts. Un tā, pārkāpjot api pieprasījumu skaita ierobežojumu (starp citu, tehniskais atbalsts bez problēmām palielināja pieprasījumu kvotu vienam lietotājam līdz 100 10 000 sekundēs), dati ātri aizplūda uz tā tālākās izvietošanas vietu. .

Šķiet, ka viss ir labi, bet tagad tas ir jānodod gala lietotājam. Turklāt bez novirzīšanas uz citiem resursiem, bet tā, lai cilvēks vienkārši nospiestu pogu “Lejupielādēt” un kļūtu par laimīgo vērtīgā faila īpašnieku.

Lūk, ar Dievu, es iekļuvu visādās nepatikšanās. Sākumā tas bija skripts AmPHP, bet mani neapmierināja tā radītā slodze (straujš lēciens sākumā līdz 100% pamata patēriņam). Tad spēlēja ReactPHP čokurošanās iesaiņojums, kas diezgan atbilst manām vēlmēm patērēto CPU ciklu skaita ziņā, taču nedeva ātrumu, ko gribēju (izrādījās, ka var vienkārši samazināt zvanīšanas intervālu curl_multi_select, bet tad mums ir rijība, kas līdzīga pirmajai opcijai ). Es pat mēģināju uzrakstīt nelielu pakalpojumu Rustā, un tas strādāja diezgan ātri (pārsteidzoši, ka tas strādāja, ņemot vērā manas zināšanas), bet es gribēju vairāk, un to bija kaut kā grūti pielāgot. Turklāt visi šie risinājumi kaut kā dīvaini buferēja atbildi, un es gribēju izsekot brīdi, kad faila lejupielāde beidzās ar vislielāko precizitāti.

Vispār kādu laiku bija šķībi, bet izdevās. Līdz kādu dienu man radās ideja, kas bija ievērojama savā trakumā: nginx teorētiski var darīt, ko gribu, ātri strādāt un pat ar konfigurāciju pieļaut visādas perversijas. Mums ir jāpamēģina – ja nu tas izdodas? Un pēc pusdienas neatlaidīgiem meklējumiem piedzima risinājums, kas stabili darbojās vairākus mēnešus un atbilda visām manām prasībām.

Notiek NGINX iestatīšana

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

Īsa versija bez komentāriem redzama zem spoilera

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

Mēs rakstām skriptu, lai pārvaldītu visu šo laimi

Piemērs būs PHP un apzināti rakstīts ar minimālu komplektu. Es domāju, ka ikviens, kam ir pieredze ar jebkuru citu valodu, varēs integrēt šo sadaļu, izmantojot manu piemēru.

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

Rezultāti

Kopumā šī metode ļauj diezgan viegli organizēt failu izplatīšanu lietotājiem no jebkuras mākoņa krātuves. Jā, pat no telegrammas vai VK (ar nosacījumu, ka faila lielums nepārsniedz šīs krātuves pieļaujamo izmēru). Man bija līdzīga ideja šis, bet diemžēl sastopos ar failiem līdz 2GB, un vēl neesmu atradis metodi vai moduli atbilžu līmēšanai no augšpuses, un kaut kādu iesaiņojumu rakstīšana šim projektam ir nepamatoti darbietilpīga.

Paldies par jūsu uzmanību. Es ceru, ka mans stāsts jums bija vismaz nedaudz interesants vai noderīgs.

Avots: www.habr.com

Pievieno komentāru