feat: 建立可靠通知、吊销与跨实例状态

This commit is contained in:
weijuesen
2026-08-14 01:41:14 +08:00
parent a6a996a518
commit a25bc7abc6
22 changed files with 1017 additions and 245 deletions
+25 -51
View File
@@ -1,61 +1,34 @@
package handler
import (
"fmt"
"math/rand"
"net/http"
"sync"
"time"
"silk-server-go/internal/middleware"
"silk-server-go/internal/model"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// notificationItem 通知项
type notificationItem struct {
ID string `json:"id"`
Channel string `json:"channel"`
Target string `json:"target"`
Title string `json:"title"`
Body string `json:"body"`
CreatedAt string `json:"createdAt"`
}
// 通知内存存储(后续可替换为 Redis)
var (
notificationStore []notificationItem
notificationMu sync.Mutex
)
// RegisterNotificationRoutes 注册通知路由
func RegisterNotificationRoutes(rg *gin.RouterGroup, db *gorm.DB) {
readPerm := middleware.RequirePermission(db, "alarm:read")
rg.GET("/notifications", readPerm, listNotifications())
rg.POST("/notifications", readPerm, createNotification())
rg.GET("/notifications", readPerm, listNotifications(db))
rg.POST("/notifications", readPerm, createNotification(db))
}
// listNotifications 通知列表(上限200
func listNotifications() gin.HandlerFunc {
func listNotifications(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
notificationMu.Lock()
defer notificationMu.Unlock()
limit := 200
if len(notificationStore) < limit {
limit = len(notificationStore)
}
// 返回最新的 limit 条(存储已按新到旧排序)
result := make([]notificationItem, limit)
copy(result, notificationStore[:limit])
c.JSON(http.StatusOK, result)
var list []model.Notification
db.Order("created_at DESC").Limit(200).Find(&list)
c.JSON(http.StatusOK, list)
}
}
// createNotification 手动发通知
func createNotification() gin.HandlerFunc {
func createNotification(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) {
var body struct {
Channel string `json:"channel"`
@@ -68,24 +41,25 @@ func createNotification() gin.HandlerFunc {
return
}
ntf := notificationItem{
ID: fmt.Sprintf("%d%d", time.Now().UnixNano(), rand.Intn(1000000)),
Channel: body.Channel,
Target: body.Target,
Title: body.Title,
Body: body.Body,
CreatedAt: time.Now().Format(time.RFC3339),
ntf := model.Notification{
UserID: currentUserID(c),
Channel: body.Channel,
Target: body.Target,
Title: body.Title,
Body: body.Body,
Status: "sent",
NextAttemptAt: time.Now(),
}
notificationMu.Lock()
// 插入到头部(最新在前)
notificationStore = append([]notificationItem{ntf}, notificationStore...)
// 保留最近 500 条
if len(notificationStore) > 500 {
notificationStore = notificationStore[:500]
if ntf.Channel == "" {
ntf.Channel = "manual"
}
if ntf.Target == "" {
ntf.Target = "all"
}
if err := db.Create(&ntf).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "创建通知失败"})
return
}
notificationMu.Unlock()
c.JSON(http.StatusCreated, ntf)
}
}