package room import ( "bet24.com/log" "bet24.com/servers/common" IRoomMgr "bet24.com/servers/micros/audioroom/handler/interface" pb "bet24.com/servers/micros/audioroom/proto" "bet24.com/servers/micros/audioroom/transaction/database" userservices "bet24.com/servers/micros/userservices/proto" "bet24.com/servers/zego" "strconv" "sync" "time" ) const room_Seconds = 600 // 过期时长(秒) type Room struct { roomMgr IRoomMgr.RoomMgr pb.RoomInfo // 房间基本信息 pb.RoomExtInfo // 房间扩展信息 pb.EnterCondition // 进入条件 onlineUsers []int // 在线用户 members []pb.UserRoomInfo // 成员用户 mics []pb.MicInfo // 麦位 blackList []pb.BlackInfo // 黑名单 permissionList []pb.PermissionInfo // 权限列表 taskList []*pb.RoomTask // 房间任务 collectList []*pb.RoomCollect // 房间收集 micApplyList []int // 上麦申请列表 gameRoomList []*pb.GameRoomInfo // 游戏房间列表 micLogList []pb.MicLog // 麦位日志 lock *sync.RWMutex timeStamp int // 时间戳(用于清理过期数据) } func NewRoom(roomId int, mgr IRoomMgr.RoomMgr) *Room { ret := new(Room) ret.RoomId = roomId ret.roomMgr = mgr ret.lock = &sync.RWMutex{} ret.timeStamp = common.GetTimeStamp() + room_Seconds //log.Debug("room.newRoom roomId=%d", roomId) if !ret.loadRoom() { return ret } go func() { ret.loadEnterCondition() ret.loadMembers() ret.loadBlackList() ret.loadPermission(true) ret.loadTask() ret.loadCollect() }() return ret } // 获取房间信息 func (this *Room) loadRoom() bool { // DB:房间信息 info := database.GetRoom(this.RoomId) if info.RoomId <= 0 { return false } // 获取麦位信息 mics := database.GetMicInfo(info.RoomId) if len(mics) <= 0 { mics = make([]pb.MicInfo, info.MicCount) } this.RoomInfo = info this.mics = mics return true } // 获取扩展信息 func (this *Room) GetExtInfo() *pb.RoomExtInfo { // 还没有扩展信息 if this.RoomExtInfo.UpdateTime == 0 { this.RoomExtInfo = database.GetExtInfo(this.RoomId) } // 判断是否过期 if common.IsSameDay(this.RoomExtInfo.UpdateTime, common.GetTimeStamp()) { return &this.RoomExtInfo } this.RoomExtInfo.DayExps = 0 this.RoomExtInfo.UpdateTime = common.GetTimeStamp() return &this.RoomExtInfo } // 获取房间进入条件 func (this *Room) loadEnterCondition() { this.EnterCondition = database.GetEnterCondition(this.RoomId) return } // 是否过期房间 func (this *Room) IsExpire() bool { if this.timeStamp >= common.GetTimeStamp() { //log.Debug("room.checkExpire roomId=%d 有效期时间 %s", this.RoomId, time.Unix(int64(this.timeStamp), 0).Format(common.Layout)) this.checkOnlineUser() return false } if len(this.onlineUsers) > 0 { //log.Debug("room.checkExpire roomId=%d 已过期,仍有在线用户 %+v,有效期时间 %s", // this.RoomId, this.onlineUsers, time.Unix(int64(this.timeStamp), 0).Format(common.Layout)) this.checkOnlineUser() return false } log.Debug("room.checkExpire roomId=%d 过期房间清理", this.RoomId) return true } // 更新时间戳 func (this *Room) UpdateTimeStamp() { this.timeStamp = common.GetTimeStamp() + room_Seconds return } // sdk服务器 ==> 检查在线 func (this *Room) checkOnlineUser() { // TODO:暂时不调用 return log.Debug("room.checkOnlineUser roomId=%d 检查", this.RoomId) // 房间id roomId := strconv.Itoa(this.RoomId) // 获取在线用户数 userCount := zego.GetUserNum(roomId) // 判断在线人数 if this.OnlineCount == userCount { return } // 人数不相等,需要去同步 var onlineUsers []int // 获取在线用户列表 list := zego.GetUserList(roomId) for _, v := range list { uid, err := strconv.Atoi(v.UserId) if err != nil { log.Error("room.checkOnlineUser roomId=%s info=%+v err %v", roomId, v, err) continue } // 在线用户 onlineUsers = append(onlineUsers, uid) } // 同步在线用户 this.OnlineCount = userCount this.onlineUsers = onlineUsers // 用户通知在线 go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{ Reason: pb.Notify_Reason_User_Online, UserId: -1, }) log.Debug("room.checkOnlineUser 同步sdk服务器在线用户(%d)人,用户列表%v", this.OnlineCount, this.onlineUsers) } // 获取房间基本信息 func (this *Room) GetRoomInfo() *pb.RoomInfo { return &this.RoomInfo } // 是否有效房间 func (this *Room) IsValid() bool { return this.UserId > 0 } // 获取房间任务列表 func (this *Room) GetRoomTaskList() []*pb.RoomTask { return this.taskList } // 是否允许进入房间 func (this *Room) IsEnterRoom(userId int, password string) int { // 管理员直接进入 if this.UserId == userId { return 1 } // 会员用户 for _, v := range this.members { if v.UserId == userId { return 1 } } // 游客,需要判断条件 // 1=只能邀请进入 if this.InviteOnly { return 11 } // 2=是否隐藏 if this.IsHide { return 14 } // 3=是否黑名单 if this.IsBlack(userId, pb.BlackType_Room) { return 13 } // 4=房间密码 if this.PwdExpire > common.GetTimeStamp() { // 校验密码 if password != this.Password { return 12 } } return 1 } // 进入房间 func (this *Room) EnterRoom(userId int) bool { // 在线用户 for _, uid := range this.onlineUsers { if uid == userId { return true } } this.onlineUsers = append(this.onlineUsers, userId) this.OnlineCount = len(this.onlineUsers) go func() { roleId := this.GetMemberInfo(userId).RoleId this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{ Reason: pb.Notify_Reason_User_Online, NotifyUserId: userId, UserId: userId, OldRoleId: roleId, NewRoleId: roleId, }) }() return true } // 退出房间 func (this *Room) ExitRoom(userId int) { for i := 0; i < len(this.onlineUsers); i++ { if this.onlineUsers[i] != userId { continue } this.onlineUsers = append(this.onlineUsers[:i], this.onlineUsers[i+1:]...) break } this.OnlineCount = len(this.onlineUsers) go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{ Reason: pb.Notify_Reason_User_Offline, NotifyUserId: userId, UserId: userId, }) // 删除申请处理 this.delMicApply(userId) return } // 创建房间 func (this *Room) CreateRoom(userId int, roomName, country, language, ipAddress, roomImg, announce, tag string) { // 封面为空信息,取头像 if roomImg == "" { if u := userservices.GetUserInfo(userId); u != nil { roomImg = u.FaceUrl } } if country == "" { country = "SAR" } // 初始化房间信息 info := pb.RoomInfo{ RoomId: userId, RoomName: roomName, RoomImg: roomImg, UserId: userId, Family: "Club", Country: country, Language: language, MicCount: mic_defaultCount, MicMode: pb.OnMic_All, Announce: announce, Tag: tag, MemberCount: 1, Crdate: common.GetNowTimeStr(), Level: 1, } this.RoomInfo = info this.mics = make([]pb.MicInfo, info.MicCount) this.members = append(this.members, pb.UserRoomInfo{ UserId: userId, RoomId: userId, RoleId: pb.Role_Administrator, Crdate: common.GetNowTimeStr(), }) this.loadPermission(false) // DB:创建房间 go func() { // 创建房间 database.CreateRoom(&this.RoomInfo) // 保存麦位信息 database.SetMicInfo(this.RoomId, this.mics) this.loadTask() }() return } // 修改房间封面 func (this *Room) UpdateRoomImg(roomImg string) { this.RoomImg = roomImg go func() { // 修改房间 database.UpdateRoom(&this.RoomInfo) // 发送通知 this.notify(pb.Notify_Action_Refresh_Room, pb.ReasonData{}) }() return } // 修改房间信息 func (this *Room) UpdateRoom(userId int, r *pb.RoomInfo) int { if this.UserId != userId { return 11 } log.Debug("room.updateRoom userId=%d ==> %+v", userId, r) this.RoomName = r.RoomName this.Family = r.Family this.Country = r.Country this.Language = r.Language // 麦位发生变化 if this.MicCount != r.MicCount { log.Debug("room.updateRoom userId=%d this.MicCount=%d r.MicCount=%d", userId, this.MicCount, r.MicCount) if this.MicCount < r.MicCount { // 扩麦处理 log.Debug("room.updateRoom userId=%d 扩麦处理", userId) // 新增麦位 for i := r.MicCount - 1; i >= this.MicCount; i-- { this.mics = append(this.mics, pb.MicInfo{ UserId: mic_idle, StreamId: "", }) } } else if this.MicCount > r.MicCount { // 缩麦处理 log.Debug("room.updateRoom userId=%d 缩麦处理", userId) // 踢麦且发送通知 for i := r.MicCount; i < this.MicCount; i++ { if this.mics[i].UserId > mic_idle { roomId := strconv.Itoa(this.RoomId) uid := strconv.Itoa(this.mics[i].UserId * -1) // sdk服务器 ==> 删除房间流 code, message := zego.MuteUser(roomId, uid, this.mics[i].StreamId) log.Debug("room.offTheMic(zego.MuteUser) i=%d userId=%s roomId=%s streamId=%s code=%d message=%s", i, uid, roomId, this.mics[i].StreamId, code, message) // 麦位通知 //go this.notify(this.mics[i].UserId, pb.Notify_Action_Refresh_Mic, pb.ReasonData{ // Reason: pb.Notify_Reason_Mic_Change, // SN: i, //}) } } log.Debug("room.updateRoom 缩麦前 this.Mics=%+v", this.mics) // 缩麦 this.mics = this.mics[:r.MicCount] log.Debug("room.updateRoom 缩麦后 this.Mics=%+v", this.mics) } // 麦位通知 this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{Reason: pb.Notify_Reason_Mic_Change}) } this.MicCount = r.MicCount // 申请模式切换到其他模式,需要清理麦位申请列表 if this.MicMode == pb.OnMic_Apply && r.MicMode != pb.OnMic_Apply { this.delMicApply(0) } this.MicMode = r.MicMode this.JoinFee = r.JoinFee this.Announce = r.Announce this.Tag = r.Tag // DB:更新数据库 go func() { // 修改房间 database.UpdateRoom(&this.RoomInfo) var mics []pb.MicInfo for _, v := range this.mics { if v.UserId == mic_lock { mics = append(mics, v) } else { mics = append(mics, pb.MicInfo{ UserId: mic_idle, StreamId: "", }) } } // 保存麦位信息 database.SetMicInfo(this.RoomId, mics) }() // 发送通知 go this.notify(pb.Notify_Action_Refresh_Room, pb.ReasonData{}) return 1 } // 在线用户列表 func (this *Room) GetOnlineUsers() []int { return this.onlineUsers } // 查询用户信息 func (this *Room) SearchUser(userId int) pb.UserRoomInfo { // 会员 for _, v := range this.members { if v.UserId == userId { return v } } // 黑名单 for _, v := range this.blackList { if v.UserId == userId { return pb.UserRoomInfo{ UserId: userId, RoomId: this.RoomId, RoleId: pb.Role_Guest, Crdate: common.GetNowTimeStr(), } } } return pb.UserRoomInfo{} } // 获取房间进入条件 func (this *Room) GetEnterCondition(userId int) pb.EnterCondition { // 只有管理员才能设置 if this.UserId != userId { return pb.EnterCondition{} } return this.EnterCondition } // 设置房间进入条件 func (this *Room) SetEnterCondition(userId int, inviteOnly bool, password string, seconds int, isHide bool) int { // 只有管理员才能设置 if this.UserId != userId { return 11 } pwdExpire := 0 if len(password) > 0 { pwdExpire = common.GetTimeStamp() + seconds } // 修改数据 this.EnterCondition = pb.EnterCondition{ InviteOnly: inviteOnly, Password: password, PwdExpire: pwdExpire, IsHide: isHide, } // 数据库操作 go database.SetEnterCondition(this.RoomId, this.EnterCondition) return 1 } // 通知房间 func (this *Room) NotifyRoom() { go this.notify(pb.Notify_Action_Refresh_Room, pb.ReasonData{}) } // 设置屏幕锁(1=锁定,0=解锁) func (this *Room) SetScreenLock(userId, screenLock int) int { // 是否管理员 if !this.isAdmin(userId) { return -1 } // 锁屏广播 go this.notify(pb.Notify_Action_Screen_Lock, pb.ReasonData{ Reason: pb.Notify_Reason_Screen_Lock, UserId: userId, ScreenLock: screenLock, }) this.RoomExtInfo.ScreenLock = screenLock this.RoomExtInfo.UpdateTime = common.GetTimeStamp() go database.UpdateExtInfo(this.RoomId, &this.RoomExtInfo) return 1 } // 是否禁止发言(true:禁止) func (this *Room) IsBannedSpeak(userId int) bool { if this.RoomExtInfo.ScreenLock == 0 { return false } // 是否管理员 if this.isAdmin(userId) { return false } if this.isOnMic(userId) { return false } return true } // 打印房间 func (this *Room) DumpRoom() { log.Debug("房间ID(%d),过期时间[%s]:", this.RoomId, time.Unix(int64(this.timeStamp), 0).Format(common.Layout)) log.Debug(" 基本信息:%+v ", this.RoomInfo) log.Debug(" 房间进入条件:%+v", this.EnterCondition) log.Debug(" 在线用户(%d)人:%+v", len(this.onlineUsers), this.onlineUsers) log.Debug(" 成员用户(%d)人:%+v", len(this.members), this.members) log.Debug(" 黑名单用户(%d)个:%+v", len(this.blackList), this.blackList) log.Debug(" 权限列表(%d)个:%+v", len(this.permissionList), this.permissionList) log.Debug(" 麦位用户(%d)个:%+v", len(this.mics), this.mics) log.Debug(" 任务列表:") for _, v := range this.taskList { log.Debug(" %+v", v) } log.Debug(" 收集列表:") for _, v := range this.collectList { log.Debug(" %+v", v) } log.Debug(" 游戏房间列表(%d)个:", len(this.gameRoomList)) for _, v := range this.gameRoomList { log.Debug(" %+v", v) } log.Debug(" 麦位申请列表(%d)个:", len(this.micApplyList)) for _, v := range this.micApplyList { log.Debug(" %+v", v) } log.Debug(" 麦位日志列表(%d)个:", len(this.micLogList)) for _, v := range this.micLogList { log.Debug(" %+v", v) } log.Debug("###############################################") } // 获取上麦的数量 func (this *Room) GetUpMicCount() int { return pb.AdminGetUpMicCount(this.mics) }