package friend import ( "encoding/json" "os" "sync" "time" "bet24.com/log" "bet24.com/servers/common" "bet24.com/servers/coreservice/client" notification "bet24.com/servers/micros/notification/proto" platformconfig "bet24.com/servers/micros/platformconfig/proto" user "bet24.com/servers/micros/userservices/proto" vipservice "bet24.com/servers/micros/userservices/proto" ) const config_key = "friend_config" type friendmgr struct { lock *sync.RWMutex userList map[int]*user_friend MaxFriendCount int // 最大好友上限 offlineList map[int]int // map[userId]expire } func newFriendMgr() *friendmgr { log.Debug("friend manager running") fm := &friendmgr{} fm.userList = make(map[int]*user_friend) fm.offlineList = make(map[int]int) fm.lock = &sync.RWMutex{} fm.checkDayRefresh() fm.checkOfflineUser() fm.loadRedisConfig() return fm } func (fm *friendmgr) checkDayRefresh() { ticker := time.NewTicker(10 * time.Minute) go func(t *time.Ticker) { lastCheck := common.GetTimeStamp() for { //循环 select { case <-t.C: now := common.GetTimeStamp() if !common.IsSameDay(lastCheck, now) { fm.refreshUserList() } lastCheck = now } } }(ticker) } func (fm *friendmgr) checkOfflineUser() { time.AfterFunc(1*time.Minute, fm.checkOfflineUser) ts := common.GetTimeStamp() var toRemove []int fm.lock.RLock() for userId, expire := range fm.offlineList { if expire <= ts { toRemove = append(toRemove, userId) } } fm.lock.RUnlock() if len(toRemove) == 0 { return } log.Debug("friendmgr.checkOfflineUser toRemove = %v", toRemove) for _, userId := range toRemove { fm.onUserExit(userId) fm.lock.Lock() delete(fm.offlineList, userId) fm.lock.Unlock() } } // 0点过后去数据库刷新在线玩家数据 func (fm *friendmgr) refreshUserList() { fm.lock.RLock() for _, v := range fm.userList { v.refreshGift() } fm.lock.RUnlock() } // 加载redis配置 func (fm *friendmgr) loadRedisConfig() { go time.AfterFunc(5*time.Minute, fm.loadRedisConfig) if data := platformconfig.GetConfig(config_key); data != "" { if err := json.Unmarshal([]byte(data), &fm); err == nil { return } return } data, err := os.ReadFile("fishconf/friend_config.json") if err != nil { log.Release("read config failed fishconf/friend_config.json %v", err) } if err = json.Unmarshal(data, &fm); err == nil { platformconfig.SetConfig(config_key, string(data)) return } log.Release("Unmarshal config [%s] err:%v", string(data), err) } func (fm *friendmgr) onUserEnter(userId int) { u := newUserFriend(userId) fm.lock.Lock() fm.userList[userId] = u fm.lock.Unlock() fm.setUserStatus(userId, 1, "") } func (fm *friendmgr) onUserExit(userId int) { fm.setUserStatus(userId, 0, "") fm.lock.Lock() delete(fm.userList, userId) fm.lock.Unlock() } func (fm *friendmgr) searchInfo(userId, toUserId int, toNickName string) []*SearchInfo { list := searchInfo(userId, toUserId, toNickName) for i := 0; i < len(list); i++ { list[i].IsFriend = fm.ifFriend(userId, list[i].FriendID) if fm.isOnline(list[i].FriendID) { list[i].GameStatus = GameStatus_Online } u := user.GetUserInfo(list[i].FriendID) if u == nil { // log.Error("friendmgr.searchInfo userId=%d", list[i].FriendID) continue } l := user.GetUserLevel(list[i].FriendID) list[i].NickName = u.NickName list[i].Sex = u.Sex list[i].FaceID = u.FaceId list[i].FaceUrl = u.FaceUrl list[i].UserWords = u.UserWords list[i].VipLevel = u.Vip list[i].VipExpire = u.VipExpire list[i].PrivateRoomCount = u.PrivateRoomCount list[i].Currency = u.Currency list[i].Level = l.Level list[i].Gold = u.Gold list[i].Decorations = u.Decorations list[i].Charm = u.Charm } return list } func (fm *friendmgr) getFriendList(userId int) []*FriendItem { fm.lock.RLock() l, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { return nil } var list []*FriendItem for _, v := range l.FriendList { u := user.GetUserInfo(v.FriendID) if u == nil { log.Error("friendmgr.getFriendList userId=%d ==> %+v", v.FriendID, v) continue } list = append(list, &FriendItem{ FriendBase: FriendBase{ FriendID: v.FriendID, NickName: u.NickName, Sex: u.Sex, FaceID: u.FaceId, FaceUrl: u.FaceUrl, UserWords: u.UserWords, GameStatus: v.GameStatus, VipLevel: u.Vip, VipExpire: u.VipExpire, PrivateRoomCount: u.PrivateRoomCount, Decorations: u.Decorations, }, IsGift: v.IsGift, GiftTime: v.GiftTime, IsGive: v.IsGive, GiveTime: v.GiveTime, }) } return list } // 申请好友 0=不能申请自己 1=申请成功 2=已经是好友 3=已经申请,待审核 func (fm *friendmgr) friendApply(userId, targetUserID int) int { //自己不能申请自己 if userId == targetUserID { return CANNOT_ADD_ONESELF } fm.lock.RLock() u, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { log.Debug("friendmgr.friendApply userId [%d] not exist", userId) return CANNOT_ADD_ONESELF } return u.friendApply(targetUserID) } func (fm *friendmgr) delFriend(userId, targetUserID int) []*FriendItem { var list []*FriendItem fm.lock.RLock() u, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { list = nil } else { list, ok = u.delFriend(targetUserID) } if ok { go client.RemoveChannelChat(userId, targetUserID) } for _, v := range list { u := user.GetUserInfo(v.FriendID) if u == nil { log.Error("friendmgr.delFriend userId=%d ==> %+v", v.FriendID, v) continue } v.NickName = u.NickName v.Sex = u.Sex v.FaceID = u.FaceId v.FaceUrl = u.FaceUrl v.UserWords = u.UserWords v.VipLevel = u.Vip v.VipExpire = u.VipExpire v.PrivateRoomCount = u.PrivateRoomCount v.Decorations = u.Decorations } return list } func (fm *friendmgr) friendVerifyList(userId int) []*FriendBase { fm.lock.RLock() u, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { return nil } var list []*FriendBase for _, v := range u.VerifyList { u := user.GetUserInfo(v.FriendID) if u == nil { log.Error("friendmgr.friendVerifyList userId=%d ==> %+v", v.FriendID, v) continue } list = append(list, &FriendBase{ FriendID: v.FriendID, NickName: u.NickName, Sex: u.Sex, FaceID: u.FaceId, FaceUrl: u.FaceUrl, UserWords: u.UserWords, GameStatus: v.GameStatus, VipLevel: u.Vip, VipExpire: u.VipExpire, PrivateRoomCount: u.PrivateRoomCount, Decorations: u.Decorations, }) } return list } // apply 状态 0=未处理 1=同意 2=拒绝 func (fm *friendmgr) friendHandleApply(userId, targetUserID, apply int) []*FriendItem { fm.lock.RLock() u, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { return nil } var list []*FriendItem list = u.friendHandleApply(targetUserID, apply) for _, v := range list { u := user.GetUserInfo(v.FriendID) if u == nil { log.Error("friendmgr.friendHandleApply userId=%d ==> %+v", v.FriendID, v) continue } v.NickName = u.NickName v.Sex = u.Sex v.FaceID = u.FaceId v.FaceUrl = u.FaceUrl v.UserWords = u.UserWords v.VipLevel = u.Vip v.VipExpire = u.VipExpire v.PrivateRoomCount = u.PrivateRoomCount v.Decorations = u.Decorations } return list } // 向好友赠送礼物 func (fm *friendmgr) friendGiveGift(userId, targetUserID int) int { fm.lock.RLock() u, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { return 0 } return u.friendGiveGift(targetUserID) } func (fm *friendmgr) notifyGift(userId, toUserId int) { fm.lock.RLock() u, ok := fm.userList[toUserId] fm.lock.RUnlock() if !ok { return } //好友也在线,刷新礼物状态 for _, f := range u.FriendList { if f.FriendID == userId { f.IsGift = GIFT_STATUS_HAVE break } } go func(toUserId int) { buf, _ := json.Marshal(notification.NotificationFriend{ NotifyId: Friend_Notify_Gift, }) //发送通知 notification.AddNotification(toUserId, notification.Notification_Friend, string(buf)) }(toUserId) } func (fm *friendmgr) friendGetGift(userId, targetUserID int, ipAddress string) int { fm.lock.RLock() u, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { return 0 } return u.friendGetGift(targetUserID, ipAddress) } func (fm *friendmgr) setUserStatus(userId, isOnline int, serverName string) { // 离线 status := GameStatus_Offline // 在线 if isOnline == 1 { if serverName == "广告大厅" || serverName == "游戏大厅" { // 大厅 status = GameStatus_Hall } else if serverName != "" { // 游戏中 status = GameStatus_Playing } else { status = GameStatus_Online } } else if isOnline == 0 && serverName != "" { status = GameStatus_Hall } // log.Debug("setUserStatus userId=%d isOnline=%d serverName=%s status=%s", userId, isOnline, serverName, status) fm.lock.RLock() u, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { //log.Debug("friendmgr.setUserStatus userId [%d] not exist", userId) return } go func() { // 延迟2秒 time.Sleep(2 * time.Second) // 通知我的好友 for _, f := range u.FriendList { fm.lock.RLock() friend, ok := fm.userList[f.FriendID] fm.lock.RUnlock() if !ok { continue } friend.setUserStatus(userId, status) } // 通知我待通过的好友 buf, _ := json.Marshal(notification.NotificationFriend{ NotifyId: Friend_Notify_Status, UserId: userId, Data: status, }) fm.lock.RLock() for _, u := range fm.userList { if u.UserID == userId { continue } for _, v := range u.ApplyList { v.GameStatus = status //发送通知 go notification.AddNotification(u.UserID, notification.Notification_Friend, string(buf)) break } } fm.lock.RUnlock() }() } func (fm *friendmgr) isOnline(userId int) bool { fm.lock.RLock() defer fm.lock.RUnlock() _, ok := fm.userList[userId] return ok } // 刷新好友及申请列表 func (fm *friendmgr) refreshFriends(userId int, friendFlag, applyFlag, verifyFlag bool, fromUserId int, apply string) bool { var ( giveTimes int friendlist []*FriendItem applylist []*FriendBase verifylist []*FriendBase ) //获取在线好友数据 fm.lock.RLock() l, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { return false } //从数据库获取好友列表 if friendFlag { giveTimes, friendlist = getList(userId) for _, v := range friendlist { if fm.isOnline(v.FriendID) { v.GameStatus = GameStatus_Online } } } //从数据库获取申请列表 if applyFlag { applylist = getApplyList(userId) for _, v := range applylist { if fm.isOnline(v.FriendID) { v.GameStatus = GameStatus_Online } } } //从数据库获取审核列表 if verifyFlag { verifylist = getVerifyList(userId) for _, v := range verifylist { if fm.isOnline(v.FriendID) { v.GameStatus = GameStatus_Online } } } fm.lock.Lock() defer fm.lock.Unlock() //刷新在线好友列表 if friendFlag { l.GiveTimes = giveTimes l.FriendList = friendlist } //刷新在线申请列表 if applyFlag { l.ApplyList = applylist } //刷新审核列表 if verifyFlag { l.VerifyList = verifylist } notifyId := Friend_Notify_All if friendFlag { notifyId = Friend_Notify_Friend } else if verifyFlag { notifyId = Friend_Notify_Verify } else if applyFlag { return true } buf, _ := json.Marshal(notification.NotificationFriend{ NotifyId: notifyId, UserId: fromUserId, Data: apply, }) //发送通知 notification.AddNotification(userId, notification.Notification_Friend, string(buf)) return true } func (fm *friendmgr) ifFriend(userId, targetId int) int { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.ifFriend userId[%d] targetId[%d] not exist", userId, targetId) return 0 } return u.ifFriend(targetId) } // 获取用户信息 func (fm *friendmgr) getUserInfo(userId int) *user_friend { fm.lock.RLock() u, ok := fm.userList[userId] fm.lock.RUnlock() if !ok { u = newUserFriend(userId) expire := common.GetTimeStamp() + 300 fm.lock.Lock() fm.offlineList[userId] = expire fm.lock.Unlock() log.Debug("friendmgr.getUserInfo userId=%d expire=%d", userId, expire) } return u } // 邀请好友 func (fm *friendmgr) roomInvite(userId int, nickName string, toUserId, roomNo int) { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.roomInvite userId [%d] not exist", userId) return } if info := u.roomInvite(nickName, toUserId, roomNo); info != nil { go fm.addRoomInviteHistory(toUserId, info) } return } // 添加房间邀请历史列表 func (fm *friendmgr) addRoomInviteHistory(userId int, info *RoomInviteInfo) { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.addRoomInviteHistory userId [%d] not exist", userId) return } u.addRoomInviteHistory(info) } // 获取房间邀请列表 func (fm *friendmgr) getRoomInviteList(userId int) []*RoomInviteInfo { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.getRoomInviteList userId [%d] not exist", userId) return nil } return u.getRoomInviteList() } // 房间邀请无效 func (fm *friendmgr) roomInviteInvalid(userId, roomNo int) { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.roomInviteInvalid userId [%d] not exist", userId) return } u.roomInviteInvalid(roomNo) } // 获取好友上限 func (fm *friendmgr) getMaxFriendCount(userId int) FriendCount { var ret FriendCount if fm.MaxFriendCount == 0 { fm.MaxFriendCount = DEFAULT_FRIEND_COUNT } ret.Base = fm.MaxFriendCount ret.Extra = vipservice.GetExtraFriendCount(userId) return ret } func (fm *friendmgr) dumpFriends() { log.Release("===== Friend List Begin ========================") for _, users := range fm.userList { for _, v := range users.FriendList { log.Release("friendList userId=%d ==> %+v", users.UserID, v) } } log.Release("===== Friend List End ========================") } // 获取房间邀请列表 func (fm *friendmgr) getPotentialFriendList(userId int) string { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.getPotientialList userId [%d] not exist", userId) return "" } return u.getPotentialFriendList() } func (fm *friendmgr) addPotentialFriend(userId int, toUserId int, memo string) { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.addPotentialFriend userId [%d] not exist", userId) return } u.addPotentialFriend(toUserId, memo) } // 黑名单列表 func (fm *friendmgr) getBlackList(userId int) (list []BlackItem) { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.getBlackList userId [%d] not exist", userId) return } return u.getBlackList() } // 添加黑名单 func (fm *friendmgr) addBlack(userId, toUserId int) (retCode int, message string) { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.addBlack userId [%d] not exist", userId) retCode, message = 13, "Invalid user information" return } return u.addBlack(toUserId) } // 删除黑名单 func (fm *friendmgr) delBlack(userId, toUserId int) (retCode int, message string) { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.delBlack userId [%d] not exist", userId) retCode, message = 12, "Invalid user information" return } return u.delBlack(toUserId) } func (fm *friendmgr) isBlackListUser(userId, toUserId int) bool { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.isBlackListUser userId [%d] not exist", userId) return false } return u.isBlackListUser(toUserId) } func (fm *friendmgr) isBlackListUserIn(userId int, toUserId []int) bool { u := fm.getUserInfo(userId) if u == nil { log.Debug("friendmgr.isBlackListUserIn userId [%d] not exist", userId) return false } return u.isBlackListUserIn(toUserId) }