265 lines
6.9 KiB
Go
265 lines
6.9 KiB
Go
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)
|
||
}
|
||
}
|
||
}
|