65 lines
1.6 KiB
Python
65 lines
1.6 KiB
Python
"""影子柜台 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())
|