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
76
interop/make_fixture.py
Normal file
76
interop/make_fixture.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
import libtorrent as lt
|
||||
|
||||
from common import file_sha1, parse_size, write_manifest
|
||||
|
||||
|
||||
def deterministic_bytes(offset: int, size: int) -> bytes:
|
||||
out = bytearray()
|
||||
counter = offset // 32
|
||||
while len(out) < size:
|
||||
out.extend(hashlib.sha256(f"torrent-peer-interop:{counter}".encode()).digest())
|
||||
counter += 1
|
||||
return bytes(out[:size])
|
||||
|
||||
|
||||
def write_data(path: str, size: int) -> None:
|
||||
with open(path, "wb") as f:
|
||||
off = 0
|
||||
while off < size:
|
||||
n = min(1024 * 1024, size - off)
|
||||
f.write(deterministic_bytes(off, n))
|
||||
off += n
|
||||
|
||||
|
||||
def make_torrent(root: str, size: int, piece_size: int) -> str:
|
||||
os.makedirs(root, exist_ok=True)
|
||||
data_path = os.path.join(root, "data.bin")
|
||||
torrent_path = os.path.join(root, "test.torrent")
|
||||
write_data(data_path, size)
|
||||
|
||||
fs = lt.file_storage()
|
||||
lt.add_files(fs, data_path)
|
||||
t = lt.create_torrent(fs, piece_size=piece_size)
|
||||
t.set_priv(True)
|
||||
t.add_tracker("http://fixture:9/announce")
|
||||
lt.set_piece_hashes(t, root)
|
||||
with open(torrent_path, "wb") as f:
|
||||
f.write(lt.bencode(t.generate()))
|
||||
return torrent_path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description="Create the offline interop fixture.")
|
||||
ap.add_argument("--out", required=True)
|
||||
ap.add_argument("--size", default="32M")
|
||||
ap.add_argument("--piece-size", default="256K")
|
||||
args = ap.parse_args()
|
||||
|
||||
size = parse_size(args.size)
|
||||
piece_size = parse_size(args.piece_size)
|
||||
torrent_path = make_torrent(args.out, size, piece_size)
|
||||
data_path = os.path.join(args.out, "data.bin")
|
||||
|
||||
ti = lt.torrent_info(torrent_path)
|
||||
write_manifest(
|
||||
os.path.join(args.out, "manifest.json"),
|
||||
name=ti.name(),
|
||||
size=size,
|
||||
piece_size=piece_size,
|
||||
num_pieces=ti.num_pieces(),
|
||||
sha1=file_sha1(data_path),
|
||||
announce="http://fixture:9/announce",
|
||||
torrent=os.path.basename(torrent_path),
|
||||
data=os.path.basename(data_path),
|
||||
)
|
||||
print(f"fixture ready: {size} bytes, {ti.num_pieces()} pieces", flush=True)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue