Initial commit: multi-peer torrent download engine
Reactor/loop-pool engine with TCP/µTP/MSE transports, per-connection pipelining, priority-driven piece selection with endgame, and the Python FFI test harness. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
d8208685a2
55 changed files with 9989 additions and 0 deletions
63
interop/common.py
Normal file
63
interop/common.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import time
|
||||
import sys
|
||||
|
||||
ROOT = os.environ.get("TORRENT_PEER_ROOT", "/work")
|
||||
sys.path.insert(0, os.path.join(ROOT, "harness"))
|
||||
|
||||
from torrent_meta import Metadata, load_metadata # noqa: E402
|
||||
|
||||
|
||||
def parse_size(text: str) -> int:
|
||||
s = text.strip().upper()
|
||||
mult = 1
|
||||
if s[-1:] in ("K", "M", "G"):
|
||||
mult = {"K": 1024, "M": 1024**2, "G": 1024**3}[s[-1]]
|
||||
s = s[:-1]
|
||||
return int(s) * mult
|
||||
|
||||
|
||||
def file_sha1(path: str) -> str:
|
||||
h = hashlib.sha1()
|
||||
with open(path, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(1024 * 1024), b""):
|
||||
h.update(chunk)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def write_manifest(path: str, **items) -> None:
|
||||
tmp = path + ".tmp"
|
||||
with open(tmp, "w", encoding="utf-8") as f:
|
||||
json.dump(items, f, indent=2, sort_keys=True)
|
||||
f.write("\n")
|
||||
os.replace(tmp, path)
|
||||
|
||||
|
||||
def wait_for_tcp(host: str, port: int, timeout: float = 30.0) -> None:
|
||||
deadline = time.time() + timeout
|
||||
last_error = None
|
||||
while time.time() < deadline:
|
||||
try:
|
||||
with socket.create_connection((host, port), timeout=1.0):
|
||||
return
|
||||
except OSError as exc:
|
||||
last_error = exc
|
||||
time.sleep(0.25)
|
||||
raise TimeoutError(f"timed out waiting for {host}:{port}: {last_error}")
|
||||
|
||||
|
||||
def resolve_ipv4(host: str) -> str:
|
||||
infos = socket.getaddrinfo(host, None, socket.AF_INET, socket.SOCK_STREAM)
|
||||
if not infos:
|
||||
raise OSError(f"no IPv4 address for {host}")
|
||||
return infos[0][4][0]
|
||||
|
||||
|
||||
def touch_ready(path: str = "/tmp/seed-ready") -> None:
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
f.write("ready\n")
|
||||
Loading…
Add table
Add a link
Reference in a new issue