From 7c784b31b7f0e1866328dc78a3177d20059f0f5f Mon Sep 17 00:00:00 2001 From: UUBulb <35923940+uubulb@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:21:59 +0800 Subject: [PATCH] fix list apis (#453) --- cmd/dashboard/controller/ddns.go | 81 +++++++++--------------- cmd/dashboard/controller/member_api.go | 2 +- cmd/dashboard/controller/notification.go | 15 +++-- cmd/dashboard/controller/server.go | 10 ++- service/singleton/ddns.go | 45 +++++++++++-- service/singleton/notification.go | 28 +++++++- 6 files changed, 112 insertions(+), 69 deletions(-) diff --git a/cmd/dashboard/controller/ddns.go b/cmd/dashboard/controller/ddns.go index 4f5dbbd..471e2db 100644 --- a/cmd/dashboard/controller/ddns.go +++ b/cmd/dashboard/controller/ddns.go @@ -7,12 +7,35 @@ import ( "strings" "github.com/gin-gonic/gin" + "github.com/jinzhu/copier" "golang.org/x/net/idna" "github.com/naiba/nezha/model" "github.com/naiba/nezha/service/singleton" ) +// List DDNS Profiles +// @Summary List DDNS profiles +// @Schemes +// @Description List DDNS profiles +// @Security BearerAuth +// @Tags auth required +// @Produce json +// @Success 200 {object} model.CommonResponse[[]*model.DDNSProfile] +// @Router /ddns [get] +func listDDNS(c *gin.Context) ([]*model.DDNSProfile, error) { + var ddnsProfiles []*model.DDNSProfile + + singleton.DDNSCacheLock.RLock() + defer singleton.DDNSCacheLock.RUnlock() + + if err := copier.Copy(&ddnsProfiles, &singleton.DDNSList); err != nil { + return nil, err + } + + return ddnsProfiles, nil +} + // Add DDNS profile // @Summary Add DDNS profile // @Security BearerAuth @@ -66,7 +89,8 @@ func createDDNS(c *gin.Context) (uint64, error) { return 0, newGormError("%v", err) } - singleton.OnDDNSUpdate() + singleton.OnDDNSUpdate(&p) + singleton.UpdateDDNSList() return p.ID, nil } @@ -136,7 +160,8 @@ func updateDDNS(c *gin.Context) (any, error) { return nil, newGormError("%v", err) } - singleton.OnDDNSUpdate() + singleton.OnDDNSUpdate(&p) + singleton.UpdateDDNSList() return nil, nil } @@ -163,60 +188,12 @@ func batchDeleteDDNS(c *gin.Context) (any, error) { return nil, newGormError("%v", err) } - singleton.OnDDNSUpdate() + singleton.OnDDNSDelete(ddnsConfigs) + singleton.UpdateDDNSList() return nil, nil } -// List DDNS Profiles -// @Summary List DDNS profiles -// @Schemes -// @Description List DDNS profiles -// @Security BearerAuth -// @Tags auth required -// @param id query string false "Profile ID" -// @Produce json -// @Success 200 {object} model.CommonResponse[[]model.DDNSProfile] -// @Router /ddns [get] -func listDDNS(c *gin.Context) ([]model.DDNSProfile, error) { - var idList []uint64 - idQuery := c.Query("id") - - if idQuery != "" { - idListStr := strings.Split(idQuery, ",") - idList = make([]uint64, 0, len(idListStr)) - for _, v := range idListStr { - id, err := strconv.ParseUint(v, 10, 64) - if err != nil { - return nil, err - } - idList = append(idList, id) - } - } - - var ddnsProfiles []model.DDNSProfile - - singleton.DDNSCacheLock.RLock() - if len(idList) > 0 { - ddnsProfiles = make([]model.DDNSProfile, 0, len(idList)) - for _, id := range idList { - if profile, ok := singleton.DDNSCache[id]; ok { - ddnsProfiles = append(ddnsProfiles, *profile) - } else { - return nil, fmt.Errorf("profile id %d not found", id) - } - } - } else { - ddnsProfiles = make([]model.DDNSProfile, 0, len(singleton.DDNSCache)) - for _, profile := range singleton.DDNSCache { - ddnsProfiles = append(ddnsProfiles, *profile) - } - } - - singleton.DDNSCacheLock.RUnlock() - return ddnsProfiles, nil -} - // List DDNS Providers // @Summary List DDNS providers // @Schemes diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index fa03fda..7b625a5 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -533,7 +533,7 @@ func (ma *memberAPI) addOrEditDDNS(c *gin.Context) { }) return } - singleton.OnDDNSUpdate() + //singleton.OnDDNSUpdate() c.JSON(http.StatusOK, model.Response{ Code: http.StatusOK, }) diff --git a/cmd/dashboard/controller/notification.go b/cmd/dashboard/controller/notification.go index b0db063..af1b433 100644 --- a/cmd/dashboard/controller/notification.go +++ b/cmd/dashboard/controller/notification.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/gin-gonic/gin" + "github.com/jinzhu/copier" "github.com/naiba/nezha/model" "github.com/naiba/nezha/service/singleton" "gorm.io/gorm" @@ -17,14 +18,15 @@ import ( // @Description List notification // @Tags auth required // @Produce json -// @Success 200 {object} model.CommonResponse[any] +// @Success 200 {object} model.CommonResponse[[]*model.Notification] // @Router /notification [get] -func listNotification(c *gin.Context) ([]model.Notification, error) { +func listNotification(c *gin.Context) ([]*model.Notification, error) { singleton.NotificationsLock.RLock() defer singleton.NotificationsLock.RUnlock() - notifications := make([]model.Notification, 0, len(singleton.NotificationMap)) - for _, n := range singleton.NotificationMap { - notifications = append(notifications, *n) + + var notifications []*model.Notification + if err := copier.Copy(¬ifications, &singleton.NotificationListSorted); err != nil { + return nil, err } return notifications, nil } @@ -73,6 +75,7 @@ func createNotification(c *gin.Context) (uint64, error) { } singleton.OnRefreshOrAddNotification(&n) + singleton.UpdateNotificationList() return n.ID, nil } @@ -130,6 +133,7 @@ func updateNotification(c *gin.Context) (any, error) { } singleton.OnRefreshOrAddNotification(&n) + singleton.UpdateNotificationList() return nil, nil } @@ -166,5 +170,6 @@ func batchDeleteNotification(c *gin.Context) (any, error) { } singleton.OnDeleteNotification(n) + singleton.UpdateNotificationList() return nil, nil } diff --git a/cmd/dashboard/controller/server.go b/cmd/dashboard/controller/server.go index 557dd65..4825b69 100644 --- a/cmd/dashboard/controller/server.go +++ b/cmd/dashboard/controller/server.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/gin-gonic/gin" + "github.com/jinzhu/copier" "github.com/naiba/nezha/model" "github.com/naiba/nezha/pkg/utils" @@ -18,12 +19,17 @@ import ( // @Description List server // @Tags auth required // @Produce json -// @Success 200 {object} model.CommonResponse[any] +// @Success 200 {object} model.CommonResponse[[]*model.Server] // @Router /server [get] func listServer(c *gin.Context) ([]*model.Server, error) { singleton.SortedServerLock.RLock() defer singleton.SortedServerLock.RUnlock() - return singleton.SortedServerList, nil + + var ssl []*model.Server + if err := copier.Copy(&ssl, &singleton.SortedServerList); err != nil { + return nil, err + } + return ssl, nil } // Edit server diff --git a/service/singleton/ddns.go b/service/singleton/ddns.go index cc88b63..b2461b2 100644 --- a/service/singleton/ddns.go +++ b/service/singleton/ddns.go @@ -2,6 +2,7 @@ package singleton import ( "fmt" + "slices" "sync" "github.com/libdns/cloudflare" @@ -16,22 +17,54 @@ import ( var ( DDNSCache map[uint64]*model.DDNSProfile DDNSCacheLock sync.RWMutex + DDNSList []*model.DDNSProfile ) func initDDNS() { - OnDDNSUpdate() - OnNameserverUpdate() -} - -func OnDDNSUpdate() { var ddns []*model.DDNSProfile DB.Find(&ddns) DDNSCacheLock.Lock() - defer DDNSCacheLock.Unlock() DDNSCache = make(map[uint64]*model.DDNSProfile) for i := 0; i < len(ddns); i++ { DDNSCache[ddns[i].ID] = ddns[i] } + DDNSCacheLock.Unlock() + + UpdateDDNSList() + OnNameserverUpdate() +} + +func OnDDNSUpdate(p *model.DDNSProfile) { + DDNSCacheLock.Lock() + defer DDNSCacheLock.Unlock() + DDNSCache[p.ID] = p +} + +func OnDDNSDelete(id []uint64) { + DDNSCacheLock.Lock() + defer DDNSCacheLock.Unlock() + + for _, i := range id { + delete(DDNSCache, i) + } +} + +func UpdateDDNSList() { + DDNSCacheLock.RLock() + defer DDNSCacheLock.RUnlock() + + DDNSList = make([]*model.DDNSProfile, 0, len(DDNSCache)) + for _, p := range DDNSCache { + DDNSList = append(DDNSList, p) + } + slices.SortFunc(DDNSList, func(a, b *model.DDNSProfile) int { + if a.ID < b.ID { + return -1 + } else if a.ID == b.ID { + return 0 + } + return 1 + }) } func OnNameserverUpdate() { diff --git a/service/singleton/notification.go b/service/singleton/notification.go index 19782d9..16fe79c 100644 --- a/service/singleton/notification.go +++ b/service/singleton/notification.go @@ -3,6 +3,7 @@ package singleton import ( "fmt" "log" + "slices" "sync" "time" @@ -18,8 +19,9 @@ var ( NotificationList map[uint64]map[uint64]*model.Notification // [NotificationGroupID][NotificationID] -> model.Notification NotificationIDToGroups map[uint64]map[uint64]struct{} // [NotificationID] -> NotificationGroupID - NotificationMap map[uint64]*model.Notification - NotificationGroup map[uint64]string // [NotificationGroupID] -> [NotificationGroupName] + NotificationMap map[uint64]*model.Notification + NotificationListSorted []*model.Notification + NotificationGroup map[uint64]string // [NotificationGroupID] -> [NotificationGroupName] NotificationsLock sync.RWMutex NotificationGroupLock sync.RWMutex @@ -36,7 +38,6 @@ func InitNotification() { func loadNotifications() { InitNotification() NotificationsLock.Lock() - defer NotificationsLock.Unlock() groupNotifications := make(map[uint64][]uint64) var ngn []model.NotificationGroupNotification @@ -72,6 +73,27 @@ func loadNotifications() { } } } + + NotificationsLock.Unlock() + UpdateNotificationList() +} + +func UpdateNotificationList() { + NotificationsLock.RLock() + defer NotificationsLock.RUnlock() + + NotificationListSorted = make([]*model.Notification, 0, len(NotificationMap)) + for _, n := range NotificationMap { + NotificationListSorted = append(NotificationListSorted, n) + } + slices.SortFunc(NotificationListSorted, func(a, b *model.Notification) int { + if a.ID < b.ID { + return -1 + } else if a.ID == b.ID { + return 0 + } + return 1 + }) } // OnRefreshOrAddNotificationGroup 刷新通知方式组相关参数