Писал тут асинхронный торрент-клиент полностью на asyncio и aiohttp и внезапно столкнулся с проблемой. Кратко введу в курс дела: информация о торренте хранится в специальном .torrent файле, который внутри себя содержит utf-8 текст с незатейливо закодированным словарём. Для того, чтобы идентифицировать торрент, клиенты и трекеры берут sha1-хэш от определённой части этого словаря, я это делаю примерно так:
info_dict = {} # какой-то словарь hash = hashlib.sha1(bencoding.encode(info_dict)).digest() # bytes, длиной 20
До этого я уже написал рабочий код, который успешно получал ответ от трекера, но после обновления либы aiohttp с версии 1.0.5 до текущей 1.2.0, оказалось, что код больше не работает.
А именно:
# составляем словарь с аргументами для запроса - Dict[str, Any] params = { 'info_hash': hash, 'compact': 1, # ... и т.д. } # открываем (или берём уже имеющуюся) сессию session = aiohttp.ClientSession(loop=asyncio.get_event_loop()) # делаем запрос async with session.get(announcer, params=params) as response: return await response.read()
Которая ведёт куда-то в дебри ставящегося вместе с aiohttp пакета yarl. Ясно, что байты в качестве значений словаря метод больше не берёт. Пробуем закодировать самостоятельно:
>>>str(hash) # конечно, нет "b'Y;o]G\xd7gb[\x8e\xe7\x1a...'" >>>hashlib.sha1(bencoding.encode(info_dict)).hexdigest() # нет '593b6f5d47d767625....' >>>urllib.parse.quote(hash) # опять нет 'Y%3Bo%5DG%D7gb%5B%8E%E7%...' >>>urllib.parse.quote(str(hash)[2:-1]) # не-а >>>hash.decode(????) >>>yarl.quote(hash) # нет такого торрента!