- PVSM.RU - https://www.pvsm.ru -
Допустим, у Вас есть некий сайт, написанный на языке Python и Вы хотите прикрутить к нему BitTorrent tracker, наподобие rutracker.org.
Задачу можно разделить на две большие функциональности:
Трекер [1] представляет собой http-приложение, согласно спецификации [2] протокола BitTorrent сообщающее клиенту по запросу обо всех участниках раздачи. Поскольку клиенты шлют запросы постоянно периодически, то Трекер должен быть производительным: время ответа должно быть минимальным.
В мире PHP Каталог и Трекер зачастую не разделяются на два выделенных приложения. Например, популярный TBDev Tracker [3] существует в виде приложения, объединяющего Каталог-форум и Трекер. (Автор видимо так устал от популярности своего приложения, что сайт давно не обновляется и скачать приложение с него нереально. Однако в Сети можно найти множество клонов.)
Некоторые реализации Трекера изначально были написаны на Python, но затем переписаны на C++ из соображений производительности. Так что в наши дни Python-трекеров не существует (по крайней мере мне найти не удалось). Поэтому единственное, что остается — установить отдельное приложение Трекера и интегрировать его с Python-Каталогом.
Если Вам никакой контроль не нужен, то есть:
то Вам достаточно установить одну из программ [4], выбрав среди них самую легкую и самую производительную.
Далее, Вы просто даете возможность своим пользователям создавать записи каталога и загружать и скачивать созданные ими самими .torrent-файлы. Предварительно сообщив им правильный announce-адрес Вашего tracker-а, который они запишут в .torrent-файл при создании раздачи.
Если же Вы хотите установить хоть какой-то контроль, а тем более, как в моем случае, захотите ограничить доступ некоторых групп пользователей к некоторым раздачам, то для этого Вам понадобится так называемый «частный трекер» [1].
В теории это делается следующим образом:
Учитывая все вышесказанное, мой выбор пал на XBT Tracker [6], как единственную реализацию частного Трекера, рассчитанную на интеграцию с любым сайтом-Каталогом.
XBT Tracker написан на C++ и устанавливается путем сборки из исходников. На Ubuntu Server 12.04 64-bit собирается с первого раза.
Взаимодействие с XBT Tracker предполагается через MySQL-базу данных Трекера, поэтому нашему Python-Каталогу понадобится уметь писать-читать БД MySQL. Для этого я использовал пакет pymysql
.
Для разбора и модификации .torrent-файлов также понадобится пакет BitTorrent-bencode
import bencode, pymysql
Добавление авторизованного пользователя, если еще такого нет. Здесь поле torrent_pass
таблицы xbt_users
используется для связки ID пользователя Вашего сайта и ID пользователя XBT Tracker. Ранее torrent_pass использовался для авторизации пользователя по ключу, прописанному в announce URL, однако теперь XBT Tracker использует другой алгоритм — см. ниже. Поле uid
— автоинкрементное.
c = db.cursor()
c.execute("SELECT uid, torrent_pass, torrent_pass_version, downloaded, uploaded FROM xbt_users WHERE torrent_pass = %s",
(request.user.id,))
rec = c.fetchone()
if not rec:
# insert a new user
c.execute("INSERT INTO xbt_users(torrent_pass) VALUES(%s)", (request.user.id))
c.execute("SELECT uid, torrent_pass, torrent_pass_version, downloaded, uploaded FROM xbt_users WHERE torrent_pass = %s",
(request.user.id,)) #rowcount =0
rec = c.fetchone()
db.commit()
uid, torrent_pass, torrent_pass_version, downloaded, uploaded = rec
Чтение и разбор .torrent-файла:
with open(fpath, 'rb') as f:
buf = f.read()
bt = bencode.bdecode(buf)
Насильно установить private-флаг и рассчитать info_hash (private-флаг входит в раздел info и влияет на его хэш):
if xbt_force_private:
bt['info']['private'] = 1
info_hash_obj = hashlib.sha1(bencode.bencode(bt['info']))
Регистрация раздачи в таблице xbt_files
если еще таковой нет.
sha = info_hash_obj.hexdigest()
c = db.cursor()
c.execute("SELECT flags FROM xbt_files WHERE info_hash=UNHEX(%s)", (sha,))
flag = c.fetchone()
if flag is None:
c.execute("INSERT INTO xbt_files(info_hash, mtime, ctime) VALUES(UNHEX(%s), UNIX_TIMESTAMP(), UNIX_TIMESTAMP())",
(sha,))
db.commit()
elif flag[0] % 2 :
error_msg(pagename, request, _("Torrent is marked for deletion!"))
return
XBT Tracker использует весьма хитрый алгоритм вычисления ключа. Берется набор значений:
xbt_users.uid
, xbt_users.torrent_pass_version
,xbt_config
, значение torrent_pass_private_key
,xbt_files.info_hash
.Всё это магическим образом перемешивается по принципу «кручу-верчу, запутать хочу»:
c.execute("select value from xbt_config where name = 'torrent_pass_private_key'")
torrent_pass_private_key = c.fetchone()[0]
s = "%s %d %d %s" % (torrent_pass_private_key, torrent_pass_version, uid, info_hash_obj.digest())
sha = hashlib.sha1(s).hexdigest()[0:24]
pwd = "%08x%s" % (uid, sha)
bt['announce'] = 'http://xbt.host:port/%s/announce' % pwd
# remove other trackers
if bt.has_key('announce-list'):
del bt['announce-list']
Отсюда становится понятно назначение xbt_users.torrent_pass_version
: изменив это значение, можно сделать все ранее скачанные .torrent-файлы инвалидными. То есть это — некий аналог сброса пароля.
И, наконец, кодируем .torrent-файл обратно в строку, которую и будем посылать клиенту:
buf = bencode.bencode(bt)
При удалении присоединенного файла мы должны удалить раздачу из списка зарегистрированных раздач (таблицы xbt_files
).
Есть способ вежливого удаления, при котором мы помечаем раздачу как удаленную, а реально она удаляется трекером, когда ее скачает полностью последний лич.
c.execute("update xbt_files set flags = 1 where info_hash = UNHEX(%s)", (info_hash, ))
Ну вот и всё. Дальнейшая докрутка сайта: отображение количества и списка раздающих, подсчет рейтинга, отображение списка файлов в раздаче я отношу к украшательствам. Они реализуются достаточно очевидно: вся необходимая информация, включая статистику, имеется в БД трекера, — и мне, вслед за Пьером Ферма, жаль тратить на них место.
Изложенное решение воплощено в виде плагина [7] к популярному вики-движку: MoinMoin [8]
Необходимо отметить, что предложенное решение имеет существенный недостаток:
Надеюсь, мой опыт кому-то пригодится.
Автор: alosev
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/31207
Ссылки в тексте:
[1] Трекер: http://ru.wikipedia.org/wiki/BitTorrent-%D1%82%D1%80%D0%B5%D0%BA%D0%B5%D1%80
[2] спецификации: http://wiki.theory.org/BitTorrentSpecification
[3] TBDev Tracker: http://bit-torrent.kiev.ua/
[4] программ: http://en.wikipedia.org/wiki/BitTorrent_tracker_software
[5] флага «private=1»: http://www.bittorrent.org/beps/bep_0027.html
[6] XBT Tracker: http://xbtt.sourceforge.net/tracker/
[7] плагина: http://moinmo.in/ActionMarket/AttachTorrent
[8] MoinMoin: http://moinmo.in
[9] виртуальный хостинг: https://www.reg.ru/?rlink=reflink-717
[10] Источник: http://habrahabr.ru/post/175449/
Нажмите здесь для печати.