From 37661daf404ef5444faf3e5e37f225b7444adc4f Mon Sep 17 00:00:00 2001 From: 6vision Date: Thu, 28 May 2026 14:33:45 +0800 Subject: [PATCH] refactor(wechat_kf): persist sync_msg cursor under $HOME Move the sync_msg cursor file from the project-local tmp/ dir to ~/.wechat_kf_cursors.json so it survives tmp/ cleanups and cwd changes across restarts. Aligns with the weixin channel's credentials file convention. - add wechat_kf_cursor_path config (default ~/.wechat_kf_cursors.json) - expand ~ via os.path.expanduser in the channel init - chmod the cursor file to 0o600 after each flush (no-op on Windows) --- channel/wechat_kf/wechat_kf_channel.py | 8 +++++--- channel/wechat_kf/wechat_kf_cursor_store.py | 6 ++++++ config.py | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/channel/wechat_kf/wechat_kf_channel.py b/channel/wechat_kf/wechat_kf_channel.py index c725ccbd..e33662db 100644 --- a/channel/wechat_kf/wechat_kf_channel.py +++ b/channel/wechat_kf/wechat_kf_channel.py @@ -82,9 +82,11 @@ class WechatKfChannel(ChatChannel): # corrupts URLs and triggers errcode 40014. self.client = WeChatClient(self.corp_id, self.secret) - # Cursor file is an internal implementation detail — fixed under - # the project's `tmp/` dir, not exposed as a user-facing config. - cursor_path = os.path.join("tmp", "wechat_kf_cursors.json") + # Persist sync_msg cursor under the user's home dir by default, + # so it survives `tmp/` cleanups and cwd changes across restarts. + cursor_path = os.path.expanduser( + conf().get("wechat_kf_cursor_path") or "~/.wechat_kf_cursors.json" + ) self.cursor_store = CursorStore(cursor_path) # WeCom requires the callback HTTP response to return within ~5s, diff --git a/channel/wechat_kf/wechat_kf_cursor_store.py b/channel/wechat_kf/wechat_kf_cursor_store.py index 72ba3301..cc809450 100644 --- a/channel/wechat_kf/wechat_kf_cursor_store.py +++ b/channel/wechat_kf/wechat_kf_cursor_store.py @@ -48,6 +48,12 @@ class CursorStore: with open(tmp_path, "w", encoding="utf-8") as f: json.dump(self._data, f, ensure_ascii=False) os.replace(tmp_path, self._file_path) + # Tighten permissions: cursor file lives in $HOME, restrict to owner. + # No-op on Windows. + try: + os.chmod(self._file_path, 0o600) + except Exception: + pass except Exception as e: logger.warning(f"[wechat_kf] failed to flush cursor file {self._file_path}: {e}") try: diff --git a/config.py b/config.py index 2463ab0e..19355576 100644 --- a/config.py +++ b/config.py @@ -157,6 +157,7 @@ available_setting = { "wechat_kf_port": 9888, # 微信客服回调服务端口 "wechat_kf_secret": "", # 微信客服应用的secret "wechat_kf_aes_key": "", # 微信客服回调aes_key + "wechat_kf_cursor_path": "~/.wechat_kf_cursors.json", # 微信客服sync_msg游标持久化文件路径 # 飞书配置 "feishu_port": 80, # 飞书bot监听端口,仅webhook模式需要 "feishu_app_id": "", # 飞书机器人应用APP Id