From cd4a0f5cb48239dc10cd2eb6e564cddc76116f5a Mon Sep 17 00:00:00 2001 From: eleksir Date: Sat, 28 Aug 2021 13:19:31 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20=D1=83=D1=82=D0=BE=D1=87?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE?= =?UTF-8?q?=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D0=B8=20=D0=BA=D1=8D=D1=88=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BE=D1=82=D0=B2?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B2=20yad.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Добавлены raw-функции, которые возвращают и http-заголовки ответа yad-а тоже * Уточнения в README.md и TODO * Мелкие косметические исправления. --- .gitignore | 3 +++ README.md | 40 ++++++++++++++++++++++++-------- TODO | 39 ++++++++++++++++++------------- bootstrap.sh | 0 data/sample_config.json | 4 ++-- lib/YadProxy/Lib.pm | 2 +- lib/Yandex/Disk.pm | 36 +++++++++++++++++++++++++++++ test/yad_file_info.pl | 2 ++ test/yad_file_info_raw.pl | 42 ++++++++++++++++++++++++++++++++++ test/yad_list_all_files_raw.pl | 31 +++++++++++++++++++++++++ test/yad_upload_file.pl | 1 + 11 files changed, 172 insertions(+), 28 deletions(-) mode change 100644 => 100755 bootstrap.sh create mode 100755 test/yad_file_info_raw.pl create mode 100755 test/yad_list_all_files_raw.pl diff --git a/.gitignore b/.gitignore index 90426f9..429ea2a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ +.idea/** +_Deparsed_XSubs.pm data/oauth/** +data/cache/** data/config.json data/fileindex/** vendor_perl/** diff --git a/README.md b/README.md index eb988ce..b84e574 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ ## Что это? -Своего рода API, делающий запросы в Yandex.Disk и выставляющий наружу листинг публично доступных файлов. +Своего рода API, делающий запросы в Yandex.Disk и выставляющий наружу листинг публично доступных файлов. Так же есть +утилитка, которая заливает каталог с файлами на yad. ## Зачем это нужно? @@ -11,21 +12,38 @@ ## Как это работает? +### Немного лирики +YaD использует в своей работе т.н. "публичные ссылки". Это ссылки на страничку где предлагается указанный файл +сохранить либо к себе на yad, чтобы оно засинкалось на комп через штатного клиента yad, либо скачать через браузер. +Нам такой вариант никак не подходит по понятным причинам. + +Но есть хорошие новости: в YaD есть прямые ссылки на файлы и эти ссылки "работают" напрямую, без дополнительных +http-заголовков. Но ту тже огорчу - время жизни таких ссылок ограничено и не регламентировано. Иными словами, +ссылку на объект хорошо бы каждый раз перед скачиванием запрашивать с yad. + +### В общих чертах + При загрузке файлов на диск сохраняется список урлов, по которым эти файлы будут доступны через веб-часть. +Как приятный бонус мы имеем dirlist в стиле nginx-а - со списком каталогов и файлов - в котором файлы - это по сути +ссылки на YaD, а каталоги... ну это каталоги :) Если обратиться к файлу напрямую, в веб-часть, то мы получаем редирект +на YaD. + +Также предполагается к использованию утилита **yad_upload_dir.pl**. Она аплодит каталог с файлами в YaD. + ## Как это запустить? Для запуска понадобятся: * Аккаунт @yandex.ru, через который это всё будет работать * uwsgi версии 2.0.15 или новее с поддержкой psgi -* perl-5.18 или новее (вплоть до 5.32.x) +* perl-5.18 или новее (вплоть до 5.32.x, дальше не тестировал) * пакеты perl-App-cpanminus и perl-local-lib Предполагается, что придётся подтянуть модули из CPAN-а с помощью [cpanm][4]. Для этого есть скрипт **bootstrap.sh** Как только всё вышеописанное в арсенале появится, можно переходить к [регистрации][1] приложения. Для работы понадобятся -все привилегии в разделе **Яндекс.Диск REST API**. Полученные ID и Пароль надо вписать в **data/config.json**, пример +все привилегии в разделе **Яндекс.Диск REST API**. Полученные **ID** и **Пароль** надо вписать в **data/config.json**, пример конфига **data/sample_config.json**. Также надо убедиться, что параметр "Код подтверждения" либо отсутствует в конфиге, либо закоментирован. @@ -42,21 +60,25 @@ ## Статус пректа -RC. Пока он *не готов*, хотя в принципе работает. Формально, он выйдет в релиз, как только закончатся пункты из файла -TODO. :) - -Ясное дело, что для серьёзного prodution-а это приложение не годится, во всяком случае в таком виде, как оно есть. -Как минимум необходимо организовать кэширование. Соответственно, корректно выдавать expires со стороны приложения, -чтобы, например, nginx мог без проблем кэшировать контент через proxy_cache. +Beta. Пока он *не готов*, хотя в принципе, как PoC, работает. Формально, он выйдет в релиз, как только закончатся пункты +из файла TODO. :) Планов и сроков нет, возможно через год, когда в нём появится необходимость. ## Завендоренные библиотеки 1. [Yandex::OAuth][5] 2. [Yandex::Disk][6] +## Справочная литература +1. [Yandex OAuth2 Reference][7] (FYI, для бОльшего понимания, как это работает, можно почитать документацию [imgur][8] на +эту тематику) +2. [Yandex Disk API reference][9] + [1]: https://oauth.yandex.ru/ [2]: https://uwsgi-docs.readthedocs.io/en/latest/Perl.html [3]: https://github.com/unbit/uwsgi [4]: https://github.com/miyagawa/cpanminus [5]: https://metacpan.org/pod/Yandex::OAuth [6]: https://metacpan.org/pod/Yandex::Disk +[7]: https://yandex.com/dev/oauth/doc/dg/concepts/about.html +[8]: https://api.imgur.com/oauth2 +[9]: https://yandex.com/dev/disk/api/concepts/about.html diff --git a/TODO b/TODO index f90abbb..c896c31 100644 --- a/TODO +++ b/TODO @@ -1,19 +1,26 @@ -* Реализовать проверку кэша на тухлость (Yandex.Диск зачем-то регулярно - обновляет ссылки, период обновления я пока не выявил). Делать по приходу - клиента. -* Из вышележащего следует, что можно пред-генерировать практически всё. Ибо - оно зависит целиком и полностью от полного списка, который нам выдаёт yad и - по факту является статическим контентом. То есть вполне можно полностью - пред-генерировать все страницы и все редиректы. И по-хорошему так и надо - делать. -* Не аплодить файлы, которые уже есть в диске (проверка по длине + md5 или sha). +* Реализовать проверку кэша на тухлость (Yandex.Диск зачем-то регулярно обновляет ссылки, период обновления я пока не + выявил). Делать по приходу клиента. In fact, придётся делать запрос в yad на каждый redirect. Т.к. у yad выставлен + заголовок Сache-Сontrol в значение no-cache, иными словами время жизни ссылки на файл не регламентировано. То есть от + идеи построения file index и вписывания в него ссылок прямо на yad придётся отказаться и на каждый запрос на файл + генерировать 302, делая подзапрос в yad. + +* Не аплодить файлы, которые уже есть в диске (проверка по длине + md5 или sha). (Утилита yad_upload_dir.pl) + +* Нужна утилита, которая синкает файлы из локального каталога в каталог на yad, удаляя в целевом каталоге всё лишнее. + * Исправить листинг каталогов, чтобы без слеша был 301-й редирект. -* Исправить листинг файлов, чтобы по ссылке на файл отображался локальный урл, - а при переходе на него происходил 302-й редирект. -* Добавить режим *настоящего* проксирования, а не редиректа. До кучи. Но это - опционально, факультативно, так редиректы работают нормально сами по себе. + +* Исправить листинг файлов, чтобы по ссылке на файл отображался локальный урл, а при переходе на него происходил 302-й + редирект в yad. + +* Добавить режим *настоящего* проксирования, а не редиректа. До кучи. Но это опционально, факультативно, так редиректы + работают нормально сами по себе. + * Добавить проверки corner-case-ов. + * Описать утилиты. -* Организовать многопоточную загрузку файлов на Yandex.Disk, вероятно, через - AnyEvent::HTTP, т.к. у него есть встроенное огранчение на количество - подключений к одному серверу, либо через CORO::LWP. + +* Организовать многопоточную загрузку файлов на Yandex.Disk, вероятно, через AnyEvent::HTTP, т.к. у него есть встроенное + огранчение на количество подключений к одному серверу, либо через CORO::LWP. + +* Хранить данные об oauth на в data/cache, а в data/oauth diff --git a/bootstrap.sh b/bootstrap.sh old mode 100644 new mode 100755 diff --git a/data/sample_config.json b/data/sample_config.json index 51e32e7..d0c14a0 100644 --- a/data/sample_config.json +++ b/data/sample_config.json @@ -19,6 +19,6 @@ # Всё что относится к работе с yandex.api "ID" : "ID полученный при регистрации прилодения на oauth.yandex.ru", - "Пароль" : "Пароль полученный при регистрации прилодения на oauth.yandex.ru", - "Код подтверждения" : "Циферьки из браузера - код подтверждения", + "Пароль" : "Пароль полученный при регистрации приложения на oauth.yandex.ru", + "Код подтверждения" : "Циферьки из браузера - код подтверждения" } diff --git a/lib/YadProxy/Lib.pm b/lib/YadProxy/Lib.pm index 6d71b6d..90c05f6 100644 --- a/lib/YadProxy/Lib.pm +++ b/lib/YadProxy/Lib.pm @@ -38,7 +38,7 @@ sub GetAccessToken { } my $token = RefreshAccessToken ($refresh_token); - # yad обычно выдаёт токен на год, скинем с этого 1 минуту :) чтобы уж точно + # yad обычно выдаёт токен на год, скинем с этого 1 минуту :) чтобы уж точно $cache->set ('refresh_token', $token->{refresh_token}, 'never'); $cache->set ('access_token', $token->{access_token}, $token->{expires_in} - 60); $access_token = $token->{access_token}; diff --git a/lib/Yandex/Disk.pm b/lib/Yandex/Disk.pm index 536b382..42e4040 100644 --- a/lib/Yandex/Disk.pm +++ b/lib/Yandex/Disk.pm @@ -225,6 +225,22 @@ sub fileInfo { return $json_res; } +sub fileInfoRaw { + my $self = shift; + my %opt = @_; + my $path = $opt{-path} || croak "Specify -path param"; + + my $param = '?path=' . uri_escape($path); + my $res = $self->__request('https://cloud-api.yandex.net/v1/disk/resources' . $param, 'GET'); + + my $code = $res->code; + if ($code ne '200') { + croak "Error on fileInfo. Error: " . $res->status_line; + } + + return $res; +} + sub listFiles { my $self = shift; my %opt = @_; @@ -265,6 +281,26 @@ sub listAllFiles { return $json_res->{items}; } +sub listAllFilesRaw { + my $self = shift; + my %opt = @_; + my $limit = $opt{-limit} || 999999; + my $media_type = $opt{-media_type}; + my $offset = $opt{-offset}; + $offset = 0 if not $offset; + + my $param = "?limit=$limit&offset=$offset"; + $param .= '&media_type=' . $media_type if $media_type; + + my $res = $self->__request('https://cloud-api.yandex.net/v1/disk/resources/files' . $param, 'GET'); + my $code = $res->code; + if ($code ne '200') { + croak "Error on listFiles. Error: " . $res->status_line; + } + + return $res; +} + sub lastUploadedFiles { my $self = shift; my %opt = @_; diff --git a/test/yad_file_info.pl b/test/yad_file_info.pl index d546559..afbfe1d 100755 --- a/test/yad_file_info.pl +++ b/test/yad_file_info.pl @@ -8,6 +8,8 @@ use open qw (:std :utf8); use English qw ( -no_match_vars ); use version; our $VERSION = qw (1.0); +use Carp qw (croak); + my $workdir; # сменим рабочий каталог diff --git a/test/yad_file_info_raw.pl b/test/yad_file_info_raw.pl new file mode 100755 index 0000000..04f8e8d --- /dev/null +++ b/test/yad_file_info_raw.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl + +use 5.018; +use strict; +use warnings; +use utf8; +use open qw (:std :utf8); +use English qw ( -no_match_vars ); +use version; our $VERSION = qw (1.0); + +use Carp qw (croak); + +my $workdir; + +# сменим рабочий каталог +BEGIN { + use Cwd qw (chdir abs_path); + my @CWD = split /\//xms, abs_path ($PROGRAM_NAME); + if ($#CWD > 1) { $#CWD = $#CWD - 2; } + $workdir = join '/', @CWD; + chdir $workdir; +} + +use lib ("$workdir/lib", "$workdir/vendor_perl", "$workdir/vendor_perl/lib/perl5"); +use YadProxy::Conf qw (LoadConf); +use YadProxy::Lib qw (GetAccessToken); +use Yandex::Disk; +use Data::Dumper; + +my $c = LoadConf (); +my $remote_dir = ''; +my $file = 'test_file.txt'; + +if ($c->{remote_dir} && $c->{remote_dir} ne '') { + $remote_dir = $c->{remote_dir}; +} + +my $disk = Yandex::Disk->new ( -token => GetAccessToken ); +say Dumper $disk->fileInfoRaw ( -path => sprintf ('%s/%s', $remote_dir, $file)); + +__END__ +# vim: set ft=perl noet ai ts=4 sw=4 sts=4: \ No newline at end of file diff --git a/test/yad_list_all_files_raw.pl b/test/yad_list_all_files_raw.pl new file mode 100755 index 0000000..a4845a6 --- /dev/null +++ b/test/yad_list_all_files_raw.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +use 5.018; +use strict; +use warnings; +use utf8; +use open qw (:std :utf8); +use English qw ( -no_match_vars ); +use version; our $VERSION = qw (1.0); + +my $workdir; + +# сменим рабочий каталог +BEGIN { + use Cwd qw (chdir abs_path); + my @CWD = split /\//xms, abs_path ($PROGRAM_NAME); + if ($#CWD > 1) { $#CWD = $#CWD - 2; } + $workdir = join '/', @CWD; + chdir $workdir; +} + +use lib ("$workdir/lib", "$workdir/vendor_perl", "$workdir/vendor_perl/lib/perl5"); +use YadProxy::Lib qw (GetAccessToken); +use Yandex::Disk; +use Data::Dumper; + +my $disk = Yandex::Disk->new ( -token => GetAccessToken ); +say Dumper $disk->listAllFilesRaw (); + +__END__ +# vim: set ft=perl noet ai ts=4 sw=4 sts=4: \ No newline at end of file diff --git a/test/yad_upload_file.pl b/test/yad_upload_file.pl index 29e1b53..aaecc89 100755 --- a/test/yad_upload_file.pl +++ b/test/yad_upload_file.pl @@ -25,6 +25,7 @@ use YadProxy::Conf qw (LoadConf); use YadProxy::Lib qw (GetAccessToken); use Yandex::Disk; use Data::Dumper; +use Carp qw (croak); my $c = LoadConf (); my $remote_dir = '/';