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>
80 lines
2.3 KiB
Python
80 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import signal
|
|
import subprocess
|
|
import time
|
|
|
|
from common import touch_ready, wait_for_tcp
|
|
|
|
|
|
def write_rc(path: str, torrent: str, data: str, port: int, session: str) -> None:
|
|
os.makedirs(session, exist_ok=True)
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
f.write(f"""
|
|
directory.default.set = {data}
|
|
session.path.set = {session}
|
|
network.port_range.set = {port}-{port}
|
|
network.port_random.set = no
|
|
dht.mode.set = disable
|
|
protocol.pex.set = no
|
|
trackers.use_udp.set = no
|
|
network.http.max_open.set = 0
|
|
pieces.hash.on_completion.set = no
|
|
""")
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser(description="Seed a fixture with rTorrent.")
|
|
ap.add_argument("--torrent", required=True)
|
|
ap.add_argument("--data", required=True)
|
|
ap.add_argument("--port", type=int, required=True)
|
|
args = ap.parse_args()
|
|
|
|
rc = "/tmp/rtorrent.rc"
|
|
session = "/tmp/rtorrent-session"
|
|
write_rc(rc, args.torrent, args.data, args.port, session)
|
|
env = os.environ.copy()
|
|
env.setdefault("TERM", "xterm")
|
|
command = f"rtorrent -n -o import={rc}"
|
|
proc = subprocess.Popen(
|
|
["script", "-q", "-e", "-c", command, "/dev/null"],
|
|
env=env,
|
|
stdin=subprocess.PIPE,
|
|
)
|
|
stop = False
|
|
|
|
def _stop(signum, frame):
|
|
nonlocal stop
|
|
stop = True
|
|
proc.terminate()
|
|
subprocess.run(["pkill", "-TERM", "rtorrent"], check=False)
|
|
|
|
signal.signal(signal.SIGTERM, _stop)
|
|
signal.signal(signal.SIGINT, _stop)
|
|
|
|
try:
|
|
wait_for_tcp("127.0.0.1", args.port, timeout=45)
|
|
if proc.stdin:
|
|
proc.stdin.write(b"\x7f" + args.torrent.encode("utf-8") + b"\n")
|
|
proc.stdin.flush()
|
|
time.sleep(2)
|
|
if proc.poll() is not None:
|
|
return proc.returncode or 1
|
|
touch_ready()
|
|
print(f"rTorrent seeding on {args.port}", flush=True)
|
|
while not stop:
|
|
if subprocess.run(["pgrep", "rtorrent"], stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL).returncode != 0:
|
|
return 1
|
|
time.sleep(1)
|
|
return 0
|
|
finally:
|
|
subprocess.run(["pkill", "-TERM", "rtorrent"], check=False)
|
|
if proc.poll() is None:
|
|
proc.terminate()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|