From 08323e05df9680ff1868544b563c0e9d9c1dbf02 Mon Sep 17 00:00:00 2001 From: Sarv Date: Thu, 28 Aug 2025 19:36:30 +0800 Subject: [PATCH] fix(auto decrypt): fix remote serve fsnotify watch (#231) --- README.md | 2 ++ cmd/chatlog/cmd_server.go | 2 ++ docs/docker.md | 4 ++-- internal/chatlog/wechat/service.go | 11 ++++++++++- internal/model/message.go | 5 +++++ internal/model/message_v3.go | 30 +++++++++++++++++++++++------- 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 81bcc87..43c7471 100644 --- a/README.md +++ b/README.md @@ -216,6 +216,8 @@ GET /api/v1/chatlog?time=2023-01-01&talker=wxid_xxx 需开启自动解密功能,当收到特定新消息时,可以通过 HTTP POST 请求将消息推送到指定的 URL。 +> 延迟测试: 本地服务消息回调延迟约 13 秒; 远程同步消息回调延迟约 45 秒。 + #### 0. 回调配置 使用 TUI 模式的话,在 `$HOME/.chatlog/chatlog.json` 配置文件中,新增 `webhook` 配置。 diff --git a/cmd/chatlog/cmd_server.go b/cmd/chatlog/cmd_server.go index f627eb0..c606f62 100644 --- a/cmd/chatlog/cmd_server.go +++ b/cmd/chatlog/cmd_server.go @@ -9,6 +9,8 @@ import ( func init() { rootCmd.AddCommand(serverCmd) + serverCmd.PersistentPreRun = initLog + serverCmd.PersistentFlags().BoolVar(&Debug, "debug", false, "debug") serverCmd.Flags().StringVarP(&serverAddr, "addr", "a", "", "server address") serverCmd.Flags().StringVarP(&serverPlatform, "platform", "p", "", "platform") serverCmd.Flags().IntVarP(&serverVer, "version", "v", 0, "version") diff --git a/docs/docker.md b/docs/docker.md index 6a37f49..21c13a8 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -246,8 +246,8 @@ docker-compose down #### 配置指南 -- 本地配置: 同步数据目录(Data Dir),可设置为仅发送 -- 远程服务器配置: 设置为仅接收 +- 本地配置: 同步数据目录(Data Dir),可设置为仅发送;在首次完整同步文件后,建议将 "rescanIntervalS" 设置为 0,全局扫描较为耗时,且扫描过程中会暂停同步 +- 远程服务器配置: 设置为仅接收,同样建议将 "rescanIntervalS" 设置为 0 - 使用 Docker / Docker Compose 启动 chatlog,将数据目录映射到容器的 `/app/data` 目录 - 按需配置 `/app/work` 映射目录,可配置到远程服务器本地路径或命名卷 - 启动容器后,等待首次解密完成后,即可正常请求 API 或接入 MCP 服务 diff --git a/internal/chatlog/wechat/service.go b/internal/chatlog/wechat/service.go index acd136b..708e312 100644 --- a/internal/chatlog/wechat/service.go +++ b/internal/chatlog/wechat/service.go @@ -68,6 +68,7 @@ func (s *Service) GetDataKey(info *wechat.Account) (string, error) { } func (s *Service) StartAutoDecrypt() error { + log.Info().Msgf("start auto decrypt, data dir: %s", s.conf.GetDataDir()) dbGroup, err := filemonitor.NewFileGroup("wechat", s.conf.GetDataDir(), `.*\.db$`, []string{"fts"}) if err != nil { return err @@ -94,7 +95,15 @@ func (s *Service) StopAutoDecrypt() error { } func (s *Service) DecryptFileCallback(event fsnotify.Event) error { - if event.Op.Has(fsnotify.Chmod) || !event.Op.Has(fsnotify.Write) { + // Local file system + // WRITE "/db_storage/message/message_0.db" + // WRITE "/db_storage/message/message_0.db" + // WRITE|CHMOD "/db_storage/message/message_0.db" + // Syncthing + // REMOVE "/app/data/db_storage/session/session.db" + // CREATE "/app/data/db_storage/session/session.db" ← "/app/data/db_storage/session/.syncthing.session.db.tmp" + // CHMOD "/app/data/db_storage/session/session.db" + if !(event.Op.Has(fsnotify.Write) || event.Op.Has(fsnotify.Create)) { return nil } diff --git a/internal/model/message.go b/internal/model/message.go index 4317be9..e2601e0 100644 --- a/internal/model/message.go +++ b/internal/model/message.go @@ -358,6 +358,11 @@ func (m *Message) PlainTextContent() string { keylist = append(keylist, path) } } + if m.Contents["thumbpath"] != nil { + if thumbpath, ok := m.Contents["thumbpath"].(string); ok { + keylist = append(keylist, thumbpath) + } + } return fmt.Sprintf("![图片](http://%s/image/%s)", m.Contents["host"], strings.Join(keylist, ",")) case MessageTypeVoice: if voice, ok := m.Contents["voice"]; ok { diff --git a/internal/model/message_v3.go b/internal/model/message_v3.go index 2471883..10e6aff 100644 --- a/internal/model/message_v3.go +++ b/internal/model/message_v3.go @@ -89,14 +89,22 @@ func (m *MessageV3) Wrap() *Message { if _m.IsChatRoom { _m.Sender = bytesExtra[1] } - // FIXME xml 中的 md5 数据无法匹配到 hardlink 记录,所以直接用 proto 数据 - if _m.Type == 43 { - path := bytesExtra[4] - parts := strings.Split(filepath.ToSlash(path), "/") - if len(parts) > 1 { - path = strings.Join(parts[1:], "/") + + // 图片处理 + if _m.Type == MessageTypeImage { + if len(bytesExtra[4]) > 0 { + _m.Contents["path"] = ParseBytesExtraPath(bytesExtra[4]) + } + if len(bytesExtra[3]) > 0 { + _m.Contents["thumbpath"] = ParseBytesExtraPath(bytesExtra[3]) + } + } + + // FIXME xml 中的 md5 数据无法匹配到 hardlink 记录,所以直接用 proto 数据 + if _m.Type == MessageTypeVideo { + if len(bytesExtra[4]) > 0 { + _m.Contents["path"] = ParseBytesExtraPath(bytesExtra[4]) } - _m.Contents["videofile"] = path } } } @@ -122,3 +130,11 @@ func ParseBytesExtra(b []byte) map[int]string { return ret } + +func ParseBytesExtraPath(s string) string { + parts := strings.Split(filepath.ToSlash(s), "/") + if len(parts) > 1 { + return strings.Join(parts[1:], "/") + } + return s +}