import asyncio import shutil from pathlib import Path import yaml from app.models.proxy import ProxyDocument def script_path_for(work_dir: Path, proxy: ProxyDocument) -> Path: return work_dir / "addons" / f"{proxy.proxy_port}.py" def conf_dir_for(work_dir: Path, proxy: ProxyDocument) -> Path: return work_dir / "conf" / str(proxy.proxy_port) def config_path_for(work_dir: Path, proxy: ProxyDocument) -> Path: return conf_dir_for(work_dir, proxy) / "config.yaml" def log_path_for(work_dir: Path, proxy: ProxyDocument) -> Path: return work_dir / "logs" / f"{proxy.proxy_port}.log" async def write_script(work_dir: Path, proxy: ProxyDocument) -> Path: path = script_path_for(work_dir, proxy) await asyncio.to_thread(path.parent.mkdir, parents=True, exist_ok=True) await asyncio.to_thread(path.write_text, proxy.code, encoding="utf-8") return path async def write_config(work_dir: Path, proxy: ProxyDocument) -> Path: path = config_path_for(work_dir, proxy) await asyncio.to_thread(path.parent.mkdir, parents=True, exist_ok=True) options = {"block_global": False, **proxy.mitm_options} config_text = yaml.safe_dump(options, sort_keys=True) await asyncio.to_thread(path.write_text, config_text, encoding="utf-8") return path async def ensure_log_path(work_dir: Path, proxy: ProxyDocument) -> Path: path = log_path_for(work_dir, proxy) await asyncio.to_thread(path.parent.mkdir, parents=True, exist_ok=True) return path async def read_log_tail(path: Path, limit: int = 4000) -> str: if not await asyncio.to_thread(path.exists): return "" content = await asyncio.to_thread( path.read_text, encoding="utf-8", errors="replace", ) return content[-limit:].strip() def remove_file(path: Path) -> None: try: path.unlink(missing_ok=True) except OSError: return def remove_dir(path: Path) -> None: try: shutil.rmtree(path) except FileNotFoundError: return except OSError: return def read_cmdline(pid: int) -> list[str]: path = Path(f"/proc/{pid}/cmdline") try: raw = path.read_bytes() except OSError: return [] decoded = raw.decode("utf-8", errors="replace") return [part for part in decoded.split("\x00") if part]