|
|
|
package op
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"hash/crc32"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"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
|
|
|
|
var roomCache *synccache.SyncCache[uint, *Room]
|
|
|
|
|
|
|
|
func CreateRoom(name, password string, conf ...db.CreateRoomConfig) (*Room, error) {
|
|
|
|
r, err := db.CreateRoom(name, password, conf...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return InitRoom(r)
|
|
|
|
}
|
|
|
|
|
|
|
|
func InitRoom(room *model.Room) (*Room, error) {
|
|
|
|
r := &Room{
|
|
|
|
Room: *room,
|
|
|
|
version: crc32.ChecksumIEEE(room.HashedPassword),
|
|
|
|
current: newCurrent(),
|
|
|
|
movies: movies{
|
|
|
|
roomID: room.ID,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
i, loaded := roomCache.LoadOrStore(room.ID, r, roomTTL)
|
|
|
|
if loaded {
|
|
|
|
return r, errors.New("room already init")
|
|
|
|
}
|
|
|
|
return i.Value(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func LoadOrInitRoom(room *model.Room) (*Room, bool) {
|
|
|
|
i, loaded := roomCache.LoadOrStore(room.ID, &Room{
|
|
|
|
Room: *room,
|
|
|
|
version: crc32.ChecksumIEEE(room.HashedPassword),
|
|
|
|
current: newCurrent(),
|
|
|
|
movies: movies{
|
|
|
|
roomID: room.ID,
|
|
|
|
},
|
|
|
|
}, roomTTL)
|
|
|
|
if loaded {
|
|
|
|
i.SetExpiration(time.Now().Add(roomTTL))
|
|
|
|
}
|
|
|
|
return i.Value(), loaded
|
|
|
|
}
|
|
|
|
|
|
|
|
func DeleteRoom(roomID uint) error {
|
|
|
|
err := db.DeleteRoomByID(roomID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return CloseRoom(roomID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func CloseRoom(roomID uint) error {
|
|
|
|
r, loaded := roomCache.LoadAndDelete(roomID)
|
|
|
|
if loaded {
|
|
|
|
r.Value().close()
|
|
|
|
}
|
|
|
|
return errors.New("room not found in cache")
|
|
|
|
}
|
|
|
|
|
|
|
|
func LoadRoomByID(id uint) (*Room, error) {
|
|
|
|
r2, loaded := roomCache.Load(id)
|
|
|
|
if loaded {
|
|
|
|
r2.SetExpiration(time.Now().Add(roomTTL))
|
|
|
|
return r2.Value(), nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("room not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
func LoadOrInitRoomByID(id uint) (*Room, error) {
|
|
|
|
i, loaded := roomCache.Load(id)
|
|
|
|
if loaded {
|
|
|
|
i.SetExpiration(time.Now().Add(roomTTL))
|
|
|
|
return i.Value(), nil
|
|
|
|
}
|
|
|
|
room, err := db.GetRoomByID(id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
r, _ := LoadOrInitRoom(room)
|
|
|
|
return r, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ClientNum(roomID uint) int64 {
|
|
|
|
r, loaded := roomCache.Load(roomID)
|
|
|
|
if loaded {
|
|
|
|
return r.Value().ClientNum()
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func HasRoom(roomID uint) bool {
|
|
|
|
_, ok := roomCache.Load(roomID)
|
|
|
|
if ok {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
ok, err := db.HasRoom(roomID)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func HasRoomByName(name string) bool {
|
|
|
|
ok, err := db.HasRoomByName(name)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetRoomPassword(roomID uint, password string) error {
|
|
|
|
r, err := LoadOrInitRoomByID(roomID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return r.SetPassword(password)
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetAllRoomsInCacheWithNoNeedPassword() []*Room {
|
|
|
|
rooms := make([]*Room, 0)
|
|
|
|
roomCache.Range(func(key uint, value *synccache.Entry[*Room]) bool {
|
|
|
|
v := value.Value()
|
|
|
|
if !v.NeedPassword() {
|
|
|
|
rooms = append(rooms, v)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
return rooms
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetAllRoomsInCacheWithoutHidden() []*Room {
|
|
|
|
rooms := make([]*Room, 0)
|
|
|
|
roomCache.Range(func(key uint, value *synccache.Entry[*Room]) bool {
|
|
|
|
v := value.Value()
|
|
|
|
if !v.Settings.Hidden {
|
|
|
|
rooms = append(rooms, v)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
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
|
|
|
|
}
|