Replace websocket flow with SSE support in backend.

Update handlers, services, router, and data conversion logic to support server-sent events and related message pipeline changes.

Made-with: Cursor
This commit is contained in:
2026-03-10 12:58:23 +08:00
parent 4c0177149a
commit 86ef150fec
19 changed files with 689 additions and 1719 deletions

View File

@@ -9,8 +9,8 @@ import (
"carrot_bbs/internal/cache"
"carrot_bbs/internal/model"
"carrot_bbs/internal/pkg/sse"
"carrot_bbs/internal/pkg/utils"
"carrot_bbs/internal/pkg/websocket"
"carrot_bbs/internal/repository"
"gorm.io/gorm"
@@ -18,7 +18,7 @@ import (
// 缓存TTL常量
const (
GroupMembersTTL = 120 * time.Second // 群组成员缓存120秒
GroupMembersTTL = 120 * time.Second // 群组成员缓存120秒
GroupMembersNullTTL = 5 * time.Second
GroupCacheJitter = 0.1
)
@@ -99,12 +99,12 @@ type groupService struct {
messageRepo *repository.MessageRepository
requestRepo repository.GroupJoinRequestRepository
notifyRepo *repository.SystemNotificationRepository
wsManager *websocket.WebSocketManager
sseHub *sse.Hub
cache cache.Cache
}
// NewGroupService 创建群组服务
func NewGroupService(db *gorm.DB, groupRepo repository.GroupRepository, userRepo *repository.UserRepository, messageRepo *repository.MessageRepository, wsManager *websocket.WebSocketManager) GroupService {
func NewGroupService(db *gorm.DB, groupRepo repository.GroupRepository, userRepo *repository.UserRepository, messageRepo *repository.MessageRepository, sseHub *sse.Hub) GroupService {
return &groupService{
db: db,
groupRepo: groupRepo,
@@ -112,11 +112,39 @@ func NewGroupService(db *gorm.DB, groupRepo repository.GroupRepository, userRepo
messageRepo: messageRepo,
requestRepo: repository.NewGroupJoinRequestRepository(db),
notifyRepo: repository.NewSystemNotificationRepository(db),
wsManager: wsManager,
sseHub: sseHub,
cache: cache.GetCache(),
}
}
type groupNoticeData struct {
UserID string `json:"user_id,omitempty"`
Username string `json:"username,omitempty"`
OperatorID string `json:"operator_id,omitempty"`
}
type groupNoticeMessage struct {
NoticeType string `json:"notice_type"`
GroupID string `json:"group_id"`
Data groupNoticeData `json:"data"`
Timestamp int64 `json:"timestamp"`
MessageID string `json:"message_id,omitempty"`
Seq int64 `json:"seq,omitempty"`
}
func (s *groupService) publishGroupNotice(groupID string, notice groupNoticeMessage) {
members, _, err := s.groupRepo.GetMembers(groupID, 1, 1000)
if err != nil {
log.Printf("[groupService] 获取群成员失败: groupID=%s, err=%v", groupID, err)
return
}
if s.sseHub != nil {
for _, m := range members {
s.sseHub.PublishToUser(m.UserID, "group_notice", notice)
}
}
}
// ==================== 群组管理 ====================
// CreateGroup 创建群组
@@ -422,14 +450,10 @@ func (s *groupService) broadcastMemberJoinNotice(groupID string, targetUserID st
}
}
if s.wsManager == nil {
return
}
noticeMsg := websocket.GroupNoticeMessage{
noticeMsg := groupNoticeMessage{
NoticeType: "member_join",
GroupID: groupID,
Data: websocket.GroupNoticeData{
Data: groupNoticeData{
UserID: targetUserID,
Username: targetUserName,
OperatorID: operatorID,
@@ -441,17 +465,7 @@ func (s *groupService) broadcastMemberJoinNotice(groupID string, targetUserID st
noticeMsg.Seq = savedMessage.Seq
}
wsMsg := websocket.CreateWSMessage(websocket.MessageTypeGroupNotice, noticeMsg)
members, _, err := s.groupRepo.GetMembers(groupID, 1, 1000)
if err != nil {
log.Printf("[broadcastMemberJoinNotice] 获取群成员失败: groupID=%s, err=%v", groupID, err)
return
}
for _, m := range members {
if s.wsManager.IsUserOnline(m.UserID) {
s.wsManager.SendToUser(m.UserID, wsMsg)
}
}
s.publishGroupNotice(groupID, noticeMsg)
}
func (s *groupService) addMemberToGroupAndConversation(group *model.Group, userID string, operatorID string) error {
@@ -1282,46 +1296,20 @@ func (s *groupService) MuteMember(userID string, groupID string, targetUserID st
}
}
// 发送WebSocket通知给群成员
if s.wsManager != nil {
log.Printf("[MuteMember] 准备发送禁言通知: groupID=%s, targetUserID=%s, noticeType=%s, operatorID=%s", groupID, targetUserID, noticeType, userID)
// 构建通知消息,包含保存的消息信息
noticeMsg := websocket.GroupNoticeMessage{
NoticeType: noticeType,
GroupID: groupID,
Data: websocket.GroupNoticeData{
UserID: targetUserID,
OperatorID: userID,
},
Timestamp: time.Now().UnixMilli(),
}
// 如果消息已保存添加消息ID和seq
if savedMessage != nil {
noticeMsg.MessageID = savedMessage.ID
noticeMsg.Seq = savedMessage.Seq
}
wsMsg := websocket.CreateWSMessage(websocket.MessageTypeGroupNotice, noticeMsg)
log.Printf("[MuteMember] 创建的WebSocket消息: Type=%s, Data=%+v", wsMsg.Type, wsMsg.Data)
// 获取所有群成员并发送通知
members, _, err := s.groupRepo.GetMembers(groupID, 1, 1000)
if err == nil {
log.Printf("[MuteMember] 获取到群成员数量: %d", len(members))
for _, m := range members {
isOnline := s.wsManager.IsUserOnline(m.UserID)
log.Printf("[MuteMember] 成员 %s 在线状态: %v", m.UserID, isOnline)
if isOnline {
s.wsManager.SendToUser(m.UserID, wsMsg)
log.Printf("[MuteMember] 已发送通知给成员: %s", m.UserID)
}
}
} else {
log.Printf("[MuteMember] 获取群成员失败: %v", err)
}
noticeMsg := groupNoticeMessage{
NoticeType: noticeType,
GroupID: groupID,
Data: groupNoticeData{
UserID: targetUserID,
OperatorID: userID,
},
Timestamp: time.Now().UnixMilli(),
}
if savedMessage != nil {
noticeMsg.MessageID = savedMessage.ID
noticeMsg.Seq = savedMessage.Seq
}
s.publishGroupNotice(groupID, noticeMsg)
// 失效群组成员缓存
cache.InvalidateGroupMembers(s.cache, groupID)