You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
3.8 KiB
Go

package entities
import (
"movie-sync-server/utils"
"sync"
"time"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
socket "github.com/zishang520/socket.io/v2/socket"
)
type Room interface {
Name() string
SetName(name string)
SetUrl(url string)
GetUrl() string
GetPlayTime() int64
SetPlayTime(playTime int64)
GetPlaying() bool
SetPlaying(playing bool)
AddUser(user User)
RemoveUser(username string)
Broadcast(event string, message any)
BroadcastRoomState()
GetUsers() []User
GetUser(name string) User
GetAllUserStatus() []UserStatus
InitUsers()
Refresh()
}
var (
_ Room = (*RoomImpl)(nil)
)
type RoomImpl struct {
name string
url string
users map[string]User
lastUpdatePlayTime int64 // 上次更新时间
playTime int64
playing bool
broadcastRoomInfoLock sync.Mutex
}
func (r *RoomImpl) Name() string {
return r.name
}
func (r *RoomImpl) SetName(name string) {
r.name = name
}
func (r *RoomImpl) SetUrl(url string) {
r.url = url
}
func (r *RoomImpl) GetUrl() string {
return r.url
}
func (r *RoomImpl) GetPlayTime() int64 {
if r.lastUpdatePlayTime == 0 { // 暂停状态
return r.playTime
}
// 计算实时播放时间
deltaTime := time.Now().Unix() - r.lastUpdatePlayTime
realPlayTime := max(r.playTime+deltaTime, 0)
return realPlayTime
}
func (r *RoomImpl) SetPlayTime(playTime int64) {
r.playTime = playTime
r.lastUpdatePlayTime = time.Now().Unix()
}
func (r *RoomImpl) GetPlaying() bool {
return r.playing
}
func (r *RoomImpl) SetPlaying(playing bool) {
r.playing = playing
if playing {
r.SetPlayTime(r.GetPlayTime()) // 更新播放时间为当前时间
} else {
r.SetPlayTime(r.GetPlayTime())
r.lastUpdatePlayTime = 0 // 清除上次更新时间,表示暂停状态
}
}
func (r *RoomImpl) AddUser(user User) {
r.users[user.ID()] = user
GetCinema().SetUserRoom(user.ID(), r)
user.GetSocket().Join(socket.Room(r.name))
}
func (r *RoomImpl) RemoveUser(username string) {
tmpUser, ok := r.users[username]
if ok {
tmpUser.GetSocket().Leave(socket.Room(r.name))
GetCinema().DeleteUserRoom(tmpUser.ID())
delete(r.users, username)
}
}
func (r *RoomImpl) Broadcast(event string, message any) {
rawMsg, err := utils.StructToMapViaJSON(message)
if err != nil {
logrus.WithError(err).Errorf("broadcast event marshal [%v]:{%v} error", event, message)
}
err = GetServer().To(socket.Room(r.name)).Emit(event, rawMsg)
if err != nil {
logrus.WithError(err).Errorf("broadcast event [%v]:{%v} error", event, message)
}
}
func (r *RoomImpl) BroadcastRoomState() {
// 限制广播频率
if r.broadcastRoomInfoLock.TryLock() {
go func() {
r.Broadcast("roomInfo", RoomStateChangedMessage{
ServerTime: time.Now().Unix(),
URL: r.GetUrl(),
UserStatus: r.GetAllUserStatus(),
Playing: r.GetPlaying(),
PlayTime: r.GetPlayTime(),
})
// 延迟一段时间后再次广播最新状态
time.Sleep(time.Millisecond * 500)
r.Broadcast("roomInfo", RoomStateChangedMessage{
ServerTime: time.Now().Unix(),
URL: r.GetUrl(),
UserStatus: r.GetAllUserStatus(),
Playing: r.GetPlaying(),
PlayTime: r.GetPlayTime(),
})
r.broadcastRoomInfoLock.Unlock()
}()
} else {
return
}
}
func (r *RoomImpl) InitUsers() {
r.users = make(map[string]User)
}
func (r *RoomImpl) Refresh() {
GetServer().To(socket.Room(r.name)).Emit("refresh")
}
func (r *RoomImpl) GetUsers() []User {
return lo.MapToSlice(r.users, func(k string, v User) User { return v })
}
func (r *RoomImpl) GetUser(name string) User {
user, ok := r.users[name]
if ok {
return user
}
return nil
}
func (r *RoomImpl) GetAllUserStatus() []UserStatus {
return lo.MapToSlice(r.users, func(k string, v User) UserStatus {
return v.ToUserStatus()
})
}