make peer id according to BEP20

This commit is contained in:
Victor Shyba 2022-03-10 21:10:44 -03:00
parent 3c46cc4fdd
commit 7e6ea97499

View file

@ -1,12 +1,15 @@
import random import random
import string
import struct import struct
import asyncio import asyncio
import logging import logging
import time import time
from collections import namedtuple from collections import namedtuple
from typing import Optional
from lbry.utils import resolve_host, async_timed_cache, cache_concurrent from lbry.utils import resolve_host, async_timed_cache, cache_concurrent
from lbry.wallet.stream import StreamController from lbry.wallet.stream import StreamController
from lbry import version
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
CONNECTION_EXPIRES_AFTER_SECONDS = 50 CONNECTION_EXPIRES_AFTER_SECONDS = 50
@ -59,8 +62,16 @@ def encode(obj):
return STRUCTS[type(obj)].pack(*obj) return STRUCTS[type(obj)].pack(*obj)
def make_peer_id(random_part: Optional[str] = None) -> bytes:
# see https://wiki.theory.org/BitTorrentSpecification#peer_id and https://www.bittorrent.org/beps/bep_0020.html
# not to confuse with node id; peer id identifies uniquely the software, version and instance
PREFIX = 'LB' # todo: PR BEP20 to add ourselves
random_part = random_part or ''.join(random.choice(string.ascii_letters) for _ in range(20))
return f"{PREFIX}-{'-'.join(map(str, version))}-{random_part}"[:20].encode()
class UDPTrackerClientProtocol(asyncio.DatagramProtocol): class UDPTrackerClientProtocol(asyncio.DatagramProtocol):
def __init__(self, timeout=10.0): def __init__(self, timeout: float = 10.0):
self.transport = None self.transport = None
self.data_queue = {} self.data_queue = {}
self.timeout = timeout self.timeout = timeout
@ -126,7 +137,7 @@ class TrackerClient:
def __init__(self, node_id, announce_port, servers, timeout=10.0): def __init__(self, node_id, announce_port, servers, timeout=10.0):
self.client = UDPTrackerClientProtocol(timeout=timeout) self.client = UDPTrackerClientProtocol(timeout=timeout)
self.transport = None self.transport = None
self.node_id = node_id or random.getrandbits(160).to_bytes(20, "big", signed=False) self.peer_id = make_peer_id(node_id.hex() if node_id else None)
self.announce_port = announce_port self.announce_port = announce_port
self.servers = servers self.servers = servers
self.results = {} # we can't probe the server before the interval, so we keep the result here until it expires self.results = {} # we can't probe the server before the interval, so we keep the result here until it expires
@ -191,7 +202,7 @@ class TrackerClient:
return result return result
try: try:
result = await self.client.announce( result = await self.client.announce(
info_hash, self.node_id, self.announce_port, tracker_host, tracker_port, stopped) info_hash, self.peer_id, self.announce_port, tracker_host, tracker_port, stopped)
self.results[tracker_host][info_hash] = (time.time() + result.interval, result) self.results[tracker_host][info_hash] = (time.time() + result.interval, result)
except asyncio.TimeoutError: # todo: this is UDP, timeout is common, we need a better metric for failures except asyncio.TimeoutError: # todo: this is UDP, timeout is common, we need a better metric for failures
self.results[tracker_host][info_hash] = (time.time() + 60.0, result) self.results[tracker_host][info_hash] = (time.time() + 60.0, result)