mirror of https://github.com/synctv-org/synctv
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.
220 lines
4.7 KiB
Go
220 lines
4.7 KiB
Go
package room
|
|
|
|
import (
|
|
"errors"
|
|
"math/rand"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/gorilla/websocket"
|
|
"github.com/zijiren233/gencontainer/dllist"
|
|
"github.com/zijiren233/stream"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type User struct {
|
|
room *Room
|
|
name string
|
|
password []byte
|
|
version uint64
|
|
admin bool
|
|
lastAct int64
|
|
}
|
|
|
|
var (
|
|
ErrUsernameEmpty = errors.New("user name is empty")
|
|
ErrUserPasswordEmpty = errors.New("user password is empty")
|
|
)
|
|
|
|
type UserConf func(*User)
|
|
|
|
func WithUserVersion(version uint64) UserConf {
|
|
return func(u *User) {
|
|
u.version = version
|
|
}
|
|
}
|
|
|
|
func WithUserAdmin(admin bool) UserConf {
|
|
return func(u *User) {
|
|
u.admin = admin
|
|
}
|
|
}
|
|
|
|
func NewUser(id string, password string, room *Room, conf ...UserConf) (*User, error) {
|
|
if id == "" {
|
|
return nil, ErrUsernameEmpty
|
|
}
|
|
if password == "" {
|
|
return nil, ErrUserPasswordEmpty
|
|
}
|
|
hashedPassword, err := bcrypt.GenerateFromPassword(stream.StringToBytes(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
u := &User{
|
|
room: room,
|
|
name: id,
|
|
password: hashedPassword,
|
|
lastAct: time.Now().UnixMicro(),
|
|
}
|
|
for _, c := range conf {
|
|
c(u)
|
|
}
|
|
if u.version == 0 {
|
|
u.version = rand.New(rand.NewSource(time.Now().UnixNano())).Uint64()
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
func (u *User) LastAct() int64 {
|
|
return atomic.LoadInt64(&u.lastAct)
|
|
}
|
|
|
|
func (u *User) LastActTime() time.Time {
|
|
return time.UnixMicro(u.LastAct())
|
|
}
|
|
|
|
func (u *User) UpdateLastAct() int64 {
|
|
return atomic.SwapInt64(&u.lastAct, time.Now().UnixMicro())
|
|
}
|
|
|
|
func (u *User) Version() uint64 {
|
|
return atomic.LoadUint64(&u.version)
|
|
}
|
|
|
|
func (u *User) CheckVersion(version uint64) bool {
|
|
return u.Version() == version
|
|
}
|
|
|
|
func (u *User) SetVersion(version uint64) {
|
|
atomic.StoreUint64(&u.version, version)
|
|
}
|
|
|
|
func (u *User) updateVersion() uint64 {
|
|
return atomic.AddUint64(&u.version, 1)
|
|
}
|
|
|
|
func (u *User) CheckPassword(password string) bool {
|
|
err := bcrypt.CompareHashAndPassword(u.password, stream.StringToBytes(password))
|
|
return err == nil
|
|
}
|
|
|
|
func (u *User) SetPassword(password string) error {
|
|
hashedPassword, err := bcrypt.GenerateFromPassword(stream.StringToBytes(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
u.password = hashedPassword
|
|
u.updateVersion()
|
|
return nil
|
|
}
|
|
|
|
func (u *User) CloseHub() {
|
|
c, loaded := u.room.hub.clients.LoadAndDelete(u.name)
|
|
if loaded {
|
|
c.Close()
|
|
}
|
|
}
|
|
|
|
func (u *User) IsRoot() bool {
|
|
return u.room.rootUser == u
|
|
}
|
|
|
|
func (u *User) Name() string {
|
|
return u.name
|
|
}
|
|
|
|
func (u *User) Room() *Room {
|
|
return u.room
|
|
}
|
|
|
|
func (u *User) IsAdmin() bool {
|
|
return u.admin
|
|
}
|
|
|
|
func (u *User) SetAdmin(admin bool) {
|
|
u.admin = admin
|
|
}
|
|
|
|
func (u *User) NewMovie(url string, name string, type_ string, live bool, proxy bool, rtmpSource bool, headers map[string][]string, conf ...MovieConf) (*Movie, error) {
|
|
return u.NewMovieWithBaseMovie(BaseMovie{
|
|
Url: url,
|
|
Name: name,
|
|
Live: live,
|
|
Proxy: proxy,
|
|
RtmpSource: rtmpSource,
|
|
Type: type_,
|
|
Headers: headers,
|
|
}, conf...)
|
|
}
|
|
|
|
func (u *User) NewMovieWithBaseMovie(baseMovie BaseMovie, conf ...MovieConf) (*Movie, error) {
|
|
conf = append(conf, WithCreator(u))
|
|
return NewMovieWithBaseMovie(atomic.AddUint64(&u.room.mid, 1), baseMovie, conf...)
|
|
}
|
|
|
|
func (u *User) Movie(id uint64) (*MovieInfo, error) {
|
|
u.room.movies.lock.RLock()
|
|
defer u.room.movies.lock.RUnlock()
|
|
|
|
m, err := u.room.movies.GetMovie(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
movie := &MovieInfo{
|
|
Id: m.Id(),
|
|
Url: m.Url,
|
|
Name: m.Name,
|
|
Live: m.Live,
|
|
Proxy: m.Proxy,
|
|
RtmpSource: m.RtmpSource,
|
|
Type: m.Type,
|
|
Headers: m.Headers,
|
|
PullKey: m.PullKey,
|
|
CreateAt: m.CreateAt,
|
|
LastEditAt: m.LastEditAt,
|
|
Creator: m.Creator().Name(),
|
|
}
|
|
if movie.Proxy && u.name != movie.Creator {
|
|
m.Headers = nil
|
|
}
|
|
return movie, nil
|
|
}
|
|
|
|
func (u *User) MovieList() []*MovieInfo {
|
|
u.room.movies.lock.RLock()
|
|
defer u.room.movies.lock.RUnlock()
|
|
|
|
movies := make([]*MovieInfo, 0, u.room.movies.l.Len())
|
|
u.room.movies.range_(func(e *dllist.Element[*Movie]) bool {
|
|
m := &MovieInfo{
|
|
Id: e.Value.Id(),
|
|
Url: e.Value.Url,
|
|
Name: e.Value.Name,
|
|
Live: e.Value.Live,
|
|
Proxy: e.Value.Proxy,
|
|
RtmpSource: e.Value.RtmpSource,
|
|
Type: e.Value.Type,
|
|
Headers: e.Value.Headers,
|
|
PullKey: e.Value.PullKey,
|
|
CreateAt: e.Value.CreateAt,
|
|
LastEditAt: e.Value.LastEditAt,
|
|
Creator: e.Value.Creator().Name(),
|
|
}
|
|
if e.Value.Proxy && u.name != m.Creator {
|
|
m.Headers = nil
|
|
}
|
|
movies = append(movies, m)
|
|
return true
|
|
})
|
|
return movies
|
|
}
|
|
|
|
func (u *User) RegClient(conn *websocket.Conn) (*Client, error) {
|
|
return u.room.RegClient(u, conn)
|
|
}
|
|
|
|
func (u *User) Broadcast(msg Message, conf ...BroadcastConf) error {
|
|
return u.room.Broadcast(msg, append(conf, WithSender(u.name))...)
|
|
}
|