x
This commit is contained in:
269
internal/wechatdb/contact.go
Normal file
269
internal/wechatdb/contact.go
Normal file
@@ -0,0 +1,269 @@
|
||||
package wechatdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/sjzar/chatlog/pkg/model"
|
||||
"github.com/sjzar/chatlog/pkg/util"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
ContactFileV3 = "^MicroMsg.db$"
|
||||
ContactFileV4 = "contact.db$"
|
||||
)
|
||||
|
||||
type Contact struct {
|
||||
version int
|
||||
dbFile string
|
||||
db *sql.DB
|
||||
|
||||
Contact map[string]*model.Contact // 好友和群聊信息,Key UserName
|
||||
ChatRoom map[string]*model.ChatRoom // 群聊信息,Key UserName
|
||||
Sessions []*model.Session // 历史会话,按时间倒序
|
||||
|
||||
// Quick Search
|
||||
ChatRoomUsers map[string]*model.Contact // 群聊成员信息,Key UserName
|
||||
Alias2Contack map[string]*model.Contact // 别名到联系人的映射
|
||||
Remark2Contack map[string]*model.Contact // 备注名到联系人的映射
|
||||
NickName2Contack map[string]*model.Contact // 昵称到联系人的映射
|
||||
}
|
||||
|
||||
func NewContact(path string, version int) (*Contact, error) {
|
||||
c := &Contact{
|
||||
version: version,
|
||||
}
|
||||
|
||||
files, err := util.FindFilesWithPatterns(path, ContactFileV3, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查找数据库文件失败: %v", err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return nil, fmt.Errorf("未找到任何数据库文件: %s", path)
|
||||
}
|
||||
|
||||
c.dbFile = files[0]
|
||||
|
||||
c.db, err = sql.Open("sqlite3", c.dbFile)
|
||||
if err != nil {
|
||||
log.Printf("警告: 连接数据库 %s 失败: %v", c.dbFile, err)
|
||||
return nil, fmt.Errorf("连接数据库失败: %v", err)
|
||||
}
|
||||
|
||||
c.loadContact()
|
||||
c.loadChatRoom()
|
||||
c.loadSession()
|
||||
c.fillChatRoomInfo()
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Contact) loadContact() {
|
||||
contactMap := make(map[string]*model.Contact)
|
||||
chatRoomUserMap := make(map[string]*model.Contact)
|
||||
aliasMap := make(map[string]*model.Contact)
|
||||
remarkMap := make(map[string]*model.Contact)
|
||||
nickNameMap := make(map[string]*model.Contact)
|
||||
rows, err := c.db.Query("SELECT UserName, Alias, Remark, NickName, Reserved1 FROM Contact")
|
||||
if err != nil {
|
||||
log.Errorf("查询联系人失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var contactv3 model.ContactV3
|
||||
|
||||
if err := rows.Scan(
|
||||
&contactv3.UserName,
|
||||
&contactv3.Alias,
|
||||
&contactv3.Remark,
|
||||
&contactv3.NickName,
|
||||
&contactv3.Reserved1,
|
||||
); err != nil {
|
||||
log.Printf("警告: 扫描联系人行失败: %v", err)
|
||||
continue
|
||||
}
|
||||
contact := contactv3.Wrap()
|
||||
|
||||
if contact.IsFriend {
|
||||
contactMap[contact.UserName] = contact
|
||||
if contact.Alias != "" {
|
||||
aliasMap[contact.Alias] = contact
|
||||
}
|
||||
if contact.Remark != "" {
|
||||
remarkMap[contact.Remark] = contact
|
||||
}
|
||||
if contact.NickName != "" {
|
||||
nickNameMap[contact.NickName] = contact
|
||||
}
|
||||
} else {
|
||||
chatRoomUserMap[contact.UserName] = contact
|
||||
}
|
||||
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
c.Contact = contactMap
|
||||
c.ChatRoomUsers = chatRoomUserMap
|
||||
c.Alias2Contack = aliasMap
|
||||
c.Remark2Contack = remarkMap
|
||||
c.NickName2Contack = nickNameMap
|
||||
}
|
||||
|
||||
func (c *Contact) loadChatRoom() {
|
||||
|
||||
chatRoomMap := make(map[string]*model.ChatRoom)
|
||||
rows, err := c.db.Query("SELECT ChatRoomName, Reserved2, RoomData FROM ChatRoom")
|
||||
if err != nil {
|
||||
log.Errorf("查询群聊失败: %v", err)
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
var chatRoom model.ChatRoomV3
|
||||
if err := rows.Scan(
|
||||
&chatRoom.ChatRoomName,
|
||||
&chatRoom.Reserved2,
|
||||
&chatRoom.RoomData,
|
||||
); err != nil {
|
||||
log.Printf("警告: 扫描群聊行失败: %v", err)
|
||||
continue
|
||||
}
|
||||
chatRoomMap[chatRoom.ChatRoomName] = chatRoom.Wrap()
|
||||
}
|
||||
rows.Close()
|
||||
c.ChatRoom = chatRoomMap
|
||||
}
|
||||
|
||||
func (c *Contact) loadSession() {
|
||||
|
||||
sessions := make([]*model.Session, 0)
|
||||
rows, err := c.db.Query("SELECT strUsrName, nOrder, strNickName, strContent, nTime FROM Session ORDER BY nOrder DESC")
|
||||
if err != nil {
|
||||
log.Errorf("查询群聊失败: %v", err)
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
var sessionV3 model.SessionV3
|
||||
if err := rows.Scan(
|
||||
&sessionV3.StrUsrName,
|
||||
&sessionV3.NOrder,
|
||||
&sessionV3.StrNickName,
|
||||
&sessionV3.StrContent,
|
||||
&sessionV3.NTime,
|
||||
); err != nil {
|
||||
log.Printf("警告: 扫描历史会话失败: %v", err)
|
||||
continue
|
||||
}
|
||||
session := sessionV3.Wrap()
|
||||
sessions = append(sessions, session)
|
||||
|
||||
}
|
||||
rows.Close()
|
||||
c.Sessions = sessions
|
||||
}
|
||||
|
||||
func (c *Contact) ListContact() ([]*model.Contact, error) {
|
||||
contacts := make([]*model.Contact, 0, len(c.Contact))
|
||||
for _, contact := range c.Contact {
|
||||
contacts = append(contacts, contact)
|
||||
}
|
||||
return contacts, nil
|
||||
}
|
||||
|
||||
func (c *Contact) ListChatRoom() ([]*model.ChatRoom, error) {
|
||||
chatRooms := make([]*model.ChatRoom, 0, len(c.ChatRoom))
|
||||
for _, chatRoom := range c.ChatRoom {
|
||||
chatRooms = append(chatRooms, chatRoom)
|
||||
}
|
||||
return chatRooms, nil
|
||||
}
|
||||
|
||||
func (c *Contact) GetContact(key string) *model.Contact {
|
||||
if contact, ok := c.Contact[key]; ok {
|
||||
return contact
|
||||
}
|
||||
if contact, ok := c.Alias2Contack[key]; ok {
|
||||
return contact
|
||||
}
|
||||
if contact, ok := c.Remark2Contack[key]; ok {
|
||||
return contact
|
||||
}
|
||||
if contact, ok := c.NickName2Contack[key]; ok {
|
||||
return contact
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Contact) GetChatRoom(name string) *model.ChatRoom {
|
||||
if chatRoom, ok := c.ChatRoom[name]; ok {
|
||||
return chatRoom
|
||||
}
|
||||
|
||||
if contact := c.GetContact(name); contact != nil {
|
||||
if chatRoom, ok := c.ChatRoom[contact.UserName]; ok {
|
||||
return chatRoom
|
||||
} else {
|
||||
// 被删除的群聊,在 ChatRoom 记录中没有了,但是能找到 Contact,做下 Mock
|
||||
return &model.ChatRoom{
|
||||
Name: contact.UserName,
|
||||
Remark: contact.Remark,
|
||||
NickName: contact.NickName,
|
||||
Users: make([]model.ChatRoomUser, 0),
|
||||
User2DisplayName: make(map[string]string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Contact) GetSession(limit int) []*model.Session {
|
||||
if limit <= 0 {
|
||||
limit = len(c.Sessions)
|
||||
}
|
||||
|
||||
if len(c.Sessions) < limit {
|
||||
limit = len(c.Sessions)
|
||||
}
|
||||
return c.Sessions[:limit]
|
||||
}
|
||||
|
||||
func (c *Contact) getFullContact(userName string) *model.Contact {
|
||||
if contact := c.GetContact(userName); contact != nil {
|
||||
return contact
|
||||
}
|
||||
if contact, ok := c.ChatRoomUsers[userName]; ok {
|
||||
return contact
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Contact) fillChatRoomInfo() {
|
||||
for i := range c.ChatRoom {
|
||||
if contact := c.GetContact(c.ChatRoom[i].Name); contact != nil {
|
||||
c.ChatRoom[i].Remark = contact.Remark
|
||||
c.ChatRoom[i].NickName = contact.NickName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Contact) MessageFillInfo(msg *model.Message) {
|
||||
talker := msg.Talker
|
||||
if msg.IsChatRoom {
|
||||
talker = msg.ChatRoomSender
|
||||
if chatRoom := c.GetChatRoom(msg.Talker); chatRoom != nil {
|
||||
msg.CharRoomName = chatRoom.DisplayName()
|
||||
if displayName, ok := chatRoom.User2DisplayName[talker]; ok {
|
||||
msg.DisplayName = displayName
|
||||
}
|
||||
}
|
||||
}
|
||||
if msg.DisplayName == "" && msg.IsSender != 1 {
|
||||
if contact := c.getFullContact(talker); contact != nil {
|
||||
msg.DisplayName = contact.DisplayName()
|
||||
}
|
||||
}
|
||||
}
|
||||
321
internal/wechatdb/message.go
Normal file
321
internal/wechatdb/message.go
Normal file
@@ -0,0 +1,321 @@
|
||||
package wechatdb
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sjzar/chatlog/pkg/model"
|
||||
"github.com/sjzar/chatlog/pkg/util"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
const (
|
||||
MessageFileV3 = "^MSG([0-9]?[0-9])?\\.db$"
|
||||
MessageFileV4 = "^messages_([0-9]?[0-9])+\\.db$"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
version int
|
||||
files []MsgDBInfo
|
||||
dbs map[string]*sql.DB
|
||||
}
|
||||
|
||||
type MsgDBInfo struct {
|
||||
FilePath string
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
TalkerMap map[string]int
|
||||
}
|
||||
|
||||
func NewMessage(path string, version int) (*Message, error) {
|
||||
m := &Message{
|
||||
version: version,
|
||||
files: make([]MsgDBInfo, 0),
|
||||
dbs: make(map[string]*sql.DB),
|
||||
}
|
||||
|
||||
// 查找所有 MSG[0-13].db 文件
|
||||
files, err := util.FindFilesWithPatterns(path, MessageFileV3, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查找数据库文件失败: %v", err)
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return nil, fmt.Errorf("未找到任何数据库文件: %s", path)
|
||||
}
|
||||
|
||||
// 处理每个数据库文件
|
||||
for _, filePath := range files {
|
||||
// 连接数据库
|
||||
db, err := sql.Open("sqlite3", filePath)
|
||||
if err != nil {
|
||||
log.Printf("警告: 连接数据库 %s 失败: %v", filePath, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取 DBInfo 表中的开始时间
|
||||
// 首先检查表结构
|
||||
var startTime time.Time
|
||||
|
||||
// 尝试从 DBInfo 表中查找 Start Time 对应的记录
|
||||
rows, err := db.Query("SELECT tableIndex, tableVersion, tableDesc FROM DBInfo")
|
||||
if err != nil {
|
||||
log.Printf("警告: 查询数据库 %s 的 DBInfo 表失败: %v", filePath, err)
|
||||
db.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var tableIndex int
|
||||
var tableVersion int64
|
||||
var tableDesc string
|
||||
|
||||
if err := rows.Scan(&tableIndex, &tableVersion, &tableDesc); err != nil {
|
||||
log.Printf("警告: 扫描 DBInfo 行失败: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 查找描述为 "Start Time" 的记录
|
||||
if strings.Contains(tableDesc, "Start Time") {
|
||||
startTime = time.Unix(tableVersion/1000, (tableVersion%1000)*1000000)
|
||||
break
|
||||
}
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
// 组织 TalkerMap
|
||||
talkerMap := make(map[string]int)
|
||||
rows, err = db.Query("SELECT UsrName FROM Name2ID")
|
||||
if err != nil {
|
||||
log.Printf("警告: 查询数据库 %s 的 Name2ID 表失败: %v", filePath, err)
|
||||
db.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
i := 1
|
||||
for rows.Next() {
|
||||
var userName string
|
||||
if err := rows.Scan(&userName); err != nil {
|
||||
log.Printf("警告: 扫描 Name2ID 行失败: %v", err)
|
||||
continue
|
||||
}
|
||||
talkerMap[userName] = i
|
||||
i++
|
||||
}
|
||||
|
||||
// 保存数据库信息
|
||||
m.files = append(m.files, MsgDBInfo{
|
||||
FilePath: filePath,
|
||||
StartTime: startTime,
|
||||
TalkerMap: talkerMap,
|
||||
})
|
||||
|
||||
// 保存数据库连接
|
||||
m.dbs[filePath] = db
|
||||
}
|
||||
|
||||
// 按照 StartTime 排序数据库文件
|
||||
sort.Slice(m.files, func(i, j int) bool {
|
||||
return m.files[i].StartTime.Before(m.files[j].StartTime)
|
||||
})
|
||||
|
||||
for i := range m.files {
|
||||
if i == len(m.files)-1 {
|
||||
m.files[i].EndTime = time.Now()
|
||||
} else {
|
||||
m.files[i].EndTime = m.files[i+1].StartTime
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// GetMessages 根据时间段和 talker 查询聊天记录
|
||||
func (m *Message) GetMessages(startTime, endTime time.Time, talker string, limit, offset int) ([]*model.Message, error) {
|
||||
// 找到时间范围内的数据库文件
|
||||
dbInfos := m.getDBInfosForTimeRange(startTime, endTime)
|
||||
if len(dbInfos) == 0 {
|
||||
return nil, fmt.Errorf("未找到时间范围 %v 到 %v 内的数据库文件", startTime, endTime)
|
||||
}
|
||||
|
||||
if len(dbInfos) == 1 {
|
||||
// LIMIT 和 OFFSET 逻辑在单文件情况下可以直接在 SQL 里处理
|
||||
return m.getMessagesSingleFile(dbInfos[0], startTime, endTime, talker, limit, offset)
|
||||
}
|
||||
|
||||
// 从每个相关数据库中查询消息
|
||||
totalMessages := []*model.Message{}
|
||||
|
||||
for _, dbInfo := range dbInfos {
|
||||
db, ok := m.dbs[dbInfo.FilePath]
|
||||
if !ok {
|
||||
log.Printf("警告: 数据库 %s 未打开", dbInfo.FilePath)
|
||||
continue
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
// 使用 Sequence 查询,有索引
|
||||
conditions := []string{"Sequence >= ? AND Sequence <= ?"}
|
||||
args := []interface{}{startTime.Unix() * 1000, endTime.Unix() * 1000}
|
||||
|
||||
if len(talker) > 0 {
|
||||
talkerID, ok := dbInfo.TalkerMap[talker]
|
||||
if ok {
|
||||
conditions = append(conditions, "TalkerId = ?")
|
||||
args = append(args, talkerID)
|
||||
} else {
|
||||
conditions = append(conditions, "StrTalker = ?")
|
||||
args = append(args, talker)
|
||||
}
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT Sequence, CreateTime, TalkerId, StrTalker, IsSender,
|
||||
Type, SubType, StrContent, CompressContent, BytesExtra
|
||||
FROM MSG
|
||||
WHERE %s
|
||||
ORDER BY Sequence ASC
|
||||
`, strings.Join(conditions, " AND "))
|
||||
|
||||
// 执行查询
|
||||
rows, err := db.Query(query, args...)
|
||||
if err != nil {
|
||||
log.Printf("警告: 查询数据库 %s 失败: %v", dbInfo.FilePath, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 处理查询结果
|
||||
for rows.Next() {
|
||||
var msg model.MessageV3
|
||||
var compressContent []byte
|
||||
var bytesExtra []byte
|
||||
|
||||
err := rows.Scan(
|
||||
&msg.Sequence,
|
||||
&msg.CreateTime,
|
||||
&msg.TalkerID,
|
||||
&msg.StrTalker,
|
||||
&msg.IsSender,
|
||||
&msg.Type,
|
||||
&msg.SubType,
|
||||
&msg.StrContent,
|
||||
&compressContent,
|
||||
&bytesExtra,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("警告: 扫描消息行失败: %v", err)
|
||||
continue
|
||||
}
|
||||
msg.CompressContent = compressContent
|
||||
msg.BytesExtra = bytesExtra
|
||||
|
||||
totalMessages = append(totalMessages, msg.Wrap())
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if limit+offset > 0 && len(totalMessages) >= limit+offset {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 对所有消息按时间排序
|
||||
sort.Slice(totalMessages, func(i, j int) bool {
|
||||
return totalMessages[i].Sequence < totalMessages[j].Sequence
|
||||
})
|
||||
|
||||
// FIXME limit 和 offset 逻辑,在多文件边界条件下不好处理,直接查询全量数据后在进程里处理
|
||||
if limit > 0 {
|
||||
if offset >= len(totalMessages) {
|
||||
return []*model.Message{}, nil
|
||||
}
|
||||
end := offset + limit
|
||||
if end > len(totalMessages) || limit == 0 {
|
||||
end = len(totalMessages)
|
||||
}
|
||||
return totalMessages[offset:end], nil
|
||||
}
|
||||
|
||||
return totalMessages, nil
|
||||
|
||||
}
|
||||
|
||||
func (m *Message) getMessagesSingleFile(dbInfo MsgDBInfo, startTime, endTime time.Time, talker string, limit, offset int) ([]*model.Message, error) {
|
||||
// 构建查询条件
|
||||
// 使用 Sequence 查询,有索引
|
||||
conditions := []string{"Sequence >= ? AND Sequence <= ?"}
|
||||
args := []interface{}{startTime.Unix() * 1000, endTime.Unix() * 1000}
|
||||
if len(talker) > 0 {
|
||||
// TalkerId 有索引,优先使用
|
||||
talkerID, ok := dbInfo.TalkerMap[talker]
|
||||
if ok {
|
||||
conditions = append(conditions, "TalkerId = ?")
|
||||
args = append(args, talkerID)
|
||||
} else {
|
||||
conditions = append(conditions, "StrTalker = ?")
|
||||
args = append(args, talker)
|
||||
}
|
||||
}
|
||||
query := fmt.Sprintf(`
|
||||
SELECT Sequence, CreateTime, TalkerId, StrTalker, IsSender,
|
||||
Type, SubType, StrContent, CompressContent, BytesExtra
|
||||
FROM MSG
|
||||
WHERE %s
|
||||
ORDER BY Sequence ASC
|
||||
`, strings.Join(conditions, " AND "))
|
||||
|
||||
if limit > 0 {
|
||||
query += fmt.Sprintf(" LIMIT %d", limit)
|
||||
|
||||
if offset > 0 {
|
||||
query += fmt.Sprintf(" OFFSET %d", offset)
|
||||
}
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
rows, err := m.dbs[dbInfo.FilePath].Query(query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询数据库 %s 失败: %v", dbInfo.FilePath, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
// 处理查询结果
|
||||
totalMessages := []*model.Message{}
|
||||
for rows.Next() {
|
||||
var msg model.MessageV3
|
||||
var compressContent []byte
|
||||
var bytesExtra []byte
|
||||
err := rows.Scan(
|
||||
&msg.Sequence,
|
||||
&msg.CreateTime,
|
||||
&msg.TalkerID,
|
||||
&msg.StrTalker,
|
||||
&msg.IsSender,
|
||||
&msg.Type,
|
||||
&msg.SubType,
|
||||
&msg.StrContent,
|
||||
&compressContent,
|
||||
&bytesExtra,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("扫描消息行失败: %v", err)
|
||||
}
|
||||
msg.CompressContent = compressContent
|
||||
msg.BytesExtra = bytesExtra
|
||||
totalMessages = append(totalMessages, msg.Wrap())
|
||||
}
|
||||
return totalMessages, nil
|
||||
}
|
||||
|
||||
func (m *Message) getDBInfosForTimeRange(startTime, endTime time.Time) []MsgDBInfo {
|
||||
var dbs []MsgDBInfo
|
||||
for _, info := range m.files {
|
||||
if info.StartTime.Before(endTime) && info.EndTime.After(startTime) {
|
||||
dbs = append(dbs, info)
|
||||
}
|
||||
}
|
||||
return dbs
|
||||
}
|
||||
117
internal/wechatdb/wechatdb.go
Normal file
117
internal/wechatdb/wechatdb.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package wechatdb
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/sjzar/chatlog/pkg/model"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
BasePath string
|
||||
Version int
|
||||
|
||||
contact *Contact
|
||||
message *Message
|
||||
}
|
||||
|
||||
func New(path string, version int) (*DB, error) {
|
||||
w := &DB{
|
||||
BasePath: path,
|
||||
Version: version,
|
||||
}
|
||||
|
||||
// 初始化,加载数据库文件信息
|
||||
if err := w.Initialize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *DB) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *DB) Initialize() error {
|
||||
|
||||
var err error
|
||||
w.message, err = NewMessage(w.BasePath, w.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.contact, err = NewContact(w.BasePath, w.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *DB) GetMessages(start, end time.Time, talker string, limit, offset int) ([]*model.Message, error) {
|
||||
|
||||
if talker != "" {
|
||||
if contact := w.contact.GetContact(talker); contact != nil {
|
||||
talker = contact.UserName
|
||||
}
|
||||
}
|
||||
|
||||
messages, err := w.message.GetMessages(start, end, talker, limit, offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range messages {
|
||||
w.contact.MessageFillInfo(messages[i])
|
||||
}
|
||||
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
type ListContactResp struct {
|
||||
Items []*model.Contact `json:"items"`
|
||||
}
|
||||
|
||||
func (w *DB) ListContact() (*ListContactResp, error) {
|
||||
list, err := w.contact.ListContact()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ListContactResp{
|
||||
Items: list,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *DB) GetContact(userName string) *model.Contact {
|
||||
return w.contact.GetContact(userName)
|
||||
}
|
||||
|
||||
type ListChatRoomResp struct {
|
||||
Items []*model.ChatRoom `json:"items"`
|
||||
}
|
||||
|
||||
func (w *DB) ListChatRoom() (*ListChatRoomResp, error) {
|
||||
list, err := w.contact.ListChatRoom()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ListChatRoomResp{
|
||||
Items: list,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *DB) GetChatRoom(userName string) *model.ChatRoom {
|
||||
return w.contact.GetChatRoom(userName)
|
||||
}
|
||||
|
||||
type GetSessionResp struct {
|
||||
Items []*model.Session `json:"items"`
|
||||
}
|
||||
|
||||
func (w *DB) GetSession(limit int) (*GetSessionResp, error) {
|
||||
sessions := w.contact.GetSession(limit)
|
||||
return &GetSessionResp{
|
||||
Items: sessions,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user