From ea1487363380326eaa16bd6e2c8e55b32a60b9b3 Mon Sep 17 00:00:00 2001 From: zijiren233 Date: Wed, 18 Oct 2023 00:01:55 +0800 Subject: [PATCH] Fix: movies error and first login dont init version --- internal/db/movie.go | 61 +-------------- internal/model/movie.go | 26 +++---- internal/op/movie.go | 155 ++++++++++++++++++++++++++++++++++++++- internal/op/room.go | 27 ++++--- internal/op/rooms.go | 2 + server/handlers/movie.go | 41 +++++++++-- server/handlers/room.go | 6 +- server/model/movie.go | 7 ++ server/model/room.go | 22 +++--- 9 files changed, 241 insertions(+), 106 deletions(-) diff --git a/internal/db/movie.go b/internal/db/movie.go index ce57eb0..1e70680 100644 --- a/internal/db/movie.go +++ b/internal/db/movie.go @@ -9,70 +9,17 @@ func CreateMovie(movie *model.Movie) error { return db.Create(movie).Error } -type GetMovies struct { - max int - page int -} - -func DefaultGetMovies() *GetMovies { - return &GetMovies{ - max: 10, - page: 1, - } -} - -type GetMoviesConfig func(gm *GetMovies) - -func GetMoviesMax(max int) GetMoviesConfig { - return func(gm *GetMovies) { - gm.max = max - } -} - -func GetMoviesPage(page int) GetMoviesConfig { - return func(gm *GetMovies) { - gm.page = page - } -} - -func GetMoviesByRoomID(roomID uint, conf ...GetMoviesConfig) ([]model.Movie, error) { - movies := []model.Movie{} - df := DefaultGetMovies() - for _, c := range conf { - c(df) - } - err := db.Where("room_id = ?", roomID).Limit(df.max).Offset((df.page - 1) * df.max).Find(&movies).Error - return movies, err -} - func GetAllMoviesByRoomID(roomID uint) ([]model.Movie, error) { movies := []model.Movie{} - err := db.Where("room_id = ?", roomID).Find(&movies).Error + err := db.Where("room_id = ?", roomID).Order("position ASC").Find(&movies).Error return movies, err } -func GetMovieWithPullKey(roomID uint, pullKey string) (*model.Movie, error) { - movie := &model.Movie{} - err := db.Where("room_id = ? AND pull_key = ?", roomID, pullKey).First(movie).Error - return movie, err -} - -func GetMoviesCountByRoomID(roomID uint) (int64, error) { - var count int64 - err := db.Model(&model.Movie{}).Where("room_id = ?", roomID).Count(&count).Error - return count, err -} - -func GetMovieByID(roomID, id uint) (*model.Movie, error) { - movie := &model.Movie{} - err := db.Where("room_id = ? AND id = ?", roomID, id).First(movie).Error - return movie, err -} - func DeleteMovieByID(roomID, id uint) error { return db.Where("room_id = ? AND id = ?", roomID, id).Delete(&model.Movie{}).Error } +// TODO: delete error func LoadAndDeleteMovieByID(roomID, id uint, columns ...clause.Column) (*model.Movie, error) { movie := &model.Movie{} err := db.Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", roomID, id).Delete(movie).Error @@ -93,8 +40,8 @@ func UpdateMovie(movie model.Movie) error { return db.Model(&model.Movie{}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(movie).Error } -func LoadAndUpdateMovie(movie model.Movie, columns ...string) (*model.Movie, error) { - err := db.Model(&model.Movie{}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(movie).Error +func LoadAndUpdateMovie(movie model.Movie, columns ...clause.Column) (*model.Movie, error) { + err := db.Model(&model.Movie{}).Clauses(clause.Returning{Columns: columns}).Where("room_id = ? AND id = ?", movie.RoomID, movie.ID).Updates(&movie).Error return &movie, err } diff --git a/internal/model/movie.go b/internal/model/movie.go index 3d067cd..6bec472 100644 --- a/internal/model/movie.go +++ b/internal/model/movie.go @@ -6,23 +6,23 @@ import ( type Movie struct { gorm.Model - Position uint `gorm:"not null"` - RoomID uint `gorm:"not null"` - MovieInfo + Position uint `gorm:"not null" json:"-"` + RoomID uint `gorm:"not null" json:"roomId"` + MovieInfo `gorm:"embedded"` } type MovieInfo struct { - BaseMovieInfo - PullKey string - CreatorID uint `gorm:"not null"` + BaseMovieInfo `gorm:"embedded"` + PullKey string `gorm:"varchar(16)" json:"pullKey"` + CreatorID uint `gorm:"not null" json:"creatorId"` } type BaseMovieInfo struct { - Url string `gorm:"varchar(4096)"` - Name string `gorm:"not null;varchar(256)"` - Live bool - Proxy bool - RtmpSource bool - Type string - Headers map[string]string `gorm:"serializer:json"` + Url string `gorm:"varchar(4096)" json:"url"` + Name string `gorm:"not null;varchar(256)" json:"name"` + Live bool `json:"live"` + Proxy bool `json:"proxy"` + RtmpSource bool `json:"rtmpSource"` + Type string `gorm:"varchar(32)" json:"type"` + Headers map[string]string `gorm:"serializer:json" json:"headers"` } diff --git a/internal/op/movie.go b/internal/op/movie.go index 3f868dc..715d25a 100644 --- a/internal/op/movie.go +++ b/internal/op/movie.go @@ -13,25 +13,48 @@ var movieCache = gcache.New(2048). LRU(). Build() -func GetMoviesByRoomID(roomID uint) ([]model.Movie, error) { +func GetAllMoviesByRoomID(roomID uint) ([]model.Movie, error) { i, err := movieCache.Get(roomID) if err == nil { return i.([]model.Movie), nil } - m, err := db.GetMoviesByRoomID(roomID) + m, err := db.GetAllMoviesByRoomID(roomID) if err != nil { return nil, err } return m, movieCache.SetWithExpire(roomID, m, time.Hour) } +func GetMoviesByRoomIDWithPage(roomID uint, page, pageSize int) ([]model.Movie, error) { + i, err := movieCache.Get(roomID) + if err != nil { + return nil, err + } + ms := i.([]model.Movie) + if page < 1 { + page = 1 + } + if pageSize < 1 { + pageSize = 1 + } + start := (page - 1) * pageSize + end := page * pageSize + if start > len(ms) { + start = len(ms) + } + if end > len(ms) { + end = len(ms) + } + return ms[start:end], nil +} + func GetMovieByID(roomID, id uint) (*model.Movie, error) { var m []model.Movie i, err := movieCache.Get(roomID) if err == nil { m = i.([]model.Movie) } else { - m, err = GetMoviesByRoomID(roomID) + m, err = GetAllMoviesByRoomID(roomID) if err != nil { return nil, err } @@ -43,3 +66,129 @@ func GetMovieByID(roomID, id uint) (*model.Movie, error) { } return nil, errors.New("movie not found") } + +func GetMoviesCountByRoomID(roomID uint) (int, error) { + ms, err := GetAllMoviesByRoomID(roomID) + return len(ms), err +} + +func DeleteMovieByID(roomID, id uint) error { + err := db.DeleteMovieByID(roomID, id) + if err != nil { + return err + } + i, err := movieCache.Get(roomID) + if err != nil { + return err + } + ms := i.([]model.Movie) + for i, v := range ms { + if v.ID == id { + ms = append(ms[:i], ms[i+1:]...) + break + } + } + return nil +} + +func UpdateMovie(movie model.Movie) error { + m, err := db.LoadAndUpdateMovie(movie) + if err != nil { + return err + } + i, err := movieCache.Get(movie.RoomID) + if err != nil { + return err + } + ms := i.([]model.Movie) + for i, v := range ms { + if v.ID == movie.ID { + ms[i] = *m + break + } + } + return nil +} + +func DeleteMoviesByRoomID(roomID uint) error { + err := db.DeleteMoviesByRoomID(roomID) + if err != nil { + return err + } + movieCache.Remove(roomID) + return nil +} + +func LoadAndDeleteMovieByID(roomID, id uint) (*model.Movie, error) { + m, err := db.LoadAndDeleteMovieByID(roomID, id) + if err != nil { + return nil, err + } + i, err := movieCache.Get(roomID) + if err != nil { + return nil, err + } + ms := i.([]model.Movie) + for i, v := range ms { + if v.ID == id { + ms = append(ms[:i], ms[i+1:]...) + break + } + } + return m, nil +} + +// data race +func CreateMovie(movie *model.Movie) error { + err := db.CreateMovie(movie) + if err != nil { + return err + } + i, err := movieCache.Get(movie.RoomID) + if err != nil { + movieCache.Set(movie.RoomID, []model.Movie{*movie}) + return nil + } + ms := i.([]model.Movie) + ms = append(ms, *movie) + movieCache.Set(movie.RoomID, ms) + return nil +} + +func GetMovieWithPullKey(roomID uint, pullKey string) (*model.Movie, error) { + i, err := movieCache.Get(roomID) + if err != nil { + return nil, err + } + ms := i.([]model.Movie) + for _, v := range ms { + if v.PullKey == pullKey { + return &v, nil + } + } + return nil, errors.New("movie not found") +} + +func SwapMoviePositions(roomID uint, movie1ID uint, movie2ID uint) error { + err := db.SwapMoviePositions(roomID, movie1ID, movie2ID) + if err != nil { + return err + } + i, err := movieCache.Get(roomID) + if err != nil { + return err + } + ms := i.([]model.Movie) + movie1I, movie2I := 0, 0 + for i, v := range ms { + if v.ID == movie1ID { + movie1I = i + } + if v.ID == movie2ID { + movie2I = i + } + } + ms[movie1I].Position, ms[movie2I].Position = ms[movie2I].Position, ms[movie1I].Position + ms[movie1I], ms[movie2I] = ms[movie2I], ms[movie1I] + return nil +} diff --git a/internal/op/room.go b/internal/op/room.go index b4d8feb..198874a 100644 --- a/internal/op/room.go +++ b/internal/op/room.go @@ -36,7 +36,6 @@ type Room struct { func (r *Room) lazyInit() { r.initOnce.Do(func() { - atomic.CompareAndSwapUint32(&r.version, 0, 1) r.current = newCurrent() r.hub = newHub(r.ID) a, err := rtmp.RtmpServer().NewApp(r.Name) @@ -85,7 +84,7 @@ func (r *Room) UpdateMovie(movieId uint, movie model.BaseMovieInfo) error { case m.Proxy && !movie.Proxy: m.PullKey = "" } - return db.UpdateMovie(*m) + return UpdateMovie(*m) } func (r *Room) InitMovie(movie *model.Movie) error { @@ -203,7 +202,7 @@ func (r *Room) AddMovie(m model.MovieInfo) error { return err } - return db.CreateMovie(movie) + return CreateMovie(movie) } func (r *Room) HasPermission(user *model.User, permission model.Permission) bool { @@ -251,24 +250,24 @@ func (r *Room) RemoveUserPermission(userID uint, permission model.Permission) er return db.RemoveUserPermission(r.ID, userID, permission) } -func (r *Room) GetMovies(conf ...db.GetMoviesConfig) ([]model.Movie, error) { - return db.GetMoviesByRoomID(r.ID, conf...) +func (r *Room) GetMoviesCount() (int, error) { + return GetMoviesCountByRoomID(r.ID) } -func (r *Room) GetMoviesCount() (int64, error) { - return db.GetMoviesCountByRoomID(r.ID) +func (r *Room) GetAllMoviesByRoomID() ([]model.Movie, error) { + return GetAllMoviesByRoomID(r.ID) } -func (r *Room) GetAllMoviesByRoomID() ([]model.Movie, error) { - return db.GetAllMoviesByRoomID(r.ID) +func (r *Room) GetMoviesByRoomIDWithPage(page, pageSize int) ([]model.Movie, error) { + return GetMoviesByRoomIDWithPage(r.ID, page, pageSize) } func (r *Room) GetMovieByID(id uint) (*model.Movie, error) { - return db.GetMovieByID(r.ID, id) + return GetMovieByID(r.ID, id) } func (r *Room) DeleteMovieByID(id uint) error { - m, err := db.LoadAndDeleteMovieByID(r.ID, id) + m, err := LoadAndDeleteMovieByID(r.ID, id) if err != nil { return err } @@ -300,7 +299,7 @@ func (r *Room) Current() *Current { } func (r *Room) ChangeCurrentMovie(id uint) error { - m, err := db.GetMovieByID(r.ID, id) + m, err := GetMovieByID(r.ID, id) if err != nil { return err } @@ -310,11 +309,11 @@ func (r *Room) ChangeCurrentMovie(id uint) error { } func (r *Room) SwapMoviePositions(id1, id2 uint) error { - return db.SwapMoviePositions(r.ID, id1, id2) + return SwapMoviePositions(r.ID, id1, id2) } func (r *Room) GetMovieWithPullKey(pullKey string) (*model.Movie, error) { - return db.GetMovieWithPullKey(r.ID, pullKey) + return GetMovieWithPullKey(r.ID, pullKey) } func (r *Room) RegClient(user *User, conn *websocket.Conn) (*Client, error) { diff --git a/internal/op/rooms.go b/internal/op/rooms.go index be3eedd..769cc28 100644 --- a/internal/op/rooms.go +++ b/internal/op/rooms.go @@ -2,6 +2,7 @@ package op import ( "errors" + "math/rand" "sync/atomic" "time" @@ -32,6 +33,7 @@ func initRoom(room *model.Room, conf ...RoomConf) (*Room, error) { r := &Room{ Room: *room, lastActive: time.Now().UnixMilli(), + version: rand.Uint32(), } for _, c := range conf { c(r) diff --git a/server/handlers/movie.go b/server/handlers/movie.go index dd52ad1..8793aec 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -13,7 +13,6 @@ import ( "github.com/gin-gonic/gin" "github.com/go-resty/resty/v2" "github.com/synctv-org/synctv/internal/conf" - "github.com/synctv-org/synctv/internal/db" dbModel "github.com/synctv-org/synctv/internal/model" "github.com/synctv-org/synctv/internal/op" "github.com/synctv-org/synctv/internal/rtmp" @@ -56,12 +55,28 @@ func MovieList(ctx *gin.Context) { return } - m, err := room.GetMovies(db.GetMoviesPage(int(page)), db.GetMoviesMax(int(max))) + m, err := room.GetMoviesByRoomIDWithPage(int(page), int(max)) if err != nil { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) return } + mresp := make([]model.MoviesResp, len(m)) + var creater string + for i, v := range m { + // get cteater + u, err := op.GetUserById(v.CreatorID) + if err == nil { + creater = u.Username + } + mresp[i] = model.MoviesResp{ + Id: v.ID, + Base: m[i].BaseMovieInfo, + PullKey: v.PullKey, + Creater: creater, + } + } + i, err := room.GetMoviesCount() if err != nil { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) @@ -71,7 +86,7 @@ func MovieList(ctx *gin.Context) { ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{ "current": room.Current(), "total": i, - "movies": m, + "movies": mresp, })) } @@ -94,12 +109,28 @@ func Movies(ctx *gin.Context) { return } - m, err := room.GetMovies(db.GetMoviesPage(int(page)), db.GetMoviesMax(int(max))) + m, err := room.GetMoviesByRoomIDWithPage(int(page), int(max)) if err != nil { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) return } + mresp := make([]model.MoviesResp, len(m)) + var creater string + for i, v := range m { + // get cteater + u, err := op.GetUserById(v.CreatorID) + if err == nil { + creater = u.Username + } + mresp[i] = model.MoviesResp{ + Id: v.ID, + Base: m[i].BaseMovieInfo, + PullKey: v.PullKey, + Creater: creater, + } + } + i, err := room.GetMoviesCount() if err != nil { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) @@ -108,7 +139,7 @@ func Movies(ctx *gin.Context) { ctx.JSON(http.StatusOK, model.NewApiDataResp(gin.H{ "total": i, - "movies": m, + "movies": mresp, })) } diff --git a/server/handlers/room.go b/server/handlers/room.go index cfbc723..1cbc16c 100644 --- a/server/handlers/room.go +++ b/server/handlers/room.go @@ -36,19 +36,19 @@ func CreateRoom(ctx *gin.Context) { return } - r, err := user.CreateRoom(req.RoomId, req.Password, db.WithSetting(req.Setting)) + r, err := user.CreateRoom(req.RoomName, req.Password, db.WithSetting(req.Setting)) if err != nil { ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(err)) return } - _, err = op.LoadRoom(r) + room, err := op.LoadRoom(r) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return } - token, err := middlewares.NewAuthUserToken(user) + token, err := middlewares.NewAuthRoomToken(user, room) if err != nil { ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewApiErrorResp(err)) return diff --git a/server/model/movie.go b/server/model/movie.go index 5591357..58a51ee 100644 --- a/server/model/movie.go +++ b/server/model/movie.go @@ -107,3 +107,10 @@ func (s *SwapMovieReq) Validate() error { } return nil } + +type MoviesResp struct { + Id uint `json:"id"` + Base model.BaseMovieInfo `json:"base"` + PullKey string `json:"pullKey"` + Creater string `json:"creater"` +} diff --git a/server/model/room.go b/server/model/room.go index 394d7af..6acdde3 100644 --- a/server/model/room.go +++ b/server/model/room.go @@ -13,9 +13,9 @@ import ( ) var ( - ErrEmptyRoomId = errors.New("empty room id") - ErrRoomIdTooLong = errors.New("room id too long") - ErrRoomIdHasInvalidChar = errors.New("room id has invalid char") + ErrEmptyRoomName = errors.New("empty room name") + ErrRoomNameTooLong = errors.New("room name too long") + ErrRoomNameHasInvalidChar = errors.New("room name has invalid char") ErrPasswordTooLong = errors.New("password too long") ErrPasswordHasInvalidChar = errors.New("password has invalid char") @@ -38,7 +38,7 @@ func (f FormatEmptyPasswordError) Error() string { } type CreateRoomReq struct { - RoomId string `json:"roomId"` + RoomName string `json:"roomName"` Password string `json:"password"` Setting model.Setting `json:"setting"` } @@ -48,12 +48,12 @@ func (c *CreateRoomReq) Decode(ctx *gin.Context) error { } func (c *CreateRoomReq) Validate() error { - if c.RoomId == "" { - return ErrEmptyRoomId - } else if len(c.RoomId) > 32 { - return ErrRoomIdTooLong - } else if !alphaNumChineseReg.MatchString(c.RoomId) { - return ErrRoomIdHasInvalidChar + if c.RoomName == "" { + return ErrEmptyRoomName + } else if len(c.RoomName) > 32 { + return ErrRoomNameTooLong + } else if !alphaNumChineseReg.MatchString(c.RoomName) { + return ErrRoomNameHasInvalidChar } if c.Password != "" { @@ -89,7 +89,7 @@ func (l *LoginRoomReq) Decode(ctx *gin.Context) error { func (l *LoginRoomReq) Validate() error { if l.RoomId == 0 { - return ErrEmptyRoomId + return ErrEmptyRoomName } return nil