adjust errors and logger (#10)
This commit is contained in:
@@ -9,11 +9,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
"github.com/sjzar/chatlog/pkg/util"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -45,19 +46,19 @@ func New(path string) (*DataSource, error) {
|
||||
}
|
||||
|
||||
if err := ds.initMessageDbs(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化消息数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
if err := ds.initContactDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化联系人数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
if err := ds.initChatRoomDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化群聊数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
if err := ds.initSessionDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化会话数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
if err := ds.initMediaDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化会话数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
@@ -67,11 +68,11 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
|
||||
files, err := util.FindFilesWithPatterns(path, MessageFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找消息数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, MessageFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到任何消息数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, MessageFilePattern, nil)
|
||||
}
|
||||
|
||||
// 处理每个数据库文件
|
||||
@@ -79,7 +80,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
// 连接数据库
|
||||
db, err := sql.Open("sqlite3", filePath)
|
||||
if err != nil {
|
||||
log.Printf("警告: 连接数据库 %s 失败: %v", filePath, err)
|
||||
log.Err(err).Msgf("连接数据库 %s 失败", filePath)
|
||||
continue
|
||||
}
|
||||
ds.messageDbs = append(ds.messageDbs, db)
|
||||
@@ -87,14 +88,14 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
// 获取所有表名
|
||||
rows, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'Chat_%'")
|
||||
if err != nil {
|
||||
log.Printf("警告: 获取表名失败: %v", err)
|
||||
log.Err(err).Msgf("数据库 %s 中没有 Chat 表", filePath)
|
||||
continue
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var tableName string
|
||||
if err := rows.Scan(&tableName); err != nil {
|
||||
log.Printf("警告: 扫描表名失败: %v", err)
|
||||
log.Err(err).Msgf("数据库 %s 扫描表名失败", filePath)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -115,16 +116,16 @@ func (ds *DataSource) initContactDb(path string) error {
|
||||
|
||||
files, err := util.FindFilesWithPatterns(path, ContactFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找联系人数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, ContactFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到联系人数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, ContactFilePattern, nil)
|
||||
}
|
||||
|
||||
ds.contactDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接联系人数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -133,19 +134,19 @@ func (ds *DataSource) initContactDb(path string) error {
|
||||
func (ds *DataSource) initChatRoomDb(path string) error {
|
||||
files, err := util.FindFilesWithPatterns(path, ChatRoomFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找群聊数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, ChatRoomFilePattern, err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到群聊数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, ChatRoomFilePattern, nil)
|
||||
}
|
||||
ds.chatRoomDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接群聊数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
|
||||
rows, err := ds.chatRoomDb.Query("SELECT m_nsUsrName, IFNULL(nickname,\"\") FROM GroupMember")
|
||||
if err != nil {
|
||||
log.Printf("警告: 获取群聊成员失败: %v", err)
|
||||
log.Err(err).Msgf("数据库 %s 获取群聊成员失败", files[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -153,7 +154,7 @@ func (ds *DataSource) initChatRoomDb(path string) error {
|
||||
var user string
|
||||
var nickName string
|
||||
if err := rows.Scan(&user, &nickName); err != nil {
|
||||
log.Printf("警告: 扫描表名失败: %v", err)
|
||||
log.Err(err).Msgf("数据库 %s 扫描表名失败", files[0])
|
||||
continue
|
||||
}
|
||||
ds.user2DisplayName[user] = nickName
|
||||
@@ -166,14 +167,14 @@ func (ds *DataSource) initChatRoomDb(path string) error {
|
||||
func (ds *DataSource) initSessionDb(path string) error {
|
||||
files, err := util.FindFilesWithPatterns(path, SessionFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找最近会话数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, SessionFilePattern, err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到最近会话数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, SessionFilePattern, nil)
|
||||
}
|
||||
ds.sessionDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接最近会话数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -181,14 +182,14 @@ func (ds *DataSource) initSessionDb(path string) error {
|
||||
func (ds *DataSource) initMediaDb(path string) error {
|
||||
files, err := util.FindFilesWithPatterns(path, MediaFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找媒体数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, MediaFilePattern, err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到媒体数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, MediaFilePattern, nil)
|
||||
}
|
||||
ds.mediaDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接媒体数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -198,14 +199,14 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
// 在 darwinv3 中,每个联系人/群聊的消息存储在单独的表中,表名为 Chat_md5(talker)
|
||||
// 首先需要找到对应的表名
|
||||
if talker == "" {
|
||||
return nil, fmt.Errorf("talker 不能为空")
|
||||
return nil, errors.ErrTalkerEmpty
|
||||
}
|
||||
|
||||
_talkerMd5Bytes := md5.Sum([]byte(talker))
|
||||
talkerMd5 := hex.EncodeToString(_talkerMd5Bytes[:])
|
||||
db, ok := ds.talkerDBMap[talkerMd5]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("未找到 talker %s 的消息数据库", talker)
|
||||
return nil, errors.TalkerNotFound(talker)
|
||||
}
|
||||
tableName := fmt.Sprintf("Chat_%s", talkerMd5)
|
||||
|
||||
@@ -228,7 +229,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
// 执行查询
|
||||
rows, err := db.QueryContext(ctx, query, startTime.Unix(), endTime.Unix())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询表 %s 失败: %w", tableName, err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -243,7 +244,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
&msg.MesDes,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("警告: 扫描消息行失败: %v", err)
|
||||
log.Err(err).Msgf("扫描消息行失败")
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -298,7 +299,7 @@ func (ds *DataSource) GetContacts(ctx context.Context, key string, limit, offset
|
||||
// 执行查询
|
||||
rows, err := ds.contactDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询联系人失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -314,7 +315,7 @@ func (ds *DataSource) GetContacts(ctx context.Context, key string, limit, offset
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描联系人行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
contacts = append(contacts, contactDarwinV3.Wrap())
|
||||
@@ -352,7 +353,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
// 执行查询
|
||||
rows, err := ds.chatRoomDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询群聊失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -368,7 +369,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描群聊行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
chatRooms = append(chatRooms, chatRoomDarwinV3.Wrap(ds.user2DisplayName))
|
||||
@@ -386,7 +387,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
contacts[0].UserName)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询群聊失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -401,7 +402,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描群聊行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
chatRooms = append(chatRooms, chatRoomDarwinV3.Wrap(ds.user2DisplayName))
|
||||
@@ -449,7 +450,7 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
// 执行查询
|
||||
rows, err := ds.sessionDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询会话失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -462,7 +463,7 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描会话行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
// 包装成通用模型
|
||||
@@ -488,7 +489,7 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
|
||||
func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*model.Media, error) {
|
||||
if key == "" {
|
||||
return nil, fmt.Errorf("key 不能为空")
|
||||
return nil, errors.ErrKeyEmpty
|
||||
}
|
||||
query := `SELECT
|
||||
r.mediaMd5,
|
||||
@@ -507,7 +508,7 @@ WHERE
|
||||
// 执行查询
|
||||
rows, err := ds.mediaDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询媒体失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -524,7 +525,7 @@ WHERE
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描会话行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
// 包装成通用模型
|
||||
@@ -532,7 +533,7 @@ WHERE
|
||||
}
|
||||
|
||||
if media == nil {
|
||||
return nil, fmt.Errorf("未找到媒体 %s", key)
|
||||
return nil, errors.ErrMediaNotFound
|
||||
}
|
||||
|
||||
return media, nil
|
||||
@@ -543,42 +544,42 @@ func (ds *DataSource) Close() error {
|
||||
var errs []error
|
||||
|
||||
// 关闭消息数据库连接
|
||||
for i, db := range ds.messageDbs {
|
||||
for _, db := range ds.messageDbs {
|
||||
if err := db.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭消息数据库 %d 失败: %w", i, err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭联系人数据库连接
|
||||
if ds.contactDb != nil {
|
||||
if err := ds.contactDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭联系人数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭群聊数据库连接
|
||||
if ds.chatRoomDb != nil {
|
||||
if err := ds.chatRoomDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭群聊数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭会话数据库连接
|
||||
if ds.sessionDb != nil {
|
||||
if err := ds.sessionDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭会话数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭媒体数据库连接
|
||||
if ds.mediaDb != nil {
|
||||
if err := ds.mediaDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭媒体数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("关闭数据库连接时发生错误: %v", errs)
|
||||
return errors.DBCloseFailed(errs[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -2,20 +2,15 @@ package datasource
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
"github.com/sjzar/chatlog/internal/wechatdb/datasource/darwinv3"
|
||||
v4 "github.com/sjzar/chatlog/internal/wechatdb/datasource/v4"
|
||||
"github.com/sjzar/chatlog/internal/wechatdb/datasource/windowsv3"
|
||||
)
|
||||
|
||||
// 错误定义
|
||||
var (
|
||||
ErrUnsupportedPlatform = fmt.Errorf("unsupported platform")
|
||||
)
|
||||
|
||||
type DataSource interface {
|
||||
|
||||
// 消息
|
||||
@@ -36,7 +31,7 @@ type DataSource interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
func NewDataSource(path string, platform string, version int) (DataSource, error) {
|
||||
func New(path string, platform string, version int) (DataSource, error) {
|
||||
switch {
|
||||
case platform == "windows" && version == 3:
|
||||
return windowsv3.New(path)
|
||||
@@ -47,6 +42,6 @@ func NewDataSource(path string, platform string, version int) (DataSource, error
|
||||
case platform == "darwin" && version == 4:
|
||||
return v4.New(path)
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: %s v%d", ErrUnsupportedPlatform, platform, version)
|
||||
return nil, errors.PlatformUnsupported(platform, version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@ import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
"github.com/sjzar/chatlog/pkg/util"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -51,16 +52,16 @@ func New(path string) (*DataSource, error) {
|
||||
}
|
||||
|
||||
if err := ds.initMessageDbs(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化消息数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
if err := ds.initContactDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化联系人数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
if err := ds.initSessionDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化会话数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
if err := ds.initMediaDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化媒体数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
@@ -70,11 +71,11 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
// 查找所有消息数据库文件
|
||||
files, err := util.FindFilesWithPatterns(path, MessageFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找消息数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, MessageFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到任何消息数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, MessageFilePattern, nil)
|
||||
}
|
||||
|
||||
// 处理每个数据库文件
|
||||
@@ -82,7 +83,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
// 连接数据库
|
||||
db, err := sql.Open("sqlite3", filePath)
|
||||
if err != nil {
|
||||
log.Printf("警告: 连接数据库 %s 失败: %v", filePath, err)
|
||||
log.Err(err).Msgf("连接数据库 %s 失败", filePath)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -92,7 +93,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
|
||||
row := db.QueryRow("SELECT timestamp FROM Timestamp LIMIT 1")
|
||||
if err := row.Scan(×tamp); err != nil {
|
||||
log.Printf("警告: 获取数据库 %s 的时间戳失败: %v", filePath, err)
|
||||
log.Err(err).Msgf("获取数据库 %s 的时间戳失败", filePath)
|
||||
db.Close()
|
||||
continue
|
||||
}
|
||||
@@ -102,7 +103,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
id2Name := make(map[int]string)
|
||||
rows, err := db.Query("SELECT user_name FROM Name2Id")
|
||||
if err != nil {
|
||||
log.Printf("警告: 获取数据库 %s 的 Name2Id 表失败: %v", filePath, err)
|
||||
log.Err(err).Msgf("获取数据库 %s 的 Name2Id 表失败", filePath)
|
||||
db.Close()
|
||||
continue
|
||||
}
|
||||
@@ -111,7 +112,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
for rows.Next() {
|
||||
var name string
|
||||
if err := rows.Scan(&name); err != nil {
|
||||
log.Printf("警告: 扫描 Name2Id 行失败: %v", err)
|
||||
log.Err(err).Msgf("数据库 %s 扫描 Name2Id 行失败", filePath)
|
||||
continue
|
||||
}
|
||||
id2Name[i] = name
|
||||
@@ -150,16 +151,16 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
func (ds *DataSource) initContactDb(path string) error {
|
||||
files, err := util.FindFilesWithPatterns(path, ContactFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找联系人数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, ContactFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到联系人数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, ContactFilePattern, nil)
|
||||
}
|
||||
|
||||
ds.contactDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接联系人数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -168,14 +169,14 @@ func (ds *DataSource) initContactDb(path string) error {
|
||||
func (ds *DataSource) initSessionDb(path string) error {
|
||||
files, err := util.FindFilesWithPatterns(path, SessionFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找最近会话数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, SessionFilePattern, err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到最近会话数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, SessionFilePattern, nil)
|
||||
}
|
||||
ds.sessionDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接最近会话数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -183,14 +184,14 @@ func (ds *DataSource) initSessionDb(path string) error {
|
||||
func (ds *DataSource) initMediaDb(path string) error {
|
||||
files, err := util.FindFilesWithPatterns(path, MediaFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找媒体数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, MediaFilePattern, err)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到媒体数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, MediaFilePattern, nil)
|
||||
}
|
||||
ds.mediaDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接媒体数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -208,13 +209,13 @@ func (ds *DataSource) getDBInfosForTimeRange(startTime, endTime time.Time) []Mes
|
||||
|
||||
func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.Time, talker string, limit, offset int) ([]*model.Message, error) {
|
||||
if talker == "" {
|
||||
return nil, fmt.Errorf("必须指定 talker 参数")
|
||||
return nil, errors.ErrTalkerEmpty
|
||||
}
|
||||
|
||||
// 找到时间范围内的数据库文件
|
||||
dbInfos := ds.getDBInfosForTimeRange(startTime, endTime)
|
||||
if len(dbInfos) == 0 {
|
||||
return nil, fmt.Errorf("未找到时间范围 %v 到 %v 内的数据库文件", startTime, endTime)
|
||||
return nil, errors.TimeRangeNotFound(startTime, endTime)
|
||||
}
|
||||
|
||||
if len(dbInfos) == 1 {
|
||||
@@ -233,13 +234,13 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
|
||||
db, ok := ds.messageDbs[dbInfo.FilePath]
|
||||
if !ok {
|
||||
log.Printf("警告: 数据库 %s 未打开", dbInfo.FilePath)
|
||||
log.Error().Msgf("数据库 %s 未打开", dbInfo.FilePath)
|
||||
continue
|
||||
}
|
||||
|
||||
messages, err := ds.getMessagesFromDB(ctx, db, dbInfo, startTime, endTime, talker)
|
||||
if err != nil {
|
||||
log.Printf("警告: 从数据库 %s 获取消息失败: %v", dbInfo.FilePath, err)
|
||||
log.Err(err).Msgf("从数据库 %s 获取消息失败", dbInfo.FilePath)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -274,7 +275,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
func (ds *DataSource) getMessagesSingleFile(ctx context.Context, dbInfo MessageDBInfo, startTime, endTime time.Time, talker string, limit, offset int) ([]*model.Message, error) {
|
||||
db, ok := ds.messageDbs[dbInfo.FilePath]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("数据库 %s 未打开", dbInfo.FilePath)
|
||||
return nil, errors.DBConnectFailed(dbInfo.FilePath, nil)
|
||||
}
|
||||
|
||||
// 构建表名
|
||||
@@ -303,7 +304,7 @@ func (ds *DataSource) getMessagesSingleFile(ctx context.Context, dbInfo MessageD
|
||||
// 执行查询
|
||||
rows, err := db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询数据库 %s 失败: %w", dbInfo.FilePath, err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -323,7 +324,7 @@ func (ds *DataSource) getMessagesSingleFile(ctx context.Context, dbInfo MessageD
|
||||
&msg.Status,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描消息行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
messages = append(messages, msg.Wrap(dbInfo.ID2Name, isChatRoom))
|
||||
@@ -350,7 +351,7 @@ func (ds *DataSource) getMessagesFromDB(ctx context.Context, db *sql.DB, dbInfo
|
||||
// 表不存在,返回空结果
|
||||
return []*model.Message{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("检查表 %s 是否存在失败: %w", tableName, err)
|
||||
return nil, errors.QueryFailed("", err)
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
@@ -371,7 +372,7 @@ func (ds *DataSource) getMessagesFromDB(ctx context.Context, db *sql.DB, dbInfo
|
||||
if strings.Contains(err.Error(), "no such table") {
|
||||
return []*model.Message{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("查询数据库失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -391,7 +392,7 @@ func (ds *DataSource) getMessagesFromDB(ctx context.Context, db *sql.DB, dbInfo
|
||||
&msg.Status,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描消息行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
messages = append(messages, msg.Wrap(dbInfo.ID2Name, isChatRoom))
|
||||
@@ -428,7 +429,7 @@ func (ds *DataSource) GetContacts(ctx context.Context, key string, limit, offset
|
||||
// 执行查询
|
||||
rows, err := ds.contactDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询联系人失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -444,7 +445,7 @@ func (ds *DataSource) GetContacts(ctx context.Context, key string, limit, offset
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描联系人行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
contacts = append(contacts, contactV4.Wrap())
|
||||
@@ -466,7 +467,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
// 执行查询
|
||||
rows, err := ds.contactDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询群聊失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -480,7 +481,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描群聊行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
chatRooms = append(chatRooms, chatRoomV4.Wrap())
|
||||
@@ -496,7 +497,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
contacts[0].UserName)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询群聊失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -509,7 +510,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描群聊行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
chatRooms = append(chatRooms, chatRoomV4.Wrap())
|
||||
@@ -543,7 +544,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
// 执行查询
|
||||
rows, err := ds.contactDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询群聊失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -557,7 +558,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描群聊行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
chatRooms = append(chatRooms, chatRoomV4.Wrap())
|
||||
@@ -597,7 +598,7 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
// 执行查询
|
||||
rows, err := ds.sessionDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询会话失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -613,7 +614,7 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描会话行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
sessions = append(sessions, sessionV4.Wrap())
|
||||
@@ -624,11 +625,11 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
|
||||
func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*model.Media, error) {
|
||||
if key == "" {
|
||||
return nil, fmt.Errorf("key 不能为空")
|
||||
return nil, errors.ErrKeyEmpty
|
||||
}
|
||||
|
||||
if len(key) != 32 {
|
||||
return nil, fmt.Errorf("key 长度必须为 32")
|
||||
return nil, errors.ErrKeyLengthMust32
|
||||
}
|
||||
|
||||
var table string
|
||||
@@ -640,7 +641,7 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
case "file":
|
||||
table = "file_hardlink_info_v3"
|
||||
default:
|
||||
return nil, fmt.Errorf("不支持的媒体类型: %s", _type)
|
||||
return nil, errors.MediaTypeUnsupported(_type)
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
@@ -663,7 +664,7 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
|
||||
rows, err := ds.mediaDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询媒体失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -679,7 +680,7 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
&mediaV4.Dir2,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描会话行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
mediaV4.Type = _type
|
||||
media = mediaV4.Wrap()
|
||||
@@ -691,7 +692,7 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
}
|
||||
|
||||
if media == nil {
|
||||
return nil, fmt.Errorf("未找到媒体 %s", key)
|
||||
return nil, errors.ErrMediaNotFound
|
||||
}
|
||||
|
||||
return media, nil
|
||||
@@ -701,34 +702,34 @@ func (ds *DataSource) Close() error {
|
||||
var errs []error
|
||||
|
||||
// 关闭消息数据库连接
|
||||
for path, db := range ds.messageDbs {
|
||||
for _, db := range ds.messageDbs {
|
||||
if err := db.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭消息数据库 %s 失败: %w", path, err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭联系人数据库连接
|
||||
if ds.contactDb != nil {
|
||||
if err := ds.contactDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭联系人数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭会话数据库连接
|
||||
if ds.sessionDb != nil {
|
||||
if err := ds.sessionDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭会话数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if ds.mediaDb != nil {
|
||||
if err := ds.mediaDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭媒体数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("关闭数据库连接时发生错误: %v", errs)
|
||||
return errors.DBCloseFailed(errs[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -5,15 +5,16 @@ import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
"github.com/sjzar/chatlog/pkg/util"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -56,16 +57,16 @@ func New(path string) (*DataSource, error) {
|
||||
|
||||
// 初始化消息数据库
|
||||
if err := ds.initMessageDbs(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化消息数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
|
||||
// 初始化联系人数据库
|
||||
if err := ds.initContactDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化联系人数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
|
||||
if err := ds.initMediaDb(path); err != nil {
|
||||
return nil, fmt.Errorf("初始化多媒体数据库失败: %w", err)
|
||||
return nil, errors.DBInitFailed(err)
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
@@ -76,11 +77,11 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
// 查找所有消息数据库文件
|
||||
files, err := util.FindFilesWithPatterns(path, MessageFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找消息数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, MessageFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到任何消息数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, MessageFilePattern, nil)
|
||||
}
|
||||
|
||||
// 处理每个数据库文件
|
||||
@@ -88,7 +89,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
// 连接数据库
|
||||
db, err := sql.Open("sqlite3", filePath)
|
||||
if err != nil {
|
||||
log.Printf("警告: 连接数据库 %s 失败: %v", filePath, err)
|
||||
log.Err(err).Msgf("连接数据库 %s 失败", filePath)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
|
||||
rows, err := db.Query("SELECT tableIndex, tableVersion, tableDesc FROM DBInfo")
|
||||
if err != nil {
|
||||
log.Printf("警告: 查询数据库 %s 的 DBInfo 表失败: %v", filePath, err)
|
||||
log.Err(err).Msgf("查询数据库 %s 的 DBInfo 表失败", filePath)
|
||||
db.Close()
|
||||
continue
|
||||
}
|
||||
@@ -108,7 +109,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
var tableDesc string
|
||||
|
||||
if err := rows.Scan(&tableIndex, &tableVersion, &tableDesc); err != nil {
|
||||
log.Printf("警告: 扫描 DBInfo 行失败: %v", err)
|
||||
log.Err(err).Msg("扫描 DBInfo 行失败")
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
talkerMap := make(map[string]int)
|
||||
rows, err = db.Query("SELECT UsrName FROM Name2ID")
|
||||
if err != nil {
|
||||
log.Printf("警告: 查询数据库 %s 的 Name2ID 表失败: %v", filePath, err)
|
||||
log.Err(err).Msgf("查询数据库 %s 的 Name2ID 表失败", filePath)
|
||||
db.Close()
|
||||
continue
|
||||
}
|
||||
@@ -133,7 +134,7 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
for rows.Next() {
|
||||
var userName string
|
||||
if err := rows.Scan(&userName); err != nil {
|
||||
log.Printf("警告: 扫描 Name2ID 行失败: %v", err)
|
||||
log.Err(err).Msg("扫描 Name2ID 行失败")
|
||||
continue
|
||||
}
|
||||
talkerMap[userName] = i
|
||||
@@ -173,18 +174,18 @@ func (ds *DataSource) initMessageDbs(path string) error {
|
||||
func (ds *DataSource) initContactDb(path string) error {
|
||||
files, err := util.FindFilesWithPatterns(path, ContactFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找联系人数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, ContactFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到联系人数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, ContactFilePattern, nil)
|
||||
}
|
||||
|
||||
ds.contactDbFile = files[0]
|
||||
|
||||
ds.contactDb, err = sql.Open("sqlite3", ds.contactDbFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接联系人数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(ds.contactDbFile, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -194,44 +195,44 @@ func (ds *DataSource) initContactDb(path string) error {
|
||||
func (ds *DataSource) initMediaDb(path string) error {
|
||||
files, err := util.FindFilesWithPatterns(path, ImageFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找图片数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, ImageFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到图片数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, ImageFilePattern, nil)
|
||||
}
|
||||
|
||||
ds.imageDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接图片数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
|
||||
files, err = util.FindFilesWithPatterns(path, VideoFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找视频数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, VideoFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到视频数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, VideoFilePattern, nil)
|
||||
}
|
||||
|
||||
ds.videoDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接视频数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
|
||||
files, err = util.FindFilesWithPatterns(path, FileFilePattern, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查找文件数据库文件失败: %w", err)
|
||||
return errors.DBFileNotFound(path, FileFilePattern, err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("未找到文件数据库文件: %s", path)
|
||||
return errors.DBFileNotFound(path, FileFilePattern, nil)
|
||||
}
|
||||
|
||||
ds.fileDb, err = sql.Open("sqlite3", files[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接文件数据库失败: %w", err)
|
||||
return errors.DBConnectFailed(files[0], err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -253,7 +254,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
// 找到时间范围内的数据库文件
|
||||
dbInfos := ds.getDBInfosForTimeRange(startTime, endTime)
|
||||
if len(dbInfos) == 0 {
|
||||
return nil, fmt.Errorf("未找到时间范围 %v 到 %v 内的数据库文件", startTime, endTime)
|
||||
return nil, errors.TimeRangeNotFound(startTime, endTime)
|
||||
}
|
||||
|
||||
if len(dbInfos) == 1 {
|
||||
@@ -272,7 +273,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
|
||||
db, ok := ds.messageDbs[dbInfo.FilePath]
|
||||
if !ok {
|
||||
log.Printf("警告: 数据库 %s 未打开", dbInfo.FilePath)
|
||||
log.Error().Msgf("数据库 %s 未打开", dbInfo.FilePath)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -302,7 +303,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
// 执行查询
|
||||
rows, err := db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
log.Printf("警告: 查询数据库 %s 失败: %v", dbInfo.FilePath, err)
|
||||
log.Err(err).Msgf("查询数据库 %s 失败", dbInfo.FilePath)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -325,7 +326,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
|
||||
&bytesExtra,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("警告: 扫描消息行失败: %v", err)
|
||||
log.Err(err).Msg("扫描消息行失败")
|
||||
continue
|
||||
}
|
||||
msg.CompressContent = compressContent
|
||||
@@ -395,7 +396,7 @@ func (ds *DataSource) getMessagesSingleFile(ctx context.Context, dbInfo MessageD
|
||||
// 执行查询
|
||||
rows, err := ds.messageDbs[dbInfo.FilePath].QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询数据库 %s 失败: %w", dbInfo.FilePath, err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -418,7 +419,7 @@ func (ds *DataSource) getMessagesSingleFile(ctx context.Context, dbInfo MessageD
|
||||
&bytesExtra,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描消息行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
msg.CompressContent = compressContent
|
||||
msg.BytesExtra = bytesExtra
|
||||
@@ -454,7 +455,7 @@ func (ds *DataSource) GetContacts(ctx context.Context, key string, limit, offset
|
||||
// 执行查询
|
||||
rows, err := ds.contactDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询联系人失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -470,7 +471,7 @@ func (ds *DataSource) GetContacts(ctx context.Context, key string, limit, offset
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描联系人行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
contacts = append(contacts, contactV3.Wrap())
|
||||
@@ -492,7 +493,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
// 执行查询
|
||||
rows, err := ds.contactDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询群聊失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -506,7 +507,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描群聊行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
chatRooms = append(chatRooms, chatRoomV3.Wrap())
|
||||
@@ -522,7 +523,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
contacts[0].UserName)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询群聊失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -535,7 +536,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描群聊行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
chatRooms = append(chatRooms, chatRoomV3.Wrap())
|
||||
@@ -569,7 +570,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
// 执行查询
|
||||
rows, err := ds.contactDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询群聊失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -583,7 +584,7 @@ func (ds *DataSource) GetChatRooms(ctx context.Context, key string, limit, offse
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描群聊行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
chatRooms = append(chatRooms, chatRoomV3.Wrap())
|
||||
@@ -623,7 +624,7 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
// 执行查询
|
||||
rows, err := ds.contactDb.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询会话失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -639,7 +640,7 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描会话行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
|
||||
sessions = append(sessions, sessionV3.Wrap())
|
||||
@@ -650,12 +651,12 @@ func (ds *DataSource) GetSessions(ctx context.Context, key string, limit, offset
|
||||
|
||||
func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*model.Media, error) {
|
||||
if key == "" {
|
||||
return nil, fmt.Errorf("key 不能为空")
|
||||
return nil, errors.ErrKeyEmpty
|
||||
}
|
||||
|
||||
md5key, err := hex.DecodeString(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析 key 失败: %w", err)
|
||||
return nil, errors.DecodeKeyFailed(err)
|
||||
}
|
||||
|
||||
var db *sql.DB
|
||||
@@ -675,7 +676,7 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
table1 = "HardLinkFileAttribute"
|
||||
table2 = "HardLinkFileID"
|
||||
default:
|
||||
return nil, fmt.Errorf("不支持的媒体类型: %s", _type)
|
||||
return nil, errors.MediaTypeUnsupported(_type)
|
||||
|
||||
}
|
||||
|
||||
@@ -698,7 +699,7 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
|
||||
rows, err := db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询媒体失败: %w", err)
|
||||
return nil, errors.QueryFailed(query, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
@@ -712,7 +713,7 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
&mediaV3.Dir2,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描会话行失败: %w", err)
|
||||
return nil, errors.ScanRowFailed(err)
|
||||
}
|
||||
mediaV3.Type = _type
|
||||
mediaV3.Key = key
|
||||
@@ -720,7 +721,7 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
}
|
||||
|
||||
if media == nil {
|
||||
return nil, fmt.Errorf("未找到媒体 %s", key)
|
||||
return nil, errors.ErrMediaNotFound
|
||||
}
|
||||
|
||||
return media, nil
|
||||
@@ -731,37 +732,37 @@ func (ds *DataSource) Close() error {
|
||||
var errs []error
|
||||
|
||||
// 关闭消息数据库连接
|
||||
for path, db := range ds.messageDbs {
|
||||
for _, db := range ds.messageDbs {
|
||||
if err := db.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭消息数据库 %s 失败: %w", path, err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭联系人数据库连接
|
||||
if ds.contactDb != nil {
|
||||
if err := ds.contactDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭联系人数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if ds.imageDb != nil {
|
||||
if err := ds.imageDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭图片数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if ds.videoDb != nil {
|
||||
if err := ds.videoDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭视频数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if ds.fileDb != nil {
|
||||
if err := ds.fileDb.Close(); err != nil {
|
||||
errs = append(errs, fmt.Errorf("关闭文件数据库失败: %w", err))
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("关闭数据库连接时发生错误: %v", errs)
|
||||
return errors.DBCloseFailed(errs[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -2,10 +2,10 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ func (r *Repository) initChatRoomCache(ctx context.Context) error {
|
||||
// 加载所有群聊到缓存
|
||||
chatRooms, err := r.ds.GetChatRooms(ctx, "", 0, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载群聊失败: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
chatRoomMap := make(map[string]*model.ChatRoom)
|
||||
@@ -75,7 +75,7 @@ func (r *Repository) GetChatRooms(ctx context.Context, key string, limit, offset
|
||||
if key != "" {
|
||||
ret = r.findChatRooms(key)
|
||||
if len(ret) == 0 {
|
||||
return nil, fmt.Errorf("未找到群聊: %s", key)
|
||||
return nil, errors.ChatRoomNotFound(key)
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
@@ -111,7 +111,7 @@ func (r *Repository) GetChatRooms(ctx context.Context, key string, limit, offset
|
||||
func (r *Repository) GetChatRoom(ctx context.Context, key string) (*model.ChatRoom, error) {
|
||||
chatRoom := r.findChatRoom(key)
|
||||
if chatRoom == nil {
|
||||
return nil, fmt.Errorf("未找到群聊: %s", key)
|
||||
return nil, errors.ChatRoomNotFound(key)
|
||||
}
|
||||
return chatRoom, nil
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ func (r *Repository) initContactCache(ctx context.Context) error {
|
||||
// 加载所有联系人到缓存
|
||||
contacts, err := r.ds.GetContacts(ctx, "", 0, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("加载联系人失败: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
contactMap := make(map[string]*model.Contact)
|
||||
@@ -78,7 +78,7 @@ func (r *Repository) GetContact(ctx context.Context, key string) (*model.Contact
|
||||
// 先尝试从缓存中获取
|
||||
contact := r.findContact(key)
|
||||
if contact == nil {
|
||||
return nil, fmt.Errorf("未找到联系人: %s", key)
|
||||
return nil, errors.ContactNotFound(key)
|
||||
}
|
||||
return contact, nil
|
||||
}
|
||||
@@ -88,7 +88,7 @@ func (r *Repository) GetContacts(ctx context.Context, key string, limit, offset
|
||||
if key != "" {
|
||||
ret = r.findContacts(key)
|
||||
if len(ret) == 0 {
|
||||
return nil, fmt.Errorf("未找到联系人: %s", key)
|
||||
return nil, errors.ContactNotFound(key)
|
||||
}
|
||||
if limit > 0 {
|
||||
end := offset + limit
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// GetMessages 实现 Repository 接口的 GetMessages 方法
|
||||
@@ -25,7 +25,7 @@ func (r *Repository) GetMessages(ctx context.Context, startTime, endTime time.Ti
|
||||
|
||||
// 补充消息信息
|
||||
if err := r.EnrichMessages(ctx, messages); err != nil {
|
||||
log.Debugf("EnrichMessages failed: %v", err)
|
||||
log.Debug().Msgf("EnrichMessages failed: %v", err)
|
||||
}
|
||||
|
||||
return messages, nil
|
||||
|
||||
@@ -2,8 +2,8 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
"github.com/sjzar/chatlog/internal/wechatdb/datasource"
|
||||
)
|
||||
@@ -58,7 +58,7 @@ func New(ds datasource.DataSource) (*Repository, error) {
|
||||
|
||||
// 初始化缓存
|
||||
if err := r.initCache(context.Background()); err != nil {
|
||||
return nil, fmt.Errorf("初始化缓存失败: %w", err)
|
||||
return nil, errors.InitCacheFailed(err)
|
||||
}
|
||||
|
||||
return r, nil
|
||||
|
||||
@@ -2,7 +2,6 @@ package wechatdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
@@ -45,14 +44,14 @@ func (w *DB) Close() error {
|
||||
|
||||
func (w *DB) Initialize() error {
|
||||
var err error
|
||||
w.ds, err = datasource.NewDataSource(w.path, w.platform, w.version)
|
||||
w.ds, err = datasource.New(w.path, w.platform, w.version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("初始化数据源失败: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
w.repo, err = repository.New(w.ds)
|
||||
if err != nil {
|
||||
return fmt.Errorf("初始化仓库失败: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -64,7 +63,7 @@ func (w *DB) GetMessages(start, end time.Time, talker string, limit, offset int)
|
||||
// 使用 repository 获取消息
|
||||
messages, err := w.repo.GetMessages(ctx, start, end, talker, limit, offset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取消息失败: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return messages, nil
|
||||
@@ -114,7 +113,7 @@ func (w *DB) GetSessions(key string, limit, offset int) (*GetSessionsResp, error
|
||||
// 使用 repository 获取会话列表
|
||||
sessions, err := w.repo.GetSessions(ctx, key, limit, offset)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取会话列表失败: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GetSessionsResp{
|
||||
|
||||
Reference in New Issue
Block a user