game2006go/server/imserver/friendsmgr.go
2023-08-24 11:23:07 +08:00

395 lines
11 KiB
Go

package main
import (
"cs"
"errors"
"fmt"
"q5"
"strings"
"sync"
"time"
)
type FriendsMgr struct {
cs.MsgHandlerImpl
mu sync.RWMutex
users map[string]*User // AccountId -> 用户
searchCaches map[string]SearchCache // SearchKeyword -> 好友搜索结果 []*User
friendships map[string][]*Friendship // AccountId -> 好友关系列表 []*Friendship
pendingReqs map[string]map[string]bool // AccountId -> 等待请求列表 map[account2Id]true
blackList map[string]map[string]bool // AccountId -> 黑名单列表 map[account2Id]true
userCount int // 用户总数
}
type SearchCache struct {
Users []*User
LastModified time.Time
}
func (fm *FriendsMgr) init() {
fm.userCount = 0
// 加载所有用户
fm.loadUsers()
// 加载好友关系表 列表
fm.loadFriendships()
// 加载等待验证好友请求 列表
fm.loadPendingRequests()
// 加载黑名单列表
fm.loadBlacklist()
fm.searchCaches = make(map[string]SearchCache)
}
func (fm *FriendsMgr) unInit() {
// 1. Loop struct data
// 2. Struct Data Persist to DB
}
// 搜索指定用户
func (fm *FriendsMgr) searchByAccountId(accountId string) *User {
if user, ok := fm.users[accountId]; ok {
return user
}
return nil
}
// 搜索用户
func (fm *FriendsMgr) searchUsers(keyword string) []*User {
if len(keyword) > SearchWord {
return nil
}
if cachedResult, ok := fm.searchCaches[keyword]; ok {
if time.Since(cachedResult.LastModified) <= 10*time.Hour {
return cachedResult.Users
}
}
maxUsers := 20
listFriend := make([]*User, 0, maxUsers)
lowercaseQuery := strings.ToLower(keyword)
for _, u := range fm.users {
if strings.Contains(strings.ToLower(u.Username), lowercaseQuery) {
uEntity := &User{
AccountId: u.AccountId,
Username: u.Username,
}
listFriend = append(listFriend, uEntity)
}
// 显示搜索结果 20条
if len(listFriend) >= maxUsers {
break
}
}
// Add to caches
fm.searchCaches[keyword] = SearchCache{
Users: listFriend,
LastModified: time.Now(),
}
fm.clearExpiredCaches()
return listFriend
}
// addFriendRequest 添加好友请求
func (fm *FriendsMgr) addFriendRequest(account1Id string, account2Id string) error {
_, exists1 := fm.users[account1Id]
_, exists2 := fm.users[account2Id]
if !exists1 || !exists2 {
return errors.New("users not exist")
}
err := fm.checkInBlackList(account1Id, account2Id)
if err != nil {
return err
}
// 已发送请求
if _, ok := fm.pendingReqs[account1Id][account2Id]; ok {
return nil
}
// 自己好友已满
if fm.getFriendCount(account1Id) >= MaxFriendMembers {
return fmt.Errorf("player:%s, friends are full", account1Id)
}
// 对方好友已满
if fm.getFriendCount(account2Id) >= MaxFriendMembers {
return fmt.Errorf("player:%s, friends are full", account2Id)
}
// 对方待请求已满
if fm.getFriendRequestCount(account2Id) >= MaxPendingFriendReqs {
return fmt.Errorf("player:%s, friends are full", account2Id)
}
if fm.pendingReqs == nil {
fm.pendingReqs = make(map[string]map[string]bool, 200)
}
if fm.pendingReqs[account1Id] == nil {
fm.pendingReqs[account1Id] = make(map[string]bool, MaxPendingFriendReqs)
}
fm.pendingReqs[account1Id][account2Id] = true
if fm.pendingReqs[account2Id] == nil {
fm.pendingReqs[account2Id] = make(map[string]bool, MaxPendingFriendReqs)
}
fm.pendingReqs[account2Id][account1Id] = true
// persist to db
fm.upsertFriendRequest(account1Id, account2Id, "0")
return nil
}
// acceptFriendRequest 接受好友请求
func (fm *FriendsMgr) acceptFriendRequest(account1Id string, account2Id string) error {
if _, ok := fm.pendingReqs[account1Id][account2Id]; !ok {
return errors.New("no pending friend request from account1Id to account2Id")
}
if fm.getFriendCount(account1Id) >= MaxFriendMembers {
return fmt.Errorf("player:%s, friends are full", account1Id)
}
if fm.getFriendCount(account2Id) >= MaxFriendMembers {
return fmt.Errorf("player:%s, friends are full", account2Id)
}
// step1. update reqs
fm.upsertFriendRequest(account2Id, account1Id, "1")
fm.upsertFriendRequest(account1Id, account2Id, "1")
// step2. insert friendship
a1, a2 := swapMiniAccount(account1Id, account2Id)
fm.upsertFriendShip(a1, a2, 0)
// Create a new friendship
friendship := &Friendship{
User1: fm.users[account1Id],
User2: fm.users[account2Id],
}
fm.friendships[account1Id] = append(fm.friendships[account1Id], friendship)
fm.friendships[account2Id] = append(fm.friendships[account2Id], friendship)
delete(fm.pendingReqs[account1Id], account2Id)
delete(fm.pendingReqs[account2Id], account1Id)
return nil
}
// rejectFriendRequest 拒绝好友请求
func (fm *FriendsMgr) rejectFriendRequest(account1Id string, account2Id string) error {
if fm.pendingReqs[account1Id] == nil {
return errors.New("no pending friend request to reject")
}
if _, ok := fm.pendingReqs[account1Id][account2Id]; !ok {
return errors.New("no pending friend request from user1 to user2")
}
// 申请表,申请者,目标者,
fm.upsertFriendRequest(account2Id, account1Id, "2")
delete(fm.pendingReqs[account1Id], account2Id)
delete(fm.pendingReqs[account2Id], account1Id)
return nil
}
// deleteFriendShip 删除好友
func (fm *FriendsMgr) deleteFriendShip(account1Id, account2Id string) error {
fm.mu.Lock()
defer fm.mu.Unlock()
user1Friendships := fm.friendships[account1Id]
user2Friendships := fm.friendships[account2Id]
var found bool
for i, friendship := range user1Friendships {
if friendship.User1.AccountId == account2Id || friendship.User2.AccountId == account2Id {
// 删除好友请求, upsert 不存在则新增,存在则替换值
fm.upsertFriendRequest(account1Id, account2Id, "3")
fm.friendships[account1Id] = append(user1Friendships[:i], user1Friendships[i+1:]...)
found = true
break
}
}
if !found {
return errors.New("friendship not found")
}
for i, friendship := range user2Friendships {
if friendship.User1.AccountId == account1Id || friendship.User2.AccountId == account1Id {
// 删除好友请求, insert和replace, 不存在则新增,存在则替换值
fm.upsertFriendRequest(account2Id, account1Id, "3")
fm.friendships[account2Id] = append(user2Friendships[:i], user2Friendships[i+1:]...)
break
}
}
// Delete friendship DB
a1, a2 := swapMiniAccount(account1Id, account2Id)
fields := [][]string{{"is_delete_friendship", q5.ToString(1)}}
fm.updateFriendShip(a1, a2, fields)
return nil
}
// getFriendCount 好友数量
func (fm *FriendsMgr) getFriendCount(accountId string) int {
if _, ok := fm.friendships[accountId]; ok {
return len(fm.friendships[accountId])
}
return 0
}
// getFriendRequestCount 等待请求数量
func (fm *FriendsMgr) getFriendRequestCount(accountId string) int {
if _, ok := fm.pendingReqs[accountId]; ok {
return len(fm.pendingReqs[accountId])
}
return 0
}
// listFriend 我的好友列表
func (fm *FriendsMgr) listFriend(accountId string) []*User {
// By default, Users member data count:10
var users []*User
for _, friendship := range fm.friendships[accountId] {
if friendship.User1.AccountId != accountId {
uEntity := &User{
AccountId: friendship.User1.AccountId,
Username: friendship.User1.Username,
}
users = append(users, uEntity)
} else {
uEntity := &User{
AccountId: friendship.User2.AccountId,
Username: friendship.User2.Username,
}
users = append(users, uEntity)
}
}
return users
}
// addBlacklist 加入黑名单
func (fm *FriendsMgr) addBlacklist(account1Id string, account2Id string) error {
user2 := fm.getUser(account2Id)
if user2 == nil {
return nil
}
if fm.blackList[account1Id] == nil {
fm.blackList[account1Id] = make(map[string]bool, MaxBlockedMembers)
}
isRemoved, exists := fm.blackList[account1Id][account2Id]
if exists && !isRemoved {
return nil
}
if len(fm.blackList[account1Id]) >= 50 {
return fmt.Errorf("your blacklist has reached the limit")
}
fm.blackList[account1Id][account2Id] = false
fm.upsertBlacklist(account1Id, account2Id, 0)
return nil
}
// removeBlacklist 移除黑名单
func (fm *FriendsMgr) removeBlacklist(account1Id string, account2Id string) error {
if fm.blackList[account1Id] == nil {
return fmt.Errorf("your blacklist is emtpy")
}
if isRemoved, exists := fm.blackList[account1Id][account2Id]; !exists || isRemoved {
return fmt.Errorf("your blacklist not exists target account id")
}
delete(fm.blackList[account1Id], account2Id)
fm.upsertBlacklist(account1Id, account2Id, 1)
return nil
}
func (fm *FriendsMgr) addFriendshipToMap(accountID string, friendship *Friendship) {
if fm.friendships[accountID] == nil {
fm.friendships[accountID] = []*Friendship{friendship}
} else {
fm.friendships[accountID] = append(fm.friendships[accountID], friendship)
}
}
func (fm *FriendsMgr) registerUser(accountId string, username string) error {
if fm.users[accountId] == nil {
fm.users[accountId] = &User{AccountId: accountId, Username: username}
return nil
}
return fmt.Errorf("user exists")
}
func (fm *FriendsMgr) clearExpiredCaches() {
expirationTime := time.Now().Add(-24 * time.Hour)
for key, entry := range fm.searchCaches {
if entry.LastModified.Before(expirationTime) {
delete(fm.searchCaches, key)
}
}
}
func PrintUsers(str string, userList []*User) {
for _, user := range userList {
fmt.Printf("[%s]:accountId:%s, username:%s \n", str, user.AccountId, user.Username)
}
}
func (fm *FriendsMgr) findFriendShipIndex(Account1Id, Account2Id string) int {
// 通常 account1Id,指自己, account2Id 指对方
if _, exists := fm.friendships[Account1Id]; exists {
for i, friendship := range fm.friendships[Account1Id] {
if friendship.User2.AccountId == Account2Id {
return i
}
}
}
return -1
}
func (fm *FriendsMgr) getUser(accountId string) *User {
if user, ok := fm.users[accountId]; ok {
return user
}
return nil
}
func (fm *FriendsMgr) checkInBlackList(account1Id, account2Id string) error {
if fm.blackList[account1Id] == nil {
fm.blackList[account1Id] = make(map[string]bool, MaxBlockedMembers)
}
if isRemoved, exists := fm.blackList[account1Id][account2Id]; isRemoved && exists {
return fmt.Errorf("user:%s in user:%s blocked", account2Id, account1Id)
}
if fm.blackList[account2Id] == nil {
fm.blackList[account2Id] = make(map[string]bool, MaxBlockedMembers)
}
if isRemoved, exists := fm.blackList[account2Id][account1Id]; isRemoved && exists {
return fmt.Errorf("user:%s in user:%s blocked", account1Id, account2Id)
}
return nil
}
func swapMiniAccount(account1Id, account2Id string) (string, string) {
// step2. insert friendship
compareResult := strings.Compare(account1Id, account2Id)
if compareResult > 0 {
temp := account1Id
account1Id = account2Id
account2Id = temp
}
return account1Id, account2Id
}