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())