fix: 修复构建配置和运行时错误处理

This commit is contained in:
leonincs
2026-05-20 16:34:46 +08:00
parent 732e284369
commit 9c00e06b1f
18 changed files with 234 additions and 57 deletions

View File

@@ -6,9 +6,10 @@ import (
"errors"
"feedsystem_video_go/internal/middleware/rabbitmq"
"feedsystem_video_go/internal/video"
amqp "github.com/rabbitmq/amqp091-go"
"log"
"time"
amqp "github.com/rabbitmq/amqp091-go"
)
type LikeWorker struct {

View File

@@ -42,6 +42,9 @@ func (w *NotificationWorker) Run(ctx context.Context) error {
if w == nil || w.ch == nil || w.db == nil {
return errors.New("notification worker is not initialized")
}
if w.queue == "" {
return errors.New("queue is required")
}
if err := w.db.WithContext(ctx).AutoMigrate(&Notification{}); err != nil {
return err
}
@@ -96,10 +99,12 @@ func (w *NotificationWorker) process(ctx context.Context, d amqp.Delivery) error
return nil
}
var authorID uint
w.db.WithContext(ctx).Model(&struct {
if err := w.db.WithContext(ctx).Model(&struct {
ID uint
AuthorID uint
}{}).Table("videos").Where("id = ?", evt.VideoID).Select("author_id").Scan(&authorID)
}{}).Table("videos").Where("id = ?", evt.VideoID).Select("author_id").Scan(&authorID).Error; err != nil {
return err
}
if authorID == 0 || authorID == evt.UserID {
return nil
}
@@ -114,10 +119,12 @@ func (w *NotificationWorker) process(ctx context.Context, d amqp.Delivery) error
return nil
}
var authorID uint
w.db.WithContext(ctx).Model(&struct {
if err := w.db.WithContext(ctx).Model(&struct {
ID uint
AuthorID uint
}{}).Table("videos").Where("id = ?", evt.VideoID).Select("author_id").Scan(&authorID)
}{}).Table("videos").Where("id = ?", evt.VideoID).Select("author_id").Scan(&authorID).Error; err != nil {
return err
}
if authorID == 0 || authorID == evt.AuthorID {
return nil
}

View File

@@ -35,7 +35,9 @@ func StartOutboxPoller(db *gorm.DB, tmq *rabbitmq.TimelineMQ) {
err := tmq.PublishVideo(context.Background(), msg.VideoID, msg.CreateTime)
if err == nil {
db.Delete(&msg)
if err := db.Delete(&msg).Error; err != nil {
log.Printf("删除 outbox 消息失败: id=%d, err=%v", msg.ID, err)
}
} else {
log.Printf("投递MQ失败: VideoID: %d, err: %v", msg.VideoID, err)
}

View File

@@ -2,7 +2,9 @@ package worker
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"sync"
"time"
@@ -25,8 +27,8 @@ func NewSSEHub(db *gorm.DB) *SSEHub {
func (h *SSEHub) Push(userID uint, n *Notification) {
h.mu.RLock()
defer h.mu.RUnlock()
chs, ok := h.clients[userID]
h.mu.RUnlock()
if !ok {
return
}
@@ -52,13 +54,27 @@ func (h *SSEHub) Unsubscribe(userID uint, ch chan *Notification) {
chs := h.clients[userID]
for i, c := range chs {
if c == ch {
h.clients[userID] = append(chs[:i], chs[i+1:]...)
chs = append(chs[:i], chs[i+1:]...)
if len(chs) == 0 {
delete(h.clients, userID)
} else {
h.clients[userID] = chs
}
close(c)
return
}
}
}
func sseAccountID(c *gin.Context) (uint, bool) {
accountID, ok := c.Get("accountID")
if !ok {
return 0, false
}
userID, ok := accountID.(uint)
return userID, ok && userID != 0
}
func (h *SSEHub) SSERequireAuth() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.Query("token")
@@ -83,8 +99,11 @@ func (h *SSEHub) SSERequireAuth() gin.HandlerFunc {
}
func (h *SSEHub) SSEHandler(c *gin.Context) {
accountID, _ := c.Get("accountID")
userID := accountID.(uint)
userID, ok := sseAccountID(c)
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid account"})
return
}
c.Writer.Header().Set("Content-Type", "text/event-stream")
c.Writer.Header().Set("Cache-Control", "no-cache")
@@ -120,8 +139,11 @@ func (h *SSEHub) SSEHandler(c *gin.Context) {
}
func (h *SSEHub) ListHandler(c *gin.Context) {
accountID, _ := c.Get("accountID")
userID := accountID.(uint)
userID, ok := sseAccountID(c)
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid account"})
return
}
var notifications []Notification
if err := h.db.WithContext(c.Request.Context()).
@@ -139,28 +161,45 @@ func (h *SSEHub) ListHandler(c *gin.Context) {
}
func (h *SSEHub) MarkReadHandler(c *gin.Context) {
accountID, _ := c.Get("accountID")
userID := accountID.(uint)
userID, ok := sseAccountID(c)
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid account"})
return
}
var req struct {
ID *uint `json:"id"`
}
c.ShouldBindJSON(&req)
if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var err error
if req.ID != nil {
h.db.WithContext(c.Request.Context()).Model(&Notification{}).Where("id = ? AND recipient_id = ?", *req.ID, userID).Update("is_read", true)
err = h.db.WithContext(c.Request.Context()).Model(&Notification{}).Where("id = ? AND recipient_id = ?", *req.ID, userID).Update("is_read", true).Error
} else {
h.db.WithContext(c.Request.Context()).Model(&Notification{}).Where("recipient_id = ?", userID).Update("is_read", true)
err = h.db.WithContext(c.Request.Context()).Model(&Notification{}).Where("recipient_id = ?", userID).Update("is_read", true).Error
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"message": "ok"})
}
func (h *SSEHub) UnreadCountHandler(c *gin.Context) {
accountID, _ := c.Get("accountID")
userID := accountID.(uint)
userID, ok := sseAccountID(c)
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid account"})
return
}
var count int64
h.db.WithContext(c.Request.Context()).Model(&Notification{}).Where("recipient_id = ? AND is_read = ?", userID, false).Count(&count)
if err := h.db.WithContext(c.Request.Context()).Model(&Notification{}).Where("recipient_id = ? AND is_read = ?", userID, false).Count(&count).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"count": count})
}