Форум русскоязычного сообщества Ubuntu


Считаете, что Ubuntu недостаточно дружелюбна к новичкам?
Помогите создать новое Руководство для новичков!

Автор Тема: Клиент синхронизации с Yandex.disk (Python3, OpenSource)  (Прочитано 31175 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
В рамках разработки индикатора (GUI обертки для CLI демона от яндекса - в подписи) уже неоднократно возникало желание сделать "свою синхронизацию".

У яндекса есть довольно удобный REST API к диску и тоже вполне юзабельный WebDav API. И в этих API есть некоторые "плюшки", которые они никак в своего клиента протягивать не хотят (та же очистка корзины).

В очередной раз появившийся интерес начал оформляться во что-то реальное и я решил сформулировать цели и предварительный план этого проекта. Мало ли кто заинтересуется совместной разработкой, да и как обычно - тестеры будут крайне полезны.

И так, к делу:


Глобальная Идея:
Создать аналог CLI утилиты/демона yandex-disk в виде библиотеки/класса/отдельного процесса, на Python3, использующего REST API яндекс.диска.
Разработку предполагается вести изначально через GitHub репозиторий. Проект будет развиваться под OpenSource лицензией.

Ожидаемые бенефиты:
1. Можно сделать индикатор независимым от пропиетарного CLI демона от яндекса (это упросит установку и распространение индикатора и может пригодиться в других проектах)
2. Можно реализовать то, чего нет в демоне от яндекса (например: очистку корзины)
3. "Бесшовная" интеграция с индикатором (упростит обработку ошибок, сделает ненужным оба механизма контроля за состоянием демона: по таймеру и по изменению <y.disk>/.sync/cli.log, однако вместо вотчера за одним файлом потребуется вотчить весь синхронизируемый каталог, но это другая, отдельная задача).
4. Отказ от уродских неудобных/нестандартных конфигфайлов демона (как вспоминаю конфиги яндексного демна так вновь возникает желание найти разрабов и оторвать им руки :knuppel2:).
5. Возможность создания OpenSorce заменителя пропиетарного CLI демона от яндекса (это - самый сомнительный бенефит, ИМХО, но все же...).

Задачи, которые надо решить:
1. Авторизация приложения по технологии OAuth через сервисы Yandex - DONE.
2. Решить как будет работать решение:
  а. как независимый процесс , причем возможны варианты:
    I. запускать отдельное приложение на уровне ОС, коммуникация через socket (+ можно использовать как независимый CLI демон)
    II. формировать процесс кодом внутри индикатора, коммуникация ерез pipe (+ можно все запускать в одной программе)
  б. как импортируемый/встраиваемый класс, в котром создаются несколько независимых потоков (нужно
    понять как потоки будут сочетаться с Gtk.main() циклом.... подозреваю: будут трудно воспроизводимые
    глюки.
   Предварительно решено делать отдельного клиента с возможностью взять из него класс диска и использовать его независимо в для встраивания в индикатор.
3. Решить вопросы двусторонней синхронизации:
  а. синхронизация по изменениям в синхронизируемой папке (инициилизируется по изменениям в каталоге отлавливаемым через intify вотчер) - IN PROGRES
  б. синхронизацию по изменениям в облаке (инициализируется по получению оповещения о изменении на диске) - требует реализации xmpp клиента с нестандартной авторизацией - пока не понимаю с какой стороны подступиться  :(
  в. как будут работать обе синхронизации при одновременном возникновении изменений в облаке и в синхронизируемой папке. - требует изучения в процессе отладки.
  г. реализовать процедуру полной сверки облака и каталога (есть нужный запрос в API) и решить - как часто и когда эту "сверку" запускать.
  д. продумать модель многопоточной заливки и получения файлов в/из облака - IN PROGRESS
« Последнее редактирование: 13 Октября 2016, 14:28:17 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #1 : 10 Октября 2016, 23:37:58 »
Собственно частично тема уже начала обсуждаться в теме о индикаторе.

Некоторые важные вопросы копипасчу сюда:

(Нажмите, чтобы показать/скрыть)

Пользователь добавил сообщение 11 Октября 2016, 00:01:48:
Вот какие мысли по поводу 3.в:
По идее, человек либо в облаке сидит через браузер/мобильник или какое-то приложение (фотки допустим постит), либо ковыряется в своем локальном каталоге, на компе. Одновременно изменения возникать могут тогда, когда долго/много синхронизируется с облака или из локального каталога (т.е. пользователь уже переключился на другой режим использования а синхронизация еще не прошла до конца). Тут хотелось бы не городить асинхронную двунаправленную синхронизацию - опасаюсь что могут возникнуть неприятные накладки. Лучше бы делать все последовательно (запустилась синхронизация в облако - пока не закончится - из облака обновления не принимаем, и наоборот).
С другой стороны, казалось бы, если у файлов есть версии (нужно правда решить как это отслеживать) то конфликтов у одновременной двунаправленной синхронизации будет не больше чем у двух этих процессов запущенных последовательно, но сам процесс закончится быстрее.
« Последнее редактирование: 11 Октября 2016, 00:01:48 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Punko

  • Гость
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #2 : 11 Октября 2016, 01:09:35 »
Sly_tom_cat, смотри, я сейчас мучаю получение токена через проверочный код.
Так как апликуха у меня консольная, то приходится велосипедить.
Но, вроде, работает - код получаю, а вот отправить запрос с ним - не могу О_о
Сейчас уже хочу спать, днём зафигачу репку.
Так как на пайтоне я пишу впервые (да и в принципе впервые :) ), то подозреваю, что там жуткий говнокод.

По поводу именно твоей темы:

2. Решить как будет работать решение:
раз это будет cli, то лучше запихнуть отдельным приложением:
    I. запускать отдельное приложение на уровне ОС (+ можно использовать как независимый CLI демон)

ибо не всем нужен индикатор и прибивать клиент к нему не хотелось бы.

Вопрос синхронизации - я не особо в курсе, но было бы круто иметь приоритет, что куда сливать (типа как git merge при конфликте).

Полную сверку можно задавать в параметрах, например -
1. При запуске клиента
2. автоматически каждые 12 часов (типа крона)
3. только вручную.

Но я не знаю возможностей АРІ диска. Пока реально хочу разобраться с фотками, ибо мне лично клиента не хватает. Завтра тоже запилю тему тут.

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #3 : 11 Октября 2016, 01:41:32 »
Punko, я там в репе уже выложил свои поделки по поводу OAuth, но я получение токена по коду еще не делал запрос... но там вроде бы все просто...

По поводу 3.б - там шикарное оповещение - список операций с командами: создан новый файл/каталог, удален старый, изменен файл. Т.е. просто нужно обработать список и все. Только вот протокол там довольно навороченный - с ним придется повозиться...

Примерно такой же поток команд можно формровать inotify вотчером (3.а). А далее в случае 3.а льем изменения в облако, а в случае 3.б - качаем и аплаим изменения в локальный каталог.
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #4 : 11 Октября 2016, 11:23:21 »
Добил таки получение токена через промежуточный код: https://github.com/slytomcat/yandex-disk-client/blob/master/Oauth.py

Там у меня диалог кривоватый (на коленке собирал) запрашивает код, и само собой мои ID-шники/пароли от приложения вшиты.

Про ID-шники/пароли - плохо понимаю - вроде бы их не стоит светить... но как их скроешь из приложения? :idiot2:

Из приложения ID-шники/пароли скрыть нереально, а вот GitHub я их убрал через .gitignore (файл с ID/паролем OAuth.info лежит только у меня локально на диске, а в тестовых примерах где они используются они вычитываются из этого файла).



« Последнее редактирование: 13 Октября 2016, 12:42:14 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Punko

  • Гость
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #5 : 11 Октября 2016, 11:26:25 »
Про ID-шники/пароли - плохо понимаю - вроде бы их не стоит светить... но как их скроешь из приложения? :idiot2:
Тоже не могу понять нифига. Наверно, писать на компилируемых языках. Надо в ТП написать, они шустро отвечают.

Я твой код посмотрел - кучу непонятного для меня в силу моего незнания основ :)

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #6 : 11 Октября 2016, 11:55:37 »
Ну если диалог выкинуть то все просто.

С диалогом - как-то так:

Кидаю пользователя на страницу авторизации через браузер (используя стандартную либу webbrowser)
Код: (python) [Выделить]
url = ('https://oauth.yandex.ru/authorize?' ...
webbrowser.open_new(url)

Показываю диалог
Код: (python) [Выделить]
dlg=Gtk.Dialog(...
...
dlg.run()

По закрытию диалога беру из поля ввода диалога код и закрываю диалог
Код: (python) [Выделить]
CODE = entry.get_text()
dlg.destroy()

По идее тут диалог можно выкинуть (предыдущие два шага) и спросить код в консоли.


Посылаю дополнительный POST запрос для получения токена по коду
Код: (python) [Выделить]
r = requests.post('https://oauth.yandex.ru/token',
...

Проверяю статус ответа и если ок то читаю токен из ответа
Код: (python) [Выделить]
if r.status_code == 200:
  TOKEN = r.json()['access_token']
« Последнее редактирование: 11 Октября 2016, 12:00:48 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Punko

  • Гость
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #7 : 11 Октября 2016, 11:59:50 »
Sly_tom_cat, у меня также, но без диалога, пока читаю ввод в консоли.
Сначала функционал - потом обёртка. Но могу уделять не больше пары часов в день, поэтому будет долго всё это дело.

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #8 : 11 Октября 2016, 14:20:49 »
Прорефакторил код поделки по получению токена: собрал все в одну функцию getToken(GUI=False) - работает и в GUI (GTK) и в терминале (в зависимости от параметра вызова).

Помудрил еще немного что бы исключить мусорные сообщения от запускающегося браузера (они в CLI варианте - сильно мешались)
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Punko

  • Гость
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #9 : 11 Октября 2016, 14:24:44 »
Помудрил еще немного что бы исключить мусорные сообщения от запускающегося браузера (они в CLI варианте - сильно мешались)
это те, которые xdg-open выдаёт?

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #10 : 11 Октября 2016, 16:04:07 »
Да, выдает их и xdg-open и если через webbrowser.open_new(url) запускать. Но выдает их не сам xdg-open, а именно браузер (у меня chromimum писал всякую фигню про свой запуск).

Вызов xdg-open хотя бы можно обернуть дескрипторами потоков, что бы весь его вывод шел в /dev/null.
В webbrowser таких "бантиков" нет. :(


Попутно нашел как у них по токену получить логин пользователя, а то ведь когда кидаешь на авторизацию - пользователь может под любым логином авторизацию выдать - и приложение, получая токен, не знает логин пользователя. А логин нужен для сервиса оповешений о изменениях на диске. Там авторизация по логин+токен.
« Последнее редактирование: 11 Октября 2016, 16:07:43 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #11 : 11 Октября 2016, 19:17:19 »
ибо не всем нужен индикатор и прибивать клиент к нему не хотелось бы.
По этому поводу думается так:

Можно создать в рамках клиента законченный класс для коннекшена с диском, и в рамках клиента обернуть его в виде демона/утилиты, а в рамках индикатора использовать тот же класс для замены класса YDDaemon - это класс-обертка утилиты yandex-disk
Я довольно долго вырабатывал объектную модель индикатора для того, что бы локализовать все работы связанные с демоном синхронизации в этом одном объекте.

У YDDaemon простейший набор методов: инициализировать (возможно и сразу запустить), запустить, остановить, получить статусное сообщение (в пользовательской локали) и callBack метод, который дергается каждый раз, когда что-то меняется в состоянии демона (начинается или заканчивается синхронизация, изменяется прогресс синхронизации и т.п.). Есть еще метод который можно дернуть при выходе (он стопорит демона если в настройках стоит останавливать демона при выходе из индикатора).

По идее такой класс (с таким набором интерфейсных методов) легко менять на новый, а также его элементарно завернуть в простейший код, который будет делать из него CLI демона/утилиту.
« Последнее редактирование: 11 Октября 2016, 19:20:19 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #12 : 12 Октября 2016, 21:03:45 »
Что сегодня напилил:

В скилетном классе Disk:
- сделал файловый вотчер - это iNotify наблюдатель за файловой системой крутящийся в отдельном потоке и скидывающем все события в очередь (которой он сам и является) - т.е. просто черная коробка из которой можно брать последние события.
Коробку эту можно создать, запустить и остановить. Крутится коробка, как уже было сказано в своем потоке.
- из коробки события берет обработчик (тоже отдельный поток) и немного их обработав (там есть некоторые хитрости с событиями по перемещению файлов/каталогов) формирует задания, которые исполняются внутри хитрой такой машинки: ThreadPoolExecutor.
concurrent.futures.ThreadPoolExecutor - это такая молотилка задач, которой говоришь сколько ей можно максимально делать потоков, и кидаешь во входную очередь задачи, а она создает нужное количество потоков (но не больше лимита) и в порядке очереди в этих потоках исполняет задачи.

Зачем весь этот сырбор?

С одной стороны - какой бы там тормозной не был яндекс (а он любит тормозить), но если мы с/на него будем лить файлы в несколько потоков, то это всяко будет быстрее чем последовательно.

Но с другой стороны - канал он не резиновый, и если число потоков явно не ограничить, то мы можем наплодить очень много потоков для заливки в/из облака (например, кинули в локальный каталог пару тысяч мелких файликов), но они будут по большей части висеть именно из-за загрузки канала (и тупо держать кучу ресурсов в памяти).

Сколько потоков будет в самый раз - надо будет по подбирать, ну а как вариант (не самый разумный) - вынести это в настройки что бы этим могли поиграться продвинутые пользователи....
Лучше конечно наворотить какой-то встроенный контроль и менять число потоков от состояния канала/яндекса - это это - мысли на будущее.
Cам ThreadPoolExecutor выбирает число потоков (если ему не указать сколько конкретно нужно) на основе числа ядер процессора (cpu_count * 5) - в принципе - тоже вариант...

Собственно на будущее нужно и ThreadPoolExecutor сделать свой - немножко более управляемый. Дело в том, что если задача на upload/download файла висит еще в очереди, не начала исполняться, а в этот момент упал еще один евент по этому объекту, то логично либо старую таску отменить либо можно новую не формировать.... Но у стандартного ThreadPoolExecutor наружу торчит не так и много, по крайней мере я не нашел там решения как поискать что-либо в очереди задач. Там даже не собственно в поиске основная проблема, а в том, что у поставленной задачи нет какого-либо ID/Name, чтобы их можно было как-то привязать к внешнему справочнику, по которому можно было бы построить поиск. Но это все идеи на будущее - пока (без удаления из очереди дублирующихся задач)

В принципе, то, что мне нужно от ThreadPoolExecutor - это не такой и большой объем функционала, можно и свою молотилку сварганить.

Еще один вопрос - это как-то регулировать занятость канала (это довольно полезная фича), но пока у меня даже мыслей нет как этот вопрос решать....
« Последнее редактирование: 13 Октября 2016, 10:58:30 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Punko

  • Гость
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #13 : 12 Октября 2016, 21:43:49 »
Sly_tom_cat, нифига себе у тебя прогресс, круто.

кстати, замени "unofisial" на "unofficial"

Я таки получил свой токен - практически так же, как у тебя, но у тебя логичнее сама структура выглядит.
Вопрос - ты отказался от webbrowser потому что он всё равно пинает xdg?


И отличная идея с хостнеймом в качестве device_id!
« Последнее редактирование: 12 Октября 2016, 21:50:00 от Punko »

Оффлайн Sly_tom_cat

  • Автор темы
  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: Клиент синхронизации с Yandex.disk (Python3, OpenSource)
« Ответ #14 : 13 Октября 2016, 10:22:41 »
Вопрос - ты отказался от webbrowser потому что он всё равно пинает xdg?
Я честно даже не стал разбираться - что он там пинает и как.
Дело в том, что там просто нет возможности прикрутить вывод запускаемого процесса в другой поток. Поэтому я просто перешел на уровень ниже, на вызов подпроцесса. На этом уровне уже есть возможность управлять потоками вывода порождаемого процесса (т.е. переназначить их на /dev/null). А это - именно от вариант, который позволяет гарантированно подавить вывод любого и всякого мусора в консоль родительского приложения.


unofisial - исправил, спасибо за замечание.

Хостнейм я заюзал как device_name (а не device_id, который я не передаю) - это единственное, что в голову приходит... однако это все за зря - яндекс не показывает (или я не нашел где) на какое устройство выдан токен. Более того, я с одним токеном хожу на яндекс с двух разных компов. Т.е. я подозреваю, что там не только не показывается, но еще и не учитывается.... Возможно (я не пробовал), если использовать именно device_id, то там будут разные токены на разные устройства (по крайней мере они так декларируют).

Но, для device_id логичнее использовать либо UUID (первый попавшийся и его в принципе можно даже не запоминать), либо что-то типа MAC сетевого интерфейса или ID процессора если хочется привязать токен к реальному железу.
« Последнее редактирование: 13 Октября 2016, 10:31:36 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

 

Страница сгенерирована за 0.062 секунд. Запросов: 23.