from __future__ import annotations import argparse import os import signal import time import libtorrent as lt from common import touch_ready def settings_for(mode: str, port: int) -> dict: tcp = mode in ("plain", "mse") utp = mode in ("utp", "utp-mse") encrypted = mode in ("mse", "utp-mse") settings = { "listen_interfaces": f"0.0.0.0:{port}", "enable_dht": False, "enable_lsd": False, "enable_upnp": False, "enable_natpmp": False, "enable_outgoing_tcp": tcp, "enable_incoming_tcp": tcp, "enable_outgoing_utp": utp, "enable_incoming_utp": utp, "announce_to_all_trackers": False, "announce_to_all_tiers": False, "alert_mask": 0, } if encrypted: settings.update({ "in_enc_policy": int(lt.enc_policy.forced), "out_enc_policy": int(lt.enc_policy.forced), "allowed_enc_level": int(lt.enc_level.rc4), "prefer_rc4": True, }) else: settings.update({ "in_enc_policy": int(lt.enc_policy.disabled), "out_enc_policy": int(lt.enc_policy.disabled), }) return settings def main() -> int: ap = argparse.ArgumentParser(description="Seed a fixture with libtorrent.") ap.add_argument("--torrent", required=True) ap.add_argument("--data", required=True) ap.add_argument("--port", required=True, type=int) ap.add_argument("--mode", required=True, choices=["plain", "mse", "utp", "utp-mse"]) args = ap.parse_args() stop = False def _stop(signum, frame): nonlocal stop stop = True signal.signal(signal.SIGTERM, _stop) signal.signal(signal.SIGINT, _stop) ses = lt.session(settings_for(args.mode, args.port)) h = ses.add_torrent({ "ti": lt.torrent_info(args.torrent), "save_path": args.data, "flags": lt.torrent_flags.seed_mode, }) deadline = time.time() + 60 while time.time() < deadline and not h.status().is_seeding: time.sleep(0.25) if not h.status().is_seeding: raise TimeoutError(f"libtorrent {args.mode} did not enter seed mode") touch_ready() print(f"libtorrent {args.mode} seeding on {args.port}", flush=True) while not stop: time.sleep(1) ses.remove_torrent(h) return 0 if __name__ == "__main__": raise SystemExit(main())