From 57a1c88eae7d0623fd2afddef5f842f68c55e820 Mon Sep 17 00:00:00 2001 From: zijiren233 Date: Sat, 16 Dec 2023 22:34:59 +0800 Subject: [PATCH] Feat: slice sort stable --- internal/bootstrap/provider.go | 26 +++++++++++------- internal/op/rooms.go | 39 +++------------------------ server/handlers/room.go | 49 ++++++++++++++++++++++++++++++---- server/model/room.go | 13 +++++++-- 4 files changed, 75 insertions(+), 52 deletions(-) diff --git a/internal/bootstrap/provider.go b/internal/bootstrap/provider.go index da6ad30..a166354 100644 --- a/internal/bootstrap/provider.go +++ b/internal/bootstrap/provider.go @@ -5,9 +5,10 @@ import ( "fmt" "os" "path/filepath" - "time" + "slices" "github.com/hashicorp/go-hclog" + "github.com/maruel/natural" log "github.com/sirupsen/logrus" "github.com/synctv-org/synctv/cmd/flags" "github.com/synctv-org/synctv/internal/conf" @@ -18,7 +19,6 @@ import ( "github.com/synctv-org/synctv/internal/settings" "github.com/synctv-org/synctv/utils" "github.com/zijiren233/gencontainer/refreshcache" - "github.com/zijiren233/gencontainer/vec" ) var ProviderGroupSettings = make(map[model.SettingGroup]*ProviderGroupSetting) @@ -34,17 +34,23 @@ type ProviderGroupSetting struct { var ( Oauth2EnabledCache = refreshcache.NewRefreshCache[[]provider.OAuth2Provider](func(context.Context, ...any) ([]provider.OAuth2Provider, error) { - a := vec.New[provider.OAuth2Provider](vec.WithCmpEqual[provider.OAuth2Provider](func(v1, v2 provider.OAuth2Provider) bool { - return v1 == v2 - }), vec.WithCmpLess[provider.OAuth2Provider](func(v1, v2 provider.OAuth2Provider) bool { - return v1 < v2 - })) + ps := providers.EnabledProvider() + r := make([]provider.OAuth2Provider, 0, ps.Len()) providers.EnabledProvider().Range(func(key provider.OAuth2Provider, value provider.ProviderInterface) bool { - a.Push(key) + r = append(r, key) return true }) - return a.SortStable().Slice(), nil - }, time.Hour) + slices.SortStableFunc(r, func(a, b provider.OAuth2Provider) int { + if a == b { + return 0 + } else if natural.Less(string(a), string(b)) { + return -1 + } else { + return 1 + } + }) + return r, nil + }, 0) ) func InitProvider(ctx context.Context) (err error) { diff --git a/internal/op/rooms.go b/internal/op/rooms.go index ee4f8c4..784cab2 100644 --- a/internal/op/rooms.go +++ b/internal/op/rooms.go @@ -9,11 +9,14 @@ import ( "github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/settings" "github.com/zijiren233/gencontainer/synccache" - "github.com/zijiren233/gencontainer/vec" ) var roomCache *synccache.SyncCache[string, *Room] +func RangeRoomCache(f func(key string, value *synccache.Entry[*Room]) bool) { + roomCache.Range(f) +} + func CreateRoom(name, password string, maxCount int64, conf ...db.CreateRoomConfig) (*Room, error) { r, err := db.CreateRoom(name, password, maxCount, conf...) if err != nil { @@ -146,40 +149,6 @@ func GetAllRoomsInCacheWithoutHidden() []*Room { return rooms } -type RoomInfo struct { - RoomId string `json:"roomId"` - RoomName string `json:"roomName"` - PeopleNum int64 `json:"peopleNum"` - NeedPassword bool `json:"needPassword"` - CreatorID string `json:"creatorId"` - Creator string `json:"creator"` - CreatedAt int64 `json:"createdAt"` - Status model.RoomStatus `json:"status"` -} - -func GetRoomHeapInCacheWithoutHidden() []*RoomInfo { - rooms := vec.New[*RoomInfo](vec.WithCmpLess[*RoomInfo](func(v1, v2 *RoomInfo) bool { - return v1.PeopleNum > v2.PeopleNum - }), vec.WithCmpEqual[*RoomInfo](func(v1, v2 *RoomInfo) bool { - return v1.RoomId == v2.RoomId - })) - roomCache.Range(func(key string, value *synccache.Entry[*Room]) bool { - v := value.Value() - if !v.Settings.Hidden { - rooms.Push(&RoomInfo{ - RoomId: v.ID, - RoomName: v.Name, - PeopleNum: v.PeopleNum(), - NeedPassword: v.NeedPassword(), - Creator: GetUserName(v.CreatorID), - CreatedAt: v.CreatedAt.UnixMilli(), - }) - } - return true - }) - return rooms.SortStable().Slice() -} - func SetRoomStatus(roomID string, status model.RoomStatus) error { err := db.SetRoomStatus(roomID, status) if err != nil { diff --git a/server/handlers/room.go b/server/handlers/room.go index cbcda37..7409ac0 100644 --- a/server/handlers/room.go +++ b/server/handlers/room.go @@ -5,9 +5,11 @@ import ( "errors" "fmt" "net/http" + "slices" "time" "github.com/gin-gonic/gin" + "github.com/maruel/natural" "github.com/synctv-org/synctv/internal/db" dbModel "github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/op" @@ -16,6 +18,7 @@ import ( "github.com/synctv-org/synctv/server/model" "github.com/synctv-org/synctv/utils" "github.com/zijiren233/gencontainer/refreshcache" + "github.com/zijiren233/gencontainer/synccache" "gorm.io/gorm" ) @@ -63,8 +66,41 @@ func CreateRoom(ctx *gin.Context) { })) } -var roomHotCache = refreshcache.NewRefreshCache[[]*op.RoomInfo](func(context.Context, ...any) ([]*op.RoomInfo, error) { - return op.GetRoomHeapInCacheWithoutHidden(), nil +var roomHotCache = refreshcache.NewRefreshCache[[]*model.RoomListResp](func(context.Context, ...any) ([]*model.RoomListResp, error) { + rooms := make([]*model.RoomListResp, 0) + op.RangeRoomCache(func(key string, value *synccache.Entry[*op.Room]) bool { + v := value.Value() + if !v.Settings.Hidden { + rooms = append(rooms, &model.RoomListResp{ + RoomId: v.ID, + RoomName: v.Name, + PeopleNum: v.PeopleNum(), + NeedPassword: v.NeedPassword(), + Creator: op.GetUserName(v.CreatorID), + CreatedAt: v.CreatedAt.UnixMilli(), + }) + } + return true + }) + + slices.SortStableFunc(rooms, func(a, b *model.RoomListResp) int { + if a.PeopleNum == b.PeopleNum { + if a.RoomName == b.RoomName { + return 0 + } + if natural.Less(a.RoomName, b.RoomName) { + return -1 + } else { + return 1 + } + } else if a.PeopleNum > b.PeopleNum { + return -1 + } else { + return 1 + } + }) + + return rooms, nil }, time.Second*3) func RoomHotList(ctx *gin.Context) { @@ -74,12 +110,15 @@ func RoomHotList(ctx *gin.Context) { return } - r, _ := roomHotCache.Get(ctx) - rs := utils.GetPageItems(r, page, pageSize) + r, err := roomHotCache.Get(ctx) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) + return + } ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{ "total": len(r), - "list": rs, + "list": utils.GetPageItems(r, page, pageSize), })) } diff --git a/server/model/room.go b/server/model/room.go index 97cd2c4..2a43cad 100644 --- a/server/model/room.go +++ b/server/model/room.go @@ -6,9 +6,9 @@ import ( "regexp" json "github.com/json-iterator/go" - "github.com/synctv-org/synctv/internal/op" "github.com/gin-gonic/gin" + "github.com/synctv-org/synctv/internal/model" dbModel "github.com/synctv-org/synctv/internal/model" ) @@ -68,7 +68,16 @@ func (c *CreateRoomReq) Validate() error { return nil } -type RoomListResp = op.RoomInfo +type RoomListResp struct { + RoomId string `json:"roomId"` + RoomName string `json:"roomName"` + PeopleNum int64 `json:"peopleNum"` + NeedPassword bool `json:"needPassword"` + CreatorID string `json:"creatorId"` + Creator string `json:"creator"` + CreatedAt int64 `json:"createdAt"` + Status model.RoomStatus `json:"status"` +} type LoginRoomReq struct { RoomId string `json:"roomId"`