game2006go/server/imserver/friendsmgr.go
2023-08-15 17:26:46 +08:00

265 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"cs"
"errors"
"f5"
"mt"
"q5"
"strings"
"time"
)
type FriendsMgr struct {
cs.MsgHandlerImpl
users map[string]*User
searchCaches map[string]SearchCache
friendships map[string][]*Friendship
pendingReqs map[string]map[string]bool
}
type SearchCache struct {
Users []*User
LastModified time.Time
}
var gameDBStore *q5.Mysql
var friendDBStore *q5.Mysql
func (fm *FriendsMgr) init() {
// init gameDB
gameDBStore = q5.NewMysql(
mt.Table.GameDb.GetById(0).GetHost(),
mt.Table.GameDb.GetById(0).GetPort(),
mt.Table.GameDb.GetById(0).GetUser(),
mt.Table.GameDb.GetById(0).GetPasswd(),
mt.Table.GameDb.GetById(0).GetDatabase(),
)
gameDBStore.Open()
fm.loadUsersFromDB(gameDBStore)
// init friendDB
friendDBStore = q5.NewMysql(
mt.Table.FriendDb.GetById(0).GetHost(),
mt.Table.FriendDb.GetById(0).GetPort(),
mt.Table.FriendDb.GetById(0).GetUser(),
mt.Table.FriendDb.GetById(0).GetPasswd(),
mt.Table.FriendDb.GetById(0).GetDatabase(),
)
friendDBStore.Open()
// 加载好友关系表 列表
fm.loadFriendshipsFromDB(friendDBStore)
// 加载等待验证好友请求 列表
fm.loadPendingRequestsFromDB(friendDBStore)
fm.searchCaches = make(map[string]SearchCache)
}
func (fm *FriendsMgr) unInit() {
// 1. Loop struct data
// 2. Struct Data Persist to DB
}
func (fm *FriendsMgr) searchFriends(searchKeyword string) []*User {
if cachedResult, ok := fm.searchCaches[searchKeyword]; ok {
if time.Since(cachedResult.LastModified) <= 10*time.Hour {
return cachedResult.Users
}
}
listFriend := make([]*User, 10)
lowercaseQuery := strings.ToLower(searchKeyword)
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)
}
}
// Add to caches
fm.searchCaches[searchKeyword] = SearchCache{
Users: listFriend,
LastModified: time.Now(),
}
fm.clearExpiredCaches()
return listFriend
}
// addFriendRequest 发送好友请求
func (fm *FriendsMgr) addFriendRequest(user1Id string, user2Id string) error {
// Check if users exist
_, exists1 := fm.users[user1Id]
_, exists2 := fm.users[user2Id]
if !exists1 || !exists2 {
return errors.New("users not exist")
}
// 为 user2 创建等待验证好友请求 记录由userid1 申请的
if fm.pendingReqs[user2Id] == nil {
fm.pendingReqs[user2Id] = make(map[string]bool)
}
fm.pendingReqs[user2Id][user1Id] = true
return nil
}
// acceptFriendRequest 接受好友请求
func (fm *FriendsMgr) acceptFriendRequest(user1Id string, user2Id string) error {
if !fm.pendingReqs[user1Id][user2Id] {
return errors.New("no pending friend request from user1 to user2")
}
// step1. delete or update friend request record
// step2. add friend history to db
// step3. add friendship
err := fm.acceptFriendRequestToDB(user1Id, user2Id)
if err != nil {
return err
}
// Create a new friendship
friendship := &Friendship{
User1: fm.users[user1Id],
User2: fm.users[user2Id],
}
fm.friendships[user1Id] = append(fm.friendships[user1Id], friendship)
fm.friendships[user2Id] = append(fm.friendships[user2Id], friendship)
delete(fm.pendingReqs[user1Id], user2Id)
delete(fm.pendingReqs[user2Id], user1Id)
return nil
}
// CMListFriend 我的好友列表
func (fm *FriendsMgr) listFriend(accountId string) []*User {
// By default, Users member data count:10
users := make([]*User, 10)
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
}
func (fm *FriendsMgr) acceptFriendRequestToDB(user1Id string, user2Id string) error {
// step1. UPDATE t_pending_friend_requests
_, err := friendDBStore.Exec("UPDATE t_pending_friend_requests SET flag=1 WHERE sender_account_id = ? AND receiver_account_id = ?", user1Id, user2Id)
if err != nil {
return err
}
// step2. add t_friend_ships
compareResult := strings.Compare(user1Id, user2Id)
if compareResult > 0 {
temp := user1Id
user1Id = user2Id
user2Id = temp
}
_, err = friendDBStore.Exec("REPLACE INTO `t_friend_ships` (user1_id, user2_id, createtime, createtime) VALUES (?, ?)", user1Id, user2Id, "now()", "now()")
if err != nil {
return err
}
return nil
}
func (fm *FriendsMgr) loadUsersFromDB(conn *q5.Mysql) {
// Load DB users to struct FriendsMgr.user
rows, err := conn.Query("select account_id, name from t_user")
if err != nil {
f5.GetSysLog().Info("mysql error", err)
return
}
fm.users = make(map[string]*User)
for rows.Next() {
user := &User{}
err := rows.Scan(&user.AccountId, &user.Username)
if err != nil {
continue
}
fm.users[user.AccountId] = user
}
}
func (fm *FriendsMgr) loadFriendshipsFromDB(conn *q5.Mysql) {
// Load DB t_friend_ships to struct FriendsMgr.friendship
rows, err := conn.Query("select account1_id, account2_id from t_friend_ships;")
if err != nil {
f5.GetSysLog().Info("mysql error", err)
return
}
fm.friendships = make(map[string][]*Friendship)
for rows.Next() {
user1 := &User{}
user2 := &User{}
err := rows.Scan(&user1.AccountId, &user2.AccountId)
if err != nil {
continue
}
friendship := &Friendship{}
friendship.User1 = user1
friendship.User2 = user2
fm.addFriendshipToMap(user1.AccountId, friendship)
fm.addFriendshipToMap(user2.AccountId, friendship)
}
}
func (fm *FriendsMgr) loadPendingRequestsFromDB(conn *q5.Mysql) {
rows, err := conn.Query("select sender_account_id, receiver_account_id from t_pending_friend_requests;")
if err != nil {
f5.GetSysLog().Info("mysql error", err)
return
}
pendingReqs := make(map[string]map[string]bool)
for rows.Next() {
var senderAccountId, receiverAccountId string
if err := rows.Scan(&senderAccountId, &receiverAccountId); err != nil {
continue
}
if pendingReqs[senderAccountId] == nil {
pendingReqs[senderAccountId] = make(map[string]bool)
}
pendingReqs[senderAccountId][receiverAccountId] = true
}
if err := rows.Err(); err != nil {
return
}
fm.pendingReqs = pendingReqs
}
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) {
fm.users[accountId] = &User{AccountId: accountId, Username: username}
}
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)
}
}
}