diff --git a/internal/op/rooms.go b/internal/op/rooms.go index 8bfd843..6e39af3 100644 --- a/internal/op/rooms.go +++ b/internal/op/rooms.go @@ -8,6 +8,7 @@ import ( "github.com/synctv-org/synctv/internal/db" "github.com/synctv-org/synctv/internal/model" synccache "github.com/synctv-org/synctv/utils/syncCache" + "github.com/zijiren233/gencontainer/heap" ) var roomTTL = time.Hour * 24 * 2 @@ -150,3 +151,57 @@ func GetAllRoomsInCacheWithoutHidden() []*Room { }) return rooms } + +type RoomHeapItem struct { + ID uint + RoomName string + ClientNum int64 + NeedPassword bool + CreatorID uint + CreatedAt time.Time +} + +type RoomHeap []*RoomHeapItem + +func (h RoomHeap) Len() int { + return len(h) +} + +func (h RoomHeap) Less(i, j int) bool { + return h[i].ClientNum < h[j].ClientNum +} + +func (h RoomHeap) Swap(i, j int) { + h[i], h[j] = h[j], h[i] +} + +func (h *RoomHeap) Push(x *RoomHeapItem) { + *h = append(*h, x) +} + +func (h *RoomHeap) Pop() *RoomHeapItem { + old := *h + n := len(old) + x := old[n-1] + *h = old[0 : n-1] + return x +} + +func GetRoomHeapInCacheWithoutHidden() RoomHeap { + rooms := make(RoomHeap, 0) + roomCache.Range(func(key uint, value *synccache.Entry[*Room]) bool { + v := value.Value() + if !v.Settings.Hidden { + heap.Push[*RoomHeapItem](&rooms, &RoomHeapItem{ + ID: v.ID, + RoomName: v.Name, + ClientNum: v.ClientNum(), + NeedPassword: v.NeedPassword(), + CreatorID: v.CreatorID, + CreatedAt: v.CreatedAt, + }) + } + return true + }) + return rooms +} diff --git a/server/handlers/room.go b/server/handlers/room.go index 675a919..336b409 100644 --- a/server/handlers/room.go +++ b/server/handlers/room.go @@ -13,7 +13,6 @@ import ( "github.com/synctv-org/synctv/server/middlewares" "github.com/synctv-org/synctv/server/model" "github.com/synctv-org/synctv/utils" - "github.com/zijiren233/gencontainer/vec" "gorm.io/gorm" ) @@ -75,31 +74,23 @@ func RoomHotList(ctx *gin.Context) { return } - r := op.GetAllRoomsInCacheWithoutHidden() - rs := vec.New[*model.RoomListResp](vec.WithCmpLess[*model.RoomListResp](func(v1, v2 *model.RoomListResp) bool { - return v1.PeopleNum < v2.PeopleNum - }), vec.WithCmpEqual[*model.RoomListResp](func(v1, v2 *model.RoomListResp) bool { - return v1.PeopleNum == v2.PeopleNum - })) - for _, v := range r { - rs.Push(&model.RoomListResp{ + r := op.GetRoomHeapInCacheWithoutHidden() + rs := utils.GetPageItems(r, page, pageSize) + resp := make([]*model.RoomListResp, len(rs)) + for i, v := range rs { + resp[i] = &model.RoomListResp{ RoomId: v.ID, - RoomName: v.Name, - PeopleNum: v.ClientNum(), - NeedPassword: v.NeedPassword(), - Creator: op.GetUserName(v.Room.CreatorID), - CreatedAt: v.Room.CreatedAt.UnixMilli(), - }) - } - - rs.SortStable() - if ctx.DefaultQuery("sort", "desc") == "desc" { - rs.Reverse() + RoomName: v.RoomName, + PeopleNum: v.ClientNum, + NeedPassword: v.NeedPassword, + Creator: op.GetUserName(v.CreatorID), + CreatedAt: v.CreatedAt.UnixMilli(), + } } ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{ - "total": rs.Len(), - "list": utils.GetPageItems(rs.Slice(), page, pageSize), + "total": len(r), + "list": rs, })) } diff --git a/utils/syncCache/cache.go b/utils/syncCache/cache.go index de9e524..4e1d0a9 100644 --- a/utils/syncCache/cache.go +++ b/utils/syncCache/cache.go @@ -35,18 +35,10 @@ func NewSyncCache[K comparable, V any](trimTime time.Duration, conf ...SyncCache return sc } -func (sc *SyncCache[K, V]) Releases() { - sc.ticker.Stop() - sc.cache.Clear() -} - func (sc *SyncCache[K, V]) trim() { sc.cache.Range(func(key K, value *Entry[V]) bool { if value.IsExpired() { - sc.cache.CompareAndDelete(key, value) - if sc.deletedCallback != nil { - sc.deletedCallback(value.value) - } + sc.CompareAndDelete(key, value) } return true }) @@ -61,33 +53,19 @@ func (sc *SyncCache[K, V]) Load(key K) (value *Entry[V], loaded bool) { if ok && !e.IsExpired() { return e, ok } + sc.CompareAndDelete(key, e) return } func (sc *SyncCache[K, V]) LoadOrStore(key K, value V, expire time.Duration) (actual *Entry[V], loaded bool) { e, loaded := sc.cache.LoadOrStore(key, NewEntry[V](value, expire)) - if e.IsExpired() { - e = NewEntry[V](value, expire) - sc.cache.Store(key, e) - return e, false + if loaded && e.IsExpired() { + sc.CompareAndDelete(key, e) + return sc.LoadOrStore(key, value, expire) } return e, loaded } -func (sc *SyncCache[K, V]) AddExpiration(key K, d time.Duration) { - e, ok := sc.cache.Load(key) - if ok { - e.AddExpiration(d) - } -} - -func (sc *SyncCache[K, V]) SetExpiration(key K, t time.Time) { - e, ok := sc.cache.Load(key) - if ok { - e.SetExpiration(t) - } -} - func (sc *SyncCache[K, V]) Delete(key K) { sc.LoadAndDelete(key) } @@ -117,6 +95,7 @@ func (sc *SyncCache[K, V]) Range(f func(key K, value *Entry[V]) bool) { if !value.IsExpired() { return f(key, value) } + sc.cache.CompareAndDelete(key, value) return true }) }