"""影子柜台 CLI 入口。 用法: python -m sanguo_trader.shadow # 读 env(见 runner.py docstring) python -m sanguo_trader.shadow --auto # 主管模式:轮询 paper 库自动拉起影子账户 """ from __future__ import annotations import logging import os import sys from pathlib import Path LOCK_FILE = Path( os.environ.get("SANGUO_SHADOW_LOCK") or Path.home() / ".sanguo_shadow_desk.lock" ) def _acquire_lock() -> "object | None": """单实例锁(Windows/msvcrt 与 POSIX/fcntl 双兼容)。""" LOCK_FILE.parent.mkdir(parents=True, exist_ok=True) try: import fcntl # POSIX fh = open(LOCK_FILE, "w") fcntl.flock(fh, fcntl.LOCK_EX | fcntl.LOCK_NB) return fh except ImportError: pass except OSError: return None # 已有实例在跑 try: import msvcrt # Windows fh = open(LOCK_FILE, "w") msvcrt.locking(fh.fileno(), msvcrt.LK_NBLCK, 1) return fh except (ImportError, OSError): return None def main() -> int: logging.basicConfig( level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s", ) if "--auto" in sys.argv: from .supervisor import run_auto_supervisor run_auto_supervisor() return 0 lock = _acquire_lock() if lock is None: print("影子柜台已在运行(锁占用),本次启动退出。", flush=True) return 0 from .runner import run_shadow run_shadow() return 0 if __name__ == "__main__": sys.exit(main())