refactor: introduce Wire dependency injection and interface-based architecture
- Add Google Wire for compile-time dependency injection - Replace concrete service types with interfaces across handlers - Remove global state (DB, cache) in favor of constructor injection - Split monolithic files into focused modules: - config: separate files for each config domain - dto: converters split by domain (user, post, message, group) - cache: separate metrics.go and redis_cache.go - Introduce unified apperrors package with string-based error codes - Add transaction support with context-aware repository methods - Upgrade golang.org/x/crypto from 0.17.0 to 0.26.0
This commit is contained in:
178
internal/dto/message_converter.go
Normal file
178
internal/dto/message_converter.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"carrot_bbs/internal/model"
|
||||
)
|
||||
|
||||
// ==================== Message 转换 ====================
|
||||
|
||||
// ConvertMessageToResponse 将Message转换为MessageResponse
|
||||
func ConvertMessageToResponse(message *model.Message) *MessageResponse {
|
||||
if message == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 直接使用 segments,不需要解析
|
||||
segments := make(model.MessageSegments, len(message.Segments))
|
||||
for i, seg := range message.Segments {
|
||||
segments[i] = model.MessageSegment{
|
||||
Type: seg.Type,
|
||||
Data: seg.Data,
|
||||
}
|
||||
}
|
||||
|
||||
return &MessageResponse{
|
||||
ID: message.ID,
|
||||
ConversationID: message.ConversationID,
|
||||
SenderID: message.SenderID,
|
||||
Seq: message.Seq,
|
||||
Segments: segments,
|
||||
ReplyToID: message.ReplyToID,
|
||||
Status: string(message.Status),
|
||||
Category: string(message.Category),
|
||||
CreatedAt: FormatTime(message.CreatedAt),
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertConversationToResponse 将Conversation转换为ConversationResponse
|
||||
// participants: 会话参与者列表(用户信息)
|
||||
// unreadCount: 当前用户的未读消息数
|
||||
// lastMessage: 最后一条消息
|
||||
func ConvertConversationToResponse(conv *model.Conversation, participants []*model.User, unreadCount int, lastMessage *model.Message, isPinned bool) *ConversationResponse {
|
||||
if conv == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var participantResponses []*UserResponse
|
||||
for _, p := range participants {
|
||||
participantResponses = append(participantResponses, ConvertUserToResponse(p))
|
||||
}
|
||||
|
||||
// 转换群组信息
|
||||
var groupResponse *GroupResponse
|
||||
if conv.Group != nil {
|
||||
groupResponse = GroupToResponse(conv.Group)
|
||||
}
|
||||
|
||||
return &ConversationResponse{
|
||||
ID: conv.ID,
|
||||
Type: string(conv.Type),
|
||||
IsPinned: isPinned,
|
||||
Group: groupResponse,
|
||||
LastSeq: conv.LastSeq,
|
||||
LastMessage: ConvertMessageToResponse(lastMessage),
|
||||
LastMessageAt: FormatTimePointer(conv.LastMsgTime),
|
||||
UnreadCount: unreadCount,
|
||||
Participants: participantResponses,
|
||||
CreatedAt: FormatTime(conv.CreatedAt),
|
||||
UpdatedAt: FormatTime(conv.UpdatedAt),
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertConversationToDetailResponse 将Conversation转换为ConversationDetailResponse
|
||||
func ConvertConversationToDetailResponse(conv *model.Conversation, participants []*model.User, unreadCount int64, lastMessage *model.Message, myLastReadSeq int64, otherLastReadSeq int64, isPinned bool) *ConversationDetailResponse {
|
||||
if conv == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var participantResponses []*UserResponse
|
||||
for _, p := range participants {
|
||||
participantResponses = append(participantResponses, ConvertUserToResponse(p))
|
||||
}
|
||||
|
||||
return &ConversationDetailResponse{
|
||||
ID: conv.ID,
|
||||
Type: string(conv.Type),
|
||||
IsPinned: isPinned,
|
||||
LastSeq: conv.LastSeq,
|
||||
LastMessage: ConvertMessageToResponse(lastMessage),
|
||||
LastMessageAt: FormatTimePointer(conv.LastMsgTime),
|
||||
UnreadCount: unreadCount,
|
||||
Participants: participantResponses,
|
||||
MyLastReadSeq: myLastReadSeq,
|
||||
OtherLastReadSeq: otherLastReadSeq,
|
||||
CreatedAt: FormatTime(conv.CreatedAt),
|
||||
UpdatedAt: FormatTime(conv.UpdatedAt),
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertMessagesToResponse 将Message列表转换为响应列表
|
||||
func ConvertMessagesToResponse(messages []*model.Message) []*MessageResponse {
|
||||
result := make([]*MessageResponse, 0, len(messages))
|
||||
for _, msg := range messages {
|
||||
result = append(result, ConvertMessageToResponse(msg))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ConvertConversationsToResponse 将Conversation列表转换为响应列表
|
||||
func ConvertConversationsToResponse(convs []*model.Conversation) []*ConversationResponse {
|
||||
result := make([]*ConversationResponse, 0, len(convs))
|
||||
for _, conv := range convs {
|
||||
result = append(result, ConvertConversationToResponse(conv, nil, 0, nil, false))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ==================== PushRecord 转换 ====================
|
||||
|
||||
// PushRecordToResponse 将PushRecord转换为PushRecordResponse
|
||||
func PushRecordToResponse(record *model.PushRecord) *PushRecordResponse {
|
||||
if record == nil {
|
||||
return nil
|
||||
}
|
||||
resp := &PushRecordResponse{
|
||||
ID: record.ID,
|
||||
MessageID: record.MessageID,
|
||||
PushChannel: string(record.PushChannel),
|
||||
PushStatus: string(record.PushStatus),
|
||||
RetryCount: record.RetryCount,
|
||||
CreatedAt: record.CreatedAt,
|
||||
}
|
||||
if record.PushedAt != nil {
|
||||
resp.PushedAt = *record.PushedAt
|
||||
}
|
||||
if record.DeliveredAt != nil {
|
||||
resp.DeliveredAt = *record.DeliveredAt
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// PushRecordsToResponse 将PushRecord列表转换为响应列表
|
||||
func PushRecordsToResponse(records []*model.PushRecord) []*PushRecordResponse {
|
||||
result := make([]*PushRecordResponse, 0, len(records))
|
||||
for _, record := range records {
|
||||
result = append(result, PushRecordToResponse(record))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ==================== DeviceToken 转换 ====================
|
||||
|
||||
// DeviceTokenToResponse 将DeviceToken转换为DeviceTokenResponse
|
||||
func DeviceTokenToResponse(token *model.DeviceToken) *DeviceTokenResponse {
|
||||
if token == nil {
|
||||
return nil
|
||||
}
|
||||
resp := &DeviceTokenResponse{
|
||||
ID: token.ID,
|
||||
DeviceID: token.DeviceID,
|
||||
DeviceType: string(token.DeviceType),
|
||||
IsActive: token.IsActive,
|
||||
DeviceName: token.DeviceName,
|
||||
CreatedAt: token.CreatedAt,
|
||||
}
|
||||
if token.LastUsedAt != nil {
|
||||
resp.LastUsedAt = *token.LastUsedAt
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// DeviceTokensToResponse 将DeviceToken列表转换为响应列表
|
||||
func DeviceTokensToResponse(tokens []*model.DeviceToken) []*DeviceTokenResponse {
|
||||
result := make([]*DeviceTokenResponse, 0, len(tokens))
|
||||
for _, token := range tokens {
|
||||
result = append(result, DeviceTokenToResponse(token))
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user