feat: 建立可靠通知、吊销与跨实例状态
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user