fix(wechatdb): hardlink v4 & init db (#216)
This commit is contained in:
@@ -307,10 +307,9 @@ func (s *Service) handleMedia(c *gin.Context, _type string) {
|
||||
|
||||
var _err error
|
||||
for _, k := range keys {
|
||||
if len(k) != 32 {
|
||||
absolutePath := filepath.Join(s.conf.GetDataDir(), k)
|
||||
if _, err := os.Stat(absolutePath); err == nil {
|
||||
c.Redirect(http.StatusFound, "/data/"+k)
|
||||
if strings.Contains(k, "/") {
|
||||
if absolutePath, err := s.findPath(_type, k); err == nil {
|
||||
c.Redirect(http.StatusFound, "/data/"+absolutePath)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -339,6 +338,28 @@ func (s *Service) handleMedia(c *gin.Context, _type string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) findPath(_type string, key string) (string, error) {
|
||||
absolutePath := filepath.Join(s.conf.GetDataDir(), key)
|
||||
if _, err := os.Stat(absolutePath); err == nil {
|
||||
return key, nil
|
||||
}
|
||||
switch _type {
|
||||
case "image":
|
||||
for _, suffix := range []string{"_h.dat", ".dat", "_t.dat"} {
|
||||
if _, err := os.Stat(absolutePath + suffix); err == nil {
|
||||
return key + suffix, nil
|
||||
}
|
||||
}
|
||||
case "video":
|
||||
for _, suffix := range []string{".mp4", "_thumb.jpg"} {
|
||||
if _, err := os.Stat(absolutePath + suffix); err == nil {
|
||||
return key + suffix, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", errors.ErrMediaNotFound
|
||||
}
|
||||
|
||||
func (s *Service) handleMediaData(c *gin.Context) {
|
||||
relativePath := filepath.Clean(c.Param("path"))
|
||||
|
||||
|
||||
@@ -118,3 +118,7 @@ func Err(c *gin.Context, err error) {
|
||||
|
||||
c.JSON(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
func Is(err, target error) bool {
|
||||
return errors.Is(err, target)
|
||||
}
|
||||
|
||||
@@ -245,14 +245,9 @@ func (m *Message) PlainTextContent() string {
|
||||
keylist = append(keylist, md5)
|
||||
}
|
||||
}
|
||||
if m.Contents["imgfile"] != nil {
|
||||
if imgfile, ok := m.Contents["imgfile"].(string); ok {
|
||||
keylist = append(keylist, imgfile)
|
||||
}
|
||||
}
|
||||
if m.Contents["thumb"] != nil {
|
||||
if thumb, ok := m.Contents["thumb"].(string); ok {
|
||||
keylist = append(keylist, thumb)
|
||||
if m.Contents["path"] != nil {
|
||||
if path, ok := m.Contents["path"].(string); ok {
|
||||
keylist = append(keylist, path)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("", m.Contents["host"], strings.Join(keylist, ","))
|
||||
@@ -275,14 +270,9 @@ func (m *Message) PlainTextContent() string {
|
||||
keylist = append(keylist, rawmd5)
|
||||
}
|
||||
}
|
||||
if m.Contents["videofile"] != nil {
|
||||
if videofile, ok := m.Contents["videofile"].(string); ok {
|
||||
keylist = append(keylist, videofile)
|
||||
}
|
||||
}
|
||||
if m.Contents["thumb"] != nil {
|
||||
if thumb, ok := m.Contents["thumb"].(string); ok {
|
||||
keylist = append(keylist, thumb)
|
||||
if m.Contents["path"] != nil {
|
||||
if path, ok := m.Contents["path"].(string); ok {
|
||||
keylist = append(keylist, path)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("", m.Contents["host"], strings.Join(keylist, ","))
|
||||
|
||||
@@ -90,12 +90,10 @@ func (m *MessageV4) Wrap(talker string) *Message {
|
||||
if _m.Type == 3 && packedInfo.Image != nil {
|
||||
_talkerMd5Bytes := md5.Sum([]byte(talker))
|
||||
talkerMd5 := hex.EncodeToString(_talkerMd5Bytes[:])
|
||||
_m.Contents["imgfile"] = filepath.Join("msg", "attach", talkerMd5, _m.Time.Format("2006-01"), "Img", fmt.Sprintf("%s.dat", packedInfo.Image.Md5))
|
||||
_m.Contents["thumb"] = filepath.Join("msg", "attach", talkerMd5, _m.Time.Format("2006-01"), "Img", fmt.Sprintf("%s_t.dat", packedInfo.Image.Md5))
|
||||
_m.Contents["path"] = filepath.Join("msg", "attach", talkerMd5, _m.Time.Format("2006-01"), "Img", packedInfo.Image.Md5)
|
||||
}
|
||||
if _m.Type == 43 && packedInfo.Video != nil {
|
||||
_m.Contents["videofile"] = filepath.Join("msg", "video", _m.Time.Format("2006-01"), fmt.Sprintf("%s.mp4", packedInfo.Video.Md5))
|
||||
_m.Contents["thumb"] = filepath.Join("msg", "video", _m.Time.Format("2006-01"), fmt.Sprintf("%s_thumb.jpg", packedInfo.Video.Md5))
|
||||
_m.Contents["path"] = filepath.Join("msg", "video", _m.Time.Format("2006-01"), packedInfo.Video.Md5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +162,10 @@ func (ds *DataSource) initMessageDbs() error {
|
||||
infos[i].EndTime = infos[i+1].StartTime
|
||||
}
|
||||
}
|
||||
if len(ds.messageInfos) > 0 && len(infos) < len(ds.messageInfos) {
|
||||
log.Warn().Msgf("message db count decreased from %d to %d, skip init", len(ds.messageInfos), len(infos))
|
||||
return nil
|
||||
}
|
||||
ds.messageInfos = infos
|
||||
return nil
|
||||
}
|
||||
@@ -603,10 +607,20 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
switch _type {
|
||||
case "image":
|
||||
table = "image_hardlink_info_v3"
|
||||
// 4.1.0 版本开始使用 v4 表
|
||||
if !ds.IsExist(Media, table) {
|
||||
table = "image_hardlink_info_v4"
|
||||
}
|
||||
case "video":
|
||||
table = "video_hardlink_info_v3"
|
||||
if !ds.IsExist(Media, table) {
|
||||
table = "video_hardlink_info_v4"
|
||||
}
|
||||
case "file":
|
||||
table = "file_hardlink_info_v3"
|
||||
if !ds.IsExist(Media, table) {
|
||||
table = "file_hardlink_info_v4"
|
||||
}
|
||||
case "voice":
|
||||
return ds.GetVoice(ctx, key)
|
||||
default:
|
||||
@@ -659,8 +673,8 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
mediaV4.Type = _type
|
||||
media = mediaV4.Wrap()
|
||||
|
||||
// 跳过缩略图
|
||||
if _type == "image" && !strings.Contains(media.Name, "_t") {
|
||||
// 优先返回高清图
|
||||
if _type == "image" && strings.HasSuffix(mediaV4.Name, "_h.dat") {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -672,6 +686,22 @@ func (ds *DataSource) GetMedia(ctx context.Context, _type string, key string) (*
|
||||
return media, nil
|
||||
}
|
||||
|
||||
func (ds *DataSource) IsExist(_db string, table string) bool {
|
||||
db, err := ds.dbm.GetDB(_db)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
var tableName string
|
||||
query := "SELECT name FROM sqlite_master WHERE type='table' AND name=?;"
|
||||
if err = db.QueryRow(query, table).Scan(&tableName); err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (ds *DataSource) GetVoice(ctx context.Context, key string) (*model.Media, error) {
|
||||
if key == "" {
|
||||
return nil, errors.ErrKeyEmpty
|
||||
|
||||
@@ -56,7 +56,7 @@ var Groups = []*dbm.Group{
|
||||
},
|
||||
{
|
||||
Name: Voice,
|
||||
Pattern: `^MediaMSG([0-9])?\.db$`,
|
||||
Pattern: `^MediaMSG([0-9]?[0-9])?\.db$`,
|
||||
BlackList: []string{},
|
||||
},
|
||||
}
|
||||
@@ -207,6 +207,10 @@ func (ds *DataSource) initMessageDbs() error {
|
||||
infos[i].EndTime = infos[i+1].StartTime
|
||||
}
|
||||
}
|
||||
if len(ds.messageInfos) > 0 && len(infos) < len(ds.messageInfos) {
|
||||
log.Warn().Msgf("message db count decreased from %d to %d, skip init", len(ds.messageInfos), len(infos))
|
||||
return nil
|
||||
}
|
||||
ds.messageInfos = infos
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,17 +5,14 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
)
|
||||
|
||||
// initChatRoomCache 初始化群聊缓存
|
||||
func (r *Repository) initChatRoomCache(ctx context.Context) error {
|
||||
// 加载所有群聊到缓存
|
||||
chatRooms, err := r.ds.GetChatRooms(ctx, "", 0, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chatRoomMap := make(map[string]*model.ChatRoom)
|
||||
remarkToChatRoom := make(map[string][]*model.ChatRoom)
|
||||
@@ -24,6 +21,13 @@ func (r *Repository) initChatRoomCache(ctx context.Context) error {
|
||||
chatRoomRemark := make([]string, 0)
|
||||
chatRoomNickName := make([]string, 0)
|
||||
|
||||
// 加载所有群聊到缓存
|
||||
// 暂时忽略获取不到群聊的错误
|
||||
chatRooms, err := r.ds.GetChatRooms(ctx, "", 0, 0)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to load chat rooms")
|
||||
}
|
||||
|
||||
for _, chatRoom := range chatRooms {
|
||||
// 补充群聊信息(从联系人中获取 Remark 和 NickName)
|
||||
r.enrichChatRoom(chatRoom)
|
||||
|
||||
@@ -5,17 +5,14 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/errors"
|
||||
"github.com/sjzar/chatlog/internal/model"
|
||||
)
|
||||
|
||||
// initContactCache 初始化联系人缓存
|
||||
func (r *Repository) initContactCache(ctx context.Context) error {
|
||||
// 加载所有联系人到缓存
|
||||
contacts, err := r.ds.GetContacts(ctx, "", 0, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contactMap := make(map[string]*model.Contact)
|
||||
aliasMap := make(map[string][]*model.Contact)
|
||||
@@ -28,6 +25,13 @@ func (r *Repository) initContactCache(ctx context.Context) error {
|
||||
remarkList := make([]string, 0)
|
||||
nickNameList := make([]string, 0)
|
||||
|
||||
// 加载所有联系人到缓存
|
||||
// 暂时忽略获取不到联系人的错误
|
||||
contacts, err := r.ds.GetContacts(ctx, "", 0, 0)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to load contacts")
|
||||
}
|
||||
|
||||
for _, contact := range contacts {
|
||||
contactMap[contact.UserName] = contact
|
||||
contactList = append(contactList, contact.UserName)
|
||||
|
||||
Reference in New Issue
Block a user