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.
synctv/internal/op/room.go

253 lines
5.9 KiB
Go

package op
import (
"errors"
"hash/crc32"
"sync/atomic"
"github.com/gorilla/websocket"
"github.com/synctv-org/synctv/internal/db"
"github.com/synctv-org/synctv/internal/model"
"github.com/synctv-org/synctv/utils"
rtmps "github.com/zijiren233/livelib/server"
"github.com/zijiren233/stream"
"golang.org/x/crypto/bcrypt"
)
type Room struct {
model.Room
version uint32
current *current
initOnce utils.Once
hub *Hub
movies movies
}
func (r *Room) lazyInitHub() {
r.initOnce.Do(func() {
r.hub = newHub(r.ID)
})
}
func (r *Room) PeopleNum() int64 {
if r.hub == nil {
return 0
}
return r.hub.PeopleNum()
}
func (r *Room) Broadcast(data Message, conf ...BroadcastConf) error {
if r.hub == nil {
return nil
}
return r.hub.Broadcast(data, conf...)
}
func (r *Room) SendToUser(user *User, data Message) error {
if r.hub == nil {
return nil
}
return r.hub.SendToUser(user.ID, data)
}
func (r *Room) GetChannel(channelName string) (*rtmps.Channel, error) {
return r.movies.GetChannel(channelName)
}
func (r *Room) close() {
if r.initOnce.Done() {
r.hub.Close()
r.movies.Close()
}
}
func (r *Room) Version() uint32 {
return atomic.LoadUint32(&r.version)
}
func (r *Room) CheckVersion(version uint32) bool {
return atomic.LoadUint32(&r.version) == version
}
func (r *Room) UpdateMovie(movieId string, movie *model.BaseMovie) error {
return r.movies.Update(movieId, movie)
}
func (r *Room) AddMovie(m *model.Movie) error {
m.RoomID = r.ID
return r.movies.AddMovie(m)
}
func (r *Room) AddMovies(movies []*model.Movie) error {
for _, m := range movies {
m.RoomID = r.ID
}
return r.movies.AddMovies(movies)
}
func (r *Room) HasPermission(userID string, permission model.RoomUserPermission) bool {
if r.CreatorID == userID {
return true
}
rur, err := r.LoadOrCreateRoomUserRelation(userID)
if err != nil {
return false
}
return rur.HasPermission(permission)
}
func (r *Room) LoadOrCreateRoomUserRelation(userID string) (*model.RoomUserRelation, error) {
var conf []db.CreateRoomUserRelationConfig
if r.Settings.JoinNeedReview {
conf = []db.CreateRoomUserRelationConfig{db.WithRoomUserRelationStatus(model.RoomUserStatusPending)}
} else {
conf = []db.CreateRoomUserRelationConfig{db.WithRoomUserRelationStatus(model.RoomUserStatusActive)}
}
if r.Settings.UserDefaultPermissions != 0 {
conf = append(conf, db.WithRoomUserRelationPermissions(r.Settings.UserDefaultPermissions))
}
return db.FirstOrCreateRoomUserRelation(r.ID, userID, conf...)
}
func (r *Room) GetRoomUserRelation(userID string) (model.RoomUserPermission, error) {
if r.CreatorID == userID {
return model.PermissionAll, nil
}
ur, err := db.GetRoomUserRelation(r.ID, userID)
if err != nil {
return 0, err
}
return ur.Permissions, nil
}
func (r *Room) NeedPassword() bool {
return len(r.HashedPassword) != 0
}
func (r *Room) SetPassword(password string) error {
if r.CheckPassword(password) && r.NeedPassword() {
return errors.New("password is the same")
}
var hashedPassword []byte
if password != "" {
var err error
hashedPassword, err = bcrypt.GenerateFromPassword(stream.StringToBytes(password), bcrypt.DefaultCost)
if err != nil {
return err
}
atomic.StoreUint32(&r.version, crc32.ChecksumIEEE(hashedPassword))
}
r.HashedPassword = hashedPassword
return db.SetRoomHashedPassword(r.ID, hashedPassword)
}
func (r *Room) SetUserStatus(userID string, status model.RoomUserStatus) error {
return db.SetRoomUserStatus(r.ID, userID, status)
}
func (r *Room) SetUserPermission(userID string, permission model.RoomUserPermission) error {
return db.SetUserPermission(r.ID, userID, permission)
}
func (r *Room) AddUserPermission(userID string, permission model.RoomUserPermission) error {
return db.AddUserPermission(r.ID, userID, permission)
}
func (r *Room) RemoveUserPermission(userID string, permission model.RoomUserPermission) error {
return db.RemoveUserPermission(r.ID, userID, permission)
}
func (r *Room) GetMoviesCount() int {
return r.movies.Len()
}
func (r *Room) DeleteMovieByID(id string) error {
return r.movies.DeleteMovieByID(id)
}
func (r *Room) ClearMovies() error {
return r.movies.Clear()
}
func (r *Room) GetMovieByID(id string) (*Movie, error) {
return r.movies.GetMovieByID(id)
}
func (r *Room) Current() *Current {
c := r.current.Current()
return &c
}
func (r *Room) SetCurrentMovieByID(id string, play bool) error {
m, err := r.movies.GetMovieByID(id)
if err != nil {
return err
}
r.SetCurrentMovie(&m.Movie, play)
return nil
}
func (r *Room) SetCurrentMovie(movie *model.Movie, play bool) {
r.current.SetMovie(movie, play)
}
func (r *Room) SwapMoviePositions(id1, id2 string) error {
return r.movies.SwapMoviePositions(id1, id2)
}
func (r *Room) GetMoviesWithPage(page, pageSize int) []*Movie {
return r.movies.GetMoviesWithPage(page, pageSize)
}
func (r *Room) NewClient(user *User, conn *websocket.Conn) (*Client, error) {
r.lazyInitHub()
cli := newClient(user, r, conn)
err := r.hub.RegClient(cli)
if err != nil {
return nil, err
}
return cli, nil
}
func (r *Room) RegClient(cli *Client) error {
r.lazyInitHub()
return r.hub.RegClient(cli)
}
func (r *Room) UnregisterClient(cli *Client) error {
r.lazyInitHub()
return r.hub.UnRegClient(cli)
}
func (r *Room) SetStatus(playing bool, seek float64, rate float64, timeDiff float64) Status {
return r.current.SetStatus(playing, seek, rate, timeDiff)
}
func (r *Room) SetSeekRate(seek float64, rate float64, timeDiff float64) Status {
return r.current.SetSeekRate(seek, rate, timeDiff)
}
func (r *Room) SetRoomStatus(status model.RoomStatus) error {
err := db.SetRoomStatus(r.ID, status)
if err != nil {
return err
}
r.Status = status
switch status {
case model.RoomStatusBanned, model.RoomStatusPending:
return CompareAndCloseRoom(r)
}
return nil
}
func (r *Room) SetSettings(settings model.RoomSettings) error {
err := db.SaveRoomSettings(r.ID, settings)
if err != nil {
return err
}
r.Settings = settings
return nil
}