# Minimal BitTorrent HTTP tracker for a closed scratch test (no internet). Compact peer lists. import http.server, urllib.parse, socket, struct, time peers = {} # info_hash -> {(ip,port): last_seen} def benc(o): if isinstance(o, int): return b"i%de" % o if isinstance(o, bytes): return b"%d:%s" % (len(o), o) if isinstance(o, str): return benc(o.encode()) if isinstance(o, dict): return b"d" + b"".join(benc(k) + benc(v) for k, v in sorted(o.items())) + b"e" class H(http.server.BaseHTTPRequestHandler): def do_GET(self): q = urllib.parse.parse_qs(urllib.parse.urlsplit(self.path).query.encode('latin-1').decode('latin-1'), encoding='latin-1') ih = q.get('info_hash', [''])[0]; port = int(q.get('port', ['0'])[0]); ip = self.client_address[0] d = peers.setdefault(ih, {}); now = time.time() if q.get('event', [''])[0] == 'stopped': d.pop((ip, port), None) else: d[(ip, port)] = now lst = b"".join(socket.inet_aton(i) + struct.pack(">H", p) for (i, p), t in d.items() if now - t < 600 and (i, p) != (ip, port)) body = benc({"interval": 30, "peers": lst}) print(time.strftime('%H:%M:%S'), 'announce', ip, port, q.get('event', [''])[0], 'peers', len(lst) // 6, flush=True) self.send_response(200); self.send_header('Content-Length', str(len(body))); self.end_headers(); self.wfile.write(body) def log_message(self, *a): pass http.server.ThreadingHTTPServer(('0.0.0.0', 6969), H).serve_forever()