package guild import ( "q5" "f5" "main/common" "main/constant" "fmt" "mt" ) const ( LoadGuildFlag = iota LoadGuildMemberFlag LoadGuildReqFlag LoadGuildLogFlag ) type guildMgr struct { idHash map[string]*guild nameHash map[string]*guild memberIdHash map[string]*member usingNameHash map[string]int64 } func (this *guildMgr) Init() { this.idHash = make(map[string]*guild) this.nameHash = make(map[string]*guild) this.memberIdHash = make(map[string]*member) this.usingNameHash = make(map[string]int64) this.loadFromDB() } func (this *guildMgr) UnInit() { } func (this *guildMgr) loadFromDB() { this.loadGuild() this.loadGuildMember() } func (this *guildMgr) loadGuild() { f5.GetSysLog().Info("loadGuild begin") lastIdx := f5.GetJsStyleDb().SyncBatchLoadFullTable( constant.FRIEND_DB, "SELECT * FROM t_guild WHERE idx > %d AND deleted = 0", func (ds *f5.DataSet) { p := newGuild() p.loadFromDb(ds) this.idHash[p.guildId] = p this.nameHash[p.guildName] = p }, func (err error) { panic(fmt.Sprintf("loadGuild dberror:%s", err)) }) f5.GetSysLog().Info("loadGuild end lastIdx:%d idNum:%d nameNum:%d", lastIdx, len(this.idHash), len(this.nameHash)) } func (this *guildMgr) loadGuildMember() { f5.GetSysLog().Info("loadGuildMember begin") lastIdx := f5.GetJsStyleDb().SyncBatchLoadFullTable( constant.FRIEND_DB, "SELECT * FROM t_guild_member WHERE idx > %d AND deleted = 0", func (ds *f5.DataSet) { guildId := ds.GetByName("guild_id") guildJob := q5.ToInt32(ds.GetByName("guild_job")) memberId := ds.GetByName("member_id") joinTime := q5.ToInt32(ds.GetByName("join_time")) g := this.internalGetGuildByGuildId(guildId) if g != nil { p := newMember() p.init(g, guildJob, memberId, joinTime) g.addMember(p) this.memberIdHash[memberId] = p } }, func (err error) { panic(fmt.Sprintf("loadGuildMember dberror:%s", err)) }) f5.GetSysLog().Info("loadGuildMember end memberNum:%d", lastIdx, len(this.memberIdHash)) } func (this *guildMgr) isNameTooLong(name string) bool { return len(name) > 15 } func (this *guildMgr) GetGuildByGuildId(guildId string) common.Guild { if p := this.internalGetGuildByGuildId(guildId); p != nil { return p } else { return nil } } func (this *guildMgr) GetGuildByAccountId(accountId string) common.Guild { if p := this.internalGetGuildByAccountId(accountId); p != nil { return p } else { return nil } } func (this *guildMgr) GetGuildByGuildName(guildName string) common.Guild { if p := this.internalGetGuildByGuildName(guildName); p != nil { return p } else { return nil } } func (this *guildMgr) internalGetGuildByAccountId(accountId string) *guild { m := this.internalGetMemberByAccountId(accountId) if m != nil { return m.guild } return nil } func (this *guildMgr) internalGetMemberByAccountId(accountId string) *member { if m, ok := this.memberIdHash[accountId]; ok { return m } return nil } func (this *guildMgr) internalGetGuildByGuildId(guildId string) *guild { if guild, ok := this.idHash[guildId]; ok { return guild } return nil } func (this *guildMgr) internalGetGuildByGuildName(guildName string) *guild { if guild, ok := this.nameHash[guildName]; ok { return guild } return nil } func (this *guildMgr) GetRecommendGuilds(string) []common.Guild { guilds := []common.Guild{} return guilds } func (this *guildMgr) GetGuildRank() []common.Guild { guilds := []common.Guild{} return guilds } func (this *guildMgr) addUsingName(name string) { this.usingNameHash[name] = f5.GetApp().GetNowSeconds(); } func (this *guildMgr) isUsingName(name string) bool { if _, ok := this.usingNameHash[name]; ok { return true } else { return false } } func (this* guildMgr) removeUsingName(name string) { delete(this.usingNameHash, name) } func (this *guildMgr) asyncCreateGuildTask(task *f5.AsyncTask, guildId string, accountId string, avatar int32, name string, cb func(int32, string, string)) { if this.internalGetGuildByAccountId(accountId) != nil { task.SetFail() cb(3, "You already have a cube", "") return } if this.internalGetGuildByGuildName(name) != nil { task.SetFail() cb(4, "Cube name already exists", "") return } if this.isUsingName(name) { task.SetFail() cb(4, "Cube name already exists", "") return } this.addUsingName(name) nowTime := f5.GetApp().GetNowSeconds() f5.GetJsStyleDb().Insert( constant.FRIEND_DB, "t_guild", [][]string{ {"guild_id", guildId}, {"guild_name", name}, {"owner_id", accountId}, {"creator_id", accountId}, {"badge", q5.ToString(avatar)}, {"max_members", q5.ToString(constant.GuildMaxMembers)}, {"createtime", q5.ToString(nowTime)}, {"modifytime", q5.ToString(nowTime)}, }, func (err error, lastInsertId int64, rowsAffected int64) { this.removeUsingName(name) if err != nil { task.SetFail() cb(500, "server internal error", "") return } f5.GetJsStyleDb().Upsert( constant.FRIEND_DB, "t_guild_member", [][]string{ {"member_id", accountId}, }, [][]string{ {"guild_id", guildId}, {"guild_job", q5.ToString(constant.GuildMemberLevelLeader)}, {"deleted", q5.ToString(0)}, {"join_time", q5.ToString(nowTime)}, }, [][]string{ {"guild_id", guildId}, {"guild_job", q5.ToString(constant.GuildMemberLevelLeader)}, {"member_id", accountId}, {"join_time", q5.ToString(nowTime)}, {"createtime", q5.ToString(nowTime)}, {"modifytime", q5.ToString(nowTime)}, }, func (err error, lastInsertId int64, rowsAffected int64) { if err != nil { task.SetFail() cb(500, "server internal error", "") return } guild := newGuild() { guild.guildId = guildId guild.guildName = name guild.ownerId = accountId guild.creatorId = accountId guild.badge = avatar guild.maxMemberNum = constant.GuildMaxMembers guild.createTime = int32(nowTime) guild.modifyTime = int32(nowTime) } this.idHash[guild.guildId] = guild this.nameHash[guild.guildName] = guild oldGuild := this.internalGetGuildByAccountId(accountId) if oldGuild != nil { task.SetFail() panic(fmt.Sprintf("asyncCreateGuildTask:%s", "")) } else { m := newMember() m.init(guild, constant.GuildMemberLevelLeader, accountId, q5.ToInt32(nowTime)) guild.addMember(m) this.memberIdHash[accountId] = m task.SetSucc() cb(0, "", guildId) } }) }) } func (this *guildMgr) AsyncCreateGuild(accountId string, sessionId string, avatar int32, name string, cb func(int32, string, string)) { guildId := q5.ToString(f5.GetApp().NewNodeUuid()) f5.NewLockAsyncTask([][]string{ {constant.GUILD_ID_LOCK_KEY, guildId}, {constant.GUILD_NAME_LOCK_KEY, name}, {constant.GUILD_MEMBER_LOCK_KEY, accountId}, }, func (task *f5.LockAsyncTask) { if len(name) <= 0 { task.SetFail() cb(1, "Name cantnot be empty", "") return } if this.isNameTooLong(name) { task.SetFail() cb(2, "Name is to long", "") return } if this.GetGuildByAccountId(accountId) != nil { task.SetFail() cb(3, "You already have a cube", "") return } if this.GetGuildByGuildName(name) != nil { task.SetFail() cb(4, "Cube name already exists", "") return } params := map[string]string{ "c": "Bag", "a": "createGuildConsume", "account_id": accountId, "session_id": sessionId, } url := fmt.Sprintf("%s/webapp/index.php", mt.Table.Config.GetById(0).GetGameapiUrl()) rspObj := new(common.HeadRsp) f5.GetHttpCliMgr().SendJsStyleJsonRspRequest( url, params, &rspObj, func(rsp f5.HttpCliResponse) { if rspObj.Errcode != 0 { task.SetFail() cb(4, "item not enough", "") return } this.asyncCreateGuildTask(task, guildId, accountId, avatar, name, cb) }) }) } func (this *guildMgr) AsyncGetApplyList(lastIdx int64, accountId string, cb func(int32, string, int64, []string)) { guild := this.GetGuildByAccountId(accountId) if guild != nil { cb(0, "", 0, nil) return } f5.GetJsStyleDb().PageQuery( constant.FRIEND_DB, 50, 0, "SELECT * FROM t_guild_apply", []string{}, f5.GetDbFilter().Comp( f5.GetDbFilter().GT("idx", q5.ToString(lastIdx)).And(), f5.GetDbFilter().EQ("guild_id", guild.GetGuildId()).And(), f5.GetDbFilter().EQ("account_id", accountId).And(), f5.GetDbFilter().EQ("status", q5.ToString(constant.GUILD_APPLY_STATUS_NONE)), ), "", func (err error, pg *f5.Pagination) { var lastSinceId int64 if err != nil { cb(500, "", lastSinceId, []string{}) } if pg.Rows.Next() { idx := q5.ToInt64(pg.Rows.GetByName("idx")) if idx > lastSinceId { lastSinceId = idx } else { panic(fmt.Sprintf("AsyncGetApply idx error:%s %s", idx, lastSinceId)) } } }) } func (this *guildMgr) AsyncApplyJoin(accountId string, guildId string, cb func(int32, string)) { guild := this.GetGuildByAccountId(accountId) if guild != nil { cb(0, "") return } nowTime := f5.GetApp().GetNowSeconds() f5.GetJsStyleDb().Upsert( constant.FRIEND_DB, "t_guild_apply", [][]string{ {"guild_id", guildId}, {"account_id", accountId}, }, [][]string{ {"status", q5.ToString(constant.GUILD_APPLY_STATUS_NONE)}, {"last_apply_time", q5.ToString(nowTime)}, }, [][]string{ {"guild_id", guildId}, {"account_id", accountId}, {"status", q5.ToString(constant.GUILD_APPLY_STATUS_NONE)}, {"last_apply_time", q5.ToString(nowTime)}, {"createtime", q5.ToString(nowTime)}, {"modifytime", q5.ToString(nowTime)}, }, func (err error, lastInsertId int64, rowsAffected int64) { if err != nil { cb(1, "") return } cb(0, "") }) } func (this *guildMgr) asyncAcceptApplyTask(task *f5.AsyncTask, guild *guild, accountId string, targetId string, cb func(int32, string)) { if !guild.isOwner(accountId) { task.SetFail() cb(1, "") return } if this.internalGetMemberByAccountId(targetId) != nil { task.SetFail() cb(1, "") return } nowTime := q5.ToInt32(f5.GetApp().GetNowSeconds()) f5.GetJsStyleDb().Update( constant.FRIEND_DB, "t_guild_member", [][]string{ {"member_id", accountId}, }, [][]string{ {"guild_id", guild.guildId}, {"guild_job", q5.ToString(constant.GuildMemberLevelDefault)}, {"deleted", q5.ToString(0)}, {"join_time", q5.ToString(nowTime)}, }, func (err error, lastInsertId int64, rowsAffected int64) { if err != nil { task.SetFail() cb(1, "") return } m := newMember() m.init(guild, constant.GuildMemberLevelDefault, targetId, nowTime) guild.addMember(m) this.memberIdHash[targetId] = m this.asyncSetApplyStatus( targetId, guild.guildId, constant.GUILD_APPLY_STATUS_ACCEPT, func (err error, lastInsertId int64, rowsAffected int64) { task.SetSucc() }) }) } func (this *guildMgr) AsyncAcceptApply(accountId string, targetId string, cb func(int32, string)) { guild := this.internalGetGuildByAccountId(accountId) if guild == nil { cb(1, "") return; } f5.NewLockAsyncTask([][]string{ {constant.MEMBER_LOCK_KEY, accountId}, {constant.MEMBER_LOCK_KEY, targetId}, {constant.GUILD_ID_LOCK_KEY, guild.guildId}, }, func (task *f5.AsyncTask) { this.asyncAcceptApplyTask(task, guild, accountId, targetId, cb) }) } func (this *guildMgr) AsyncRejectApply(accountId string, targetId string, cb func(int32, string)) { guild := this.internalGetGuildByAccountId(accountId) if guild == nil { cb(0, "") return; } this.asyncSetApplyStatus( targetId, guild.guildId, constant.GUILD_APPLY_STATUS_REJECT, func (err error, lastInsertId int64, rowsAffected int64) { cb(0, "") }) } func (this *guildMgr) AsyncLeave(accountId string, cb func(int32, string, []string)) { members := []string{} keys := [][]string{} { guild := this.internalGetGuildByAccountId(accountId) if guild == nil { cb(0, "", members) return } keys = [][]string{ {constant.GUILD_ID_LOCK_KEY, guild.guildId}, {constant.GUILD_NAME_LOCK_KEY, guild.guildName}, }; guild.traverseMembers( func (m *member) bool { q5.AppendSlice(&keys, []string{constant.GUILD_MEMBER_LOCK_KEY, m.memberId}) q5.AppendSlice(&members, m.memberId) return true }) } f5.NewLockAsyncTask( keys, func (task *f5.LockAsyncTask) { guild := this.internalGetGuildByAccountId(accountId) members := []string{} if guild == nil { task.SetSucc() cb(0, "", members) return } guild.asyncLeave(accountId, func (errCode int32, errMsg string) { if errCode != 0 { task.SetFail() cb(errCode, errMsg, members) return } task.SetSucc() cb(0, "", members) return }) }) } func (this *guildMgr) AsyncKickout(accountId string, targetId string, cb func(int32, string)) { guild := this.internalGetGuildByAccountId(accountId) if guild == nil { cb(0, "") return; } if !guild.isOwner(accountId) { cb(0, "") return; } } func (this *guildMgr) AsyncDisband(accountId string, cb func(int32, string, []string)) { members := []string{} keys := [][]string{} { guild := this.internalGetGuildByAccountId(accountId) if guild == nil { cb(0, "", members) return } if !guild.isOwner(accountId) { cb(1, "Disband only leader perm", members) return } keys = [][]string{ {constant.GUILD_ID_LOCK_KEY, guild.guildId}, {constant.GUILD_NAME_LOCK_KEY, guild.guildName}, }; guild.traverseMembers( func (m *member) bool { q5.AppendSlice(&keys, []string{constant.GUILD_MEMBER_LOCK_KEY, m.memberId}) q5.AppendSlice(&members, m.memberId) return true }) } f5.NewLockAsyncTask( keys, func (task *f5.LockAsyncTask) { guild := this.internalGetGuildByAccountId(accountId) members := []string{} if guild == nil { task.SetSucc() cb(0, "", members) return } if !guild.isOwner(accountId) { task.SetFail() cb(1, "Disband only leader perm", members) return } f5.GetJsStyleDb().Update( constant.FRIEND_DB, "t_guild", [][]string{ {"deleted", "1"}, }, [][]string{ {"guild_id", guild.guildId}, }, func (err error, lastInsertId int64, rowsAffected int64) { if err != nil { task.SetFail() cb(500, "server internal error", members) return } task.SetSucc() guild.disband() cb(0, "", members) return }) }) } func (this *guildMgr) AsyncSearch(string, string, func(int32, string)) { } func (this *guildMgr) AsyncGetGuildLogs(string, string, func(int32, string)) { } func (this *guildMgr) AsyncUpdateGuild(accountId string, kv map[int32]string, cb func(int32, string)) { guild := this.internalGetGuildByAccountId(accountId) if guild == nil { cb(1, "You don't have a cube yet") return } if !guild.isOwner(accountId) { cb(2, "Insufficient permissions") return } guildName := f5.GetApp().NewGlobalUuid() if name, ok := kv[constant.GUILD_UPDATE_FIELD_NAME]; ok { if this.internalGetGuildByGuildName(name) != nil { cb(4, "Cube name already exists") return } if this.isUsingName(name) { cb(4, "Cube name already exists") return } this.addUsingName(name) guildName = name } f5.NewLockAsyncTask([][]string{ {constant.GUILD_ID_LOCK_KEY, guild.guildId}, {constant.GUILD_NAME_LOCK_KEY, guild.guildName}, {constant.GUILD_NAME_LOCK_KEY, guildName}, {constant.GUILD_MEMBER_LOCK_KEY, accountId}, }, func (task *f5.LockAsyncTask) { fields := [][]string{} for k, v := range(kv) { if k == constant.GUILD_UPDATE_FIELD_NOTICE { q5.AppendSlice(&fields, []string{"notice", v}) } else if k == constant.GUILD_UPDATE_FIELD_AVATAR { q5.AppendSlice(&fields, []string{"badge", v}) } else if k == constant.GUILD_UPDATE_FIELD_NAME { q5.AppendSlice(&fields, []string{"guild_name", v}) } else if k == constant.GUILD_UPDATE_FIELD_COND_TYPE { q5.AppendSlice(&fields, []string{"join_cond_type", v}) } else if k == constant.GUILD_UPDATE_FIELD_COND_VALUE { q5.AppendSlice(&fields, []string{"join_cond_value", v}) } } if len(fields) <= 0 { task.SetSucc() cb(0, "") return } f5.GetJsStyleDb().Update( constant.FRIEND_DB, "t_guild", [][]string{ {"guild_id", guild.guildId}, }, fields, func (err error, lastInsertId int64, rowsAffected int64) { if err != nil { task.SetFail() cb(500, "server internal error") return } task.SetSucc() cb(0, "") return }) }).OnExit( func (task *f5.LockAsyncTask) { if name, ok := kv[constant.GUILD_UPDATE_FIELD_NAME]; ok { this.removeUsingName(name) } }) } func (this *guildMgr) asyncSetApplyStatus(accountId string, guildId string, status int32, cb func(error, int64, int64)) { f5.GetJsStyleDb().Update( constant.FRIEND_DB, "t_guild_apply", [][]string{ {"status", q5.ToString(status)}, {"modifytime", q5.ToString(f5.GetApp().GetNowSeconds())}, }, [][]string{ {"account_id", accountId}, {"guild_id", guildId}, }, cb) }