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>
76 lines
2.2 KiB
Python
76 lines
2.2 KiB
Python
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())
|