diff --git a/deploy.sh b/deploy.sh index 1a41d28..b136014 100644 --- a/deploy.sh +++ b/deploy.sh @@ -27,10 +27,13 @@ need_install python3-venv python3-venv need_install git git # vnpy_ctp 在 Linux 上需本地编译(Meson + pkg-config 查找 python3-dev) -echo "==> 安装 vnpy_ctp 编译依赖..." +echo "==> 安装 vnpy_ctp 编译依赖与 CTP 中文 locale..." apt-get install -y build-essential python3-dev pkg-config locales -locale-gen en_US.UTF-8 C.UTF-8 2>/dev/null || true -update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 2>/dev/null || true +# CTP C++ API 登录回调需要 zh_CN.GB18030(vnpy/vnpy_ctp#24) +sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen 2>/dev/null || true +sed -i '/^# zh_CN.UTF-8/s/^# //' /etc/locale.gen 2>/dev/null || true +locale-gen zh_CN.GB18030 zh_CN.UTF-8 en_US.UTF-8 2>/dev/null || locale-gen +update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 2>/dev/null || true if ! command -v pm2 &>/dev/null; then echo "==> 安装 PM2..." diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index d717abe..2c37d6f 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -346,7 +346,7 @@ pm2 restart qihuo |-----------|------| | `pip install vnpy_ctp` 编译失败 / `Python dependency not found` | 安装 `build-essential python3-dev pkg-config` 后重试 | | CTP 连接超时 | 检查前置 IP、端口、SimNow 是否维护、是否在允许连接时段 | -| 连接后立即崩溃 `locale::facet::_S_create_c_locale` | 安装 locale:`apt install -y locales && locale-gen en_US.UTF-8`,`git pull` 后 `pm2 restart qihuo --update-env` | +| 连接后立即崩溃 `locale::facet::_S_create_c_locale` | CTP 需 **zh_CN.GB18030**:`sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen && locale-gen zh_CN.GB18030`,再 `pm2 restart qihuo --update-env` | | 服务器 `180.168.146.187` 超时 | 换 SimNow 备用前置 `182.254.243.31:30001/30011`(见 [SIMNOW.md](./SIMNOW.md)) | | 已连接但下单拒单 | 检查合约代码、价格精度、是否有足够保证金 | diff --git a/docs/SIMNOW.md b/docs/SIMNOW.md index a097667..8b02d36 100644 --- a/docs/SIMNOW.md +++ b/docs/SIMNOW.md @@ -183,7 +183,7 @@ python scripts/test_simnow.py | 报错 **4097** / 握手失败 | `pip install -U vnpy vnpy_ctp`,`.env` 设 `SIMNOW_ENV=实盘` | | **不合法的登录** | 投资者代码/密码错,或未在快期改过一次密码 | | 快期能登、脚本不能 | 多为网络或前置地址,换 SimNow 官网其他组前置试 | -| 连上后进程崩溃 `locale::facet::_S_create_c_locale` | `apt install -y locales && locale-gen en_US.UTF-8`,`git pull` 后 `pm2 restart qihuo --update-env` | +| 连上后进程崩溃 `locale::facet::_S_create_c_locale` | **必须**安装 `zh_CN.GB18030`:`sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen && locale-gen zh_CN.GB18030` | ### 提示「未安装 vnpy / vnpy_ctp」 diff --git a/ecosystem.config.cjs b/ecosystem.config.cjs index 8dfa3c8..8774b2e 100644 --- a/ecosystem.config.cjs +++ b/ecosystem.config.cjs @@ -11,9 +11,9 @@ module.exports = { max_memory_restart: "300M", env: { NODE_ENV: "production", - LANG: "en_US.UTF-8", - LC_ALL: "en_US.UTF-8", - LC_CTYPE: "en_US.UTF-8", + LANG: "zh_CN.UTF-8", + LC_ALL: "zh_CN.UTF-8", + LC_CTYPE: "zh_CN.UTF-8", }, error_file: "/opt/qihuo/logs/pm2-error.log", out_file: "/opt/qihuo/logs/pm2-out.log", diff --git a/locale_fix.py b/locale_fix.py index 20e8290..e7f58ea 100644 --- a/locale_fix.py +++ b/locale_fix.py @@ -11,29 +11,48 @@ logger = logging.getLogger(__name__) _LOCALE_DONE = False _LOCALE_NAME = "" +# CTP C++ API 登录回调依赖中文 locale(见 vnpy/vnpy_ctp#24) +_CTP_REQUIRED_LOCALES = ("zh_CN.GB18030", "zh_CN.gb18030") + + +def _available_locales() -> set[str]: + try: + out = subprocess.check_output(["locale", "-a"], text=True, stderr=subprocess.DEVNULL) + return {line.strip() for line in out.splitlines() if line.strip()} + except (OSError, subprocess.SubprocessError): + return set() + + +def missing_ctp_locales() -> list[str]: + """CTP 所需的 zh_CN.GB18030 是否已安装。""" + avail = {x.lower() for x in _available_locales()} + if any(x.lower() in avail for x in _CTP_REQUIRED_LOCALES): + return [] + return ["zh_CN.GB18030"] + def _list_locale_candidates() -> list[str]: + avail = _available_locales() names: list[str] = [] + # CTP 回调优先尝试中文 locale for item in ( - "C.UTF-8", + "zh_CN.GB18030", + "zh_CN.gb18030", + "zh_CN.UTF-8", + "zh_CN.utf8", "en_US.UTF-8", "en_US.utf8", + "C.UTF-8", + "C.utf8", "POSIX", "C", ): - if item not in names: + if item in avail and item not in names: names.append(item) - try: - out = subprocess.check_output(["locale", "-a"], text=True, stderr=subprocess.DEVNULL) - for line in out.splitlines(): - loc = line.strip() - if not loc: - continue - low = loc.lower() - if "utf" in low and loc not in names: - names.insert(0, loc) - except (OSError, subprocess.SubprocessError): - pass + for loc in sorted(avail): + low = loc.lower() + if "utf" in low and loc not in names: + names.append(loc) return names @@ -43,6 +62,14 @@ def ensure_process_locale() -> str: if _LOCALE_DONE: return _LOCALE_NAME + missing = missing_ctp_locales() + if missing: + raise RuntimeError( + "CTP 需要中文 locale zh_CN.GB18030,当前系统未安装。" + "请执行: sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen && " + "locale-gen zh_CN.GB18030" + ) + last_err: locale.Error | None = None for name in _list_locale_candidates(): try: @@ -60,6 +87,5 @@ def ensure_process_locale() -> str: raise RuntimeError( "未找到可用 locale,vnpy_ctp 会在 CTP 登录后崩溃。" - "请执行: apt install -y locales && locale-gen en_US.UTF-8 && " - "update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8" + "请执行: apt install -y locales && locale-gen zh_CN.GB18030 en_US.UTF-8" ) from last_err diff --git a/scripts/test_simnow.py b/scripts/test_simnow.py index 687c697..e9112d5 100644 --- a/scripts/test_simnow.py +++ b/scripts/test_simnow.py @@ -9,7 +9,7 @@ import sys BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, BASE) -from locale_fix import ensure_process_locale +from locale_fix import ensure_process_locale, missing_ctp_locales ensure_process_locale() @@ -40,6 +40,9 @@ def main() -> int: print("=== SimNow 配置 ===") print(f"locale = {ensure_process_locale()}") + missing = missing_ctp_locales() + if missing: + print(f"警告: 缺少 CTP 所需 locale: {', '.join(missing)}") print(f"SIMNOW_USER = {user or '(未设置)'}") print(f"SIMNOW_PASSWORD = {'*' * 8 if os.getenv('SIMNOW_PASSWORD') else '(未设置)'}") print(f"SIMNOW_TD = {td}")