338 lines
9.6 KiB
Go
338 lines
9.6 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"mongo.games.com/goserver/core/logger"
|
||
"time"
|
||
|
||
"mongo.games.com/game/common"
|
||
"mongo.games.com/game/model"
|
||
"mongo.games.com/goserver/core/basic"
|
||
"mongo.games.com/goserver/core/module"
|
||
"mongo.games.com/goserver/core/netlib"
|
||
"mongo.games.com/goserver/core/task"
|
||
)
|
||
|
||
const (
|
||
LoginStateLogin int = iota // 登录中
|
||
LoginStateLoginFinish // 登录完成
|
||
LoginStateLogout // 登出中
|
||
LoginStateLogoutFinish // 登出完成
|
||
)
|
||
|
||
var LoginStateMgrSington = &LoginStateMgr{
|
||
statesByName: make(map[string]*AccLoginState),
|
||
statesByAccId: make(map[string]*AccLoginState),
|
||
statesByPlayer: make(map[string]*AccLoginState),
|
||
statesBySid: make(map[int64]*SessionState),
|
||
}
|
||
|
||
// SessionState 客户端连接状态
|
||
type SessionState struct {
|
||
userName string // 玩家唯一标识
|
||
sid int64 // 连接唯一标识
|
||
state int // 登录状态
|
||
gateSess *netlib.Session // 客户端所在gatesrv
|
||
als *AccLoginState // 账号状态
|
||
clog *model.ClientLoginInfo // 登录日志
|
||
startLoginTs int64 // 登录时间
|
||
}
|
||
|
||
type AccLoginState struct {
|
||
acc *model.Account
|
||
lss map[int64]*SessionState // sid
|
||
lastLoginTs int64 //最后登录时间
|
||
lastLogoutTs int64 //最后登出时间(只是用来判断清理内存缓存)
|
||
}
|
||
|
||
// LoginStateMgr 玩家登录信息
|
||
// 保存登录中和已经登录的玩家账号信息
|
||
// 玩家登出或断开连接只会清除连接信息,短时间内重复登录会使用之前的账号缓存数据不会频繁访问数据库
|
||
// 玩家长时间离开才会清除缓存信息
|
||
// 注意:玩家登录次数,登录时间,登出时间记录并没有准确同步到数据库
|
||
type LoginStateMgr struct {
|
||
statesByName map[string]*AccLoginState // key:玩家唯一标识,玩家登录状态
|
||
statesByAccId map[string]*AccLoginState // key:accountid,所有人登录状态
|
||
statesByPlayer map[string]*AccLoginState // key:accountid,真人登录状态
|
||
statesBySid map[int64]*SessionState // key:连接唯一标识,连接状态
|
||
}
|
||
|
||
func UserKey(userName, platform string, tagkey int32) string {
|
||
return fmt.Sprintf("%v_%v_%v", userName, platform, tagkey)
|
||
}
|
||
|
||
func (this *LoginStateMgr) IsLogining(userName, platform string, tagkey int32) bool {
|
||
userName = UserKey(userName, platform, tagkey)
|
||
if v, exist := this.statesByName[userName]; exist {
|
||
if len(v.lss) == 0 {
|
||
return false
|
||
}
|
||
for _, ls := range v.lss {
|
||
if ls.state == LoginStateLogin {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func (this *LoginStateMgr) IsLoginFinish(userName, platform string, tagkey int32) bool {
|
||
userName = UserKey(userName, platform, tagkey)
|
||
if v, exist := this.statesByName[userName]; exist {
|
||
if len(v.lss) == 0 {
|
||
return false
|
||
}
|
||
for _, ls := range v.lss {
|
||
if ls.state == LoginStateLoginFinish {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func (this *LoginStateMgr) GetLoginStateByName(userName string) *AccLoginState {
|
||
if v, exist := this.statesByName[userName]; exist {
|
||
return v
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (this *LoginStateMgr) GetLoginStateByAccId(accId string) *AccLoginState {
|
||
if v, exist := this.statesByAccId[accId]; exist {
|
||
return v
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (this *LoginStateMgr) GetLoginStateByTelAndPlatform(tel, platform string) *AccLoginState {
|
||
for _, als := range this.statesByPlayer {
|
||
if als != nil && als.acc != nil {
|
||
if als.acc.Tel == tel && als.acc.Platform == platform {
|
||
return als
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetLoginStateBySid 连接是否登录中
|
||
func (this *LoginStateMgr) GetLoginStateBySid(sid int64) *SessionState {
|
||
if v, exist := this.statesBySid[sid]; exist {
|
||
return v
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// StartLogin 开始登录
|
||
func (this *LoginStateMgr) StartLogin(userName, platform string, sid int64, s *netlib.Session, clog *model.ClientLoginInfo, tagkey int32) bool {
|
||
//注意此处的坑,这个地方要增加平台id
|
||
userName = UserKey(userName, platform, tagkey)
|
||
ts := time.Now().Unix()
|
||
if als, exist := this.statesByName[userName]; !exist {
|
||
als = &AccLoginState{
|
||
lss: make(map[int64]*SessionState),
|
||
lastLoginTs: ts,
|
||
}
|
||
ls := &SessionState{
|
||
userName: userName,
|
||
sid: sid,
|
||
gateSess: s,
|
||
state: LoginStateLogin,
|
||
als: als,
|
||
startLoginTs: ts,
|
||
clog: clog,
|
||
}
|
||
this.statesByName[userName] = als
|
||
als.lss[sid] = ls
|
||
this.statesBySid[sid] = ls
|
||
return true
|
||
} else {
|
||
ls := &SessionState{
|
||
userName: userName,
|
||
sid: sid,
|
||
gateSess: s,
|
||
state: LoginStateLogin,
|
||
als: als,
|
||
startLoginTs: ts,
|
||
clog: clog,
|
||
}
|
||
als.lss[sid] = ls
|
||
this.statesBySid[sid] = ls
|
||
if als.acc != nil {
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
}
|
||
|
||
// LoginFinish 玩家登录完成
|
||
func (this *LoginStateMgr) LoginFinish(userName, platform string, sid int64, acc *model.Account, tagkey int32) (oldState map[int64]*SessionState) {
|
||
userName = UserKey(userName, platform, tagkey)
|
||
if v, exist := this.statesByName[userName]; exist {
|
||
v.acc = acc
|
||
v.lastLoginTs = time.Now().Unix()
|
||
if acc != nil {
|
||
this.statesByAccId[acc.AccountId.Hex()] = v
|
||
if acc.Platform != common.Platform_Rob {
|
||
this.statesByPlayer[acc.AccountId.Hex()] = v
|
||
}
|
||
}
|
||
if len(v.lss) > 0 {
|
||
oldState = make(map[int64]*SessionState)
|
||
for k, v := range v.lss {
|
||
if k != sid {
|
||
oldState[k] = v
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if v, exist := this.statesBySid[sid]; exist {
|
||
v.state = LoginStateLoginFinish
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// Logout 删除连接状态
|
||
// 连接断开,正常登出
|
||
func (this *LoginStateMgr) Logout(s *SessionState) {
|
||
if s != nil {
|
||
delete(this.statesBySid, s.sid)
|
||
//缓存下,避免对DB造成冲击
|
||
s.state = LoginStateLogoutFinish
|
||
s.als.lastLogoutTs = time.Now().Unix()
|
||
if s.als != nil && s.als.acc != nil {
|
||
s.als.acc.LastLogoutTime = time.Now()
|
||
}
|
||
delete(s.als.lss, s.sid)
|
||
}
|
||
}
|
||
|
||
// LogoutBySid 登录失败,删除连接状态
|
||
func (this *LoginStateMgr) LogoutBySid(sid int64) {
|
||
if s, exist := this.statesBySid[sid]; exist {
|
||
this.Logout(s)
|
||
}
|
||
}
|
||
|
||
func (this *LoginStateMgr) LogoutByAccount(accId string) {
|
||
if als, exist := this.statesByAccId[accId]; exist {
|
||
if als != nil {
|
||
for _, s := range als.lss {
|
||
this.Logout(s)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// LogoutAllBySession gatesrv掉线,则上面的所有玩家掉线
|
||
func (this *LoginStateMgr) LogoutAllBySession(session *netlib.Session) {
|
||
for sid, s := range this.statesBySid {
|
||
if s.gateSess == session {
|
||
this.Logout(s)
|
||
p := PlayerMgrSington.GetOnlinePlayer(sid)
|
||
if p != nil {
|
||
p.DropLine()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// DelAccountByAccid 特殊处理,负责从statesByName删除,为了处理账号的删除问题
|
||
// 目前的一个使用功能,机器人账号会被删除,但是这里是删除真人账号数据?
|
||
func (this *LoginStateMgr) DelAccountByAccid(accid string) {
|
||
for name, s := range this.statesByPlayer {
|
||
if s != nil && s.acc != nil && s.acc.AccountId.Hex() == accid {
|
||
this.DeleteAccount(name, s)
|
||
}
|
||
}
|
||
}
|
||
|
||
func (this *LoginStateMgr) DeleteAccount(name string, s *AccLoginState) {
|
||
if s != nil && s.acc != nil {
|
||
//注意此处的坑,这个地方要增加平台id,为了和上面的匹配相同
|
||
userName := UserKey(s.acc.UserName, s.acc.Platform, s.acc.TagKey)
|
||
delete(this.statesByName, userName)
|
||
userName = UserKey(s.acc.Tel, s.acc.Platform, s.acc.TagKey)
|
||
delete(this.statesByName, userName)
|
||
acc := s.acc
|
||
if acc != nil {
|
||
delete(this.statesByAccId, acc.AccountId.Hex())
|
||
}
|
||
delete(this.statesByPlayer, name)
|
||
}
|
||
}
|
||
|
||
func (this *LoginStateMgr) ModuleName() string {
|
||
return "LoginStateMgr"
|
||
}
|
||
|
||
func (this *LoginStateMgr) Init() {
|
||
// 预加载机器人数据,是为了让机器人登录时不再访问数据库吗?
|
||
if model.GameParamData.PreLoadRobotCount > 0 {
|
||
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
|
||
tsBeg := time.Now()
|
||
accounts := model.GetRobotAccounts(model.GameParamData.PreLoadRobotCount)
|
||
tsEnd := time.Now()
|
||
logger.Logger.Tracef("GetRobotAccounts take:%v total:%v", tsEnd.Sub(tsBeg), len(accounts))
|
||
return accounts
|
||
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
|
||
if accounts, ok := data.([]model.Account); ok {
|
||
if accounts != nil {
|
||
ts := time.Now().Add(time.Hour).Unix() // 这里加了一小时,延迟数据清理?
|
||
for i := 0; i < len(accounts); i++ {
|
||
userName := UserKey(accounts[i].UserName, accounts[i].Platform, accounts[i].TagKey)
|
||
if _, exist := this.statesByName[userName]; !exist {
|
||
als := &AccLoginState{
|
||
acc: &accounts[i],
|
||
lss: make(map[int64]*SessionState),
|
||
lastLoginTs: ts,
|
||
lastLogoutTs: ts,
|
||
}
|
||
this.statesByName[userName] = als
|
||
this.statesByAccId[accounts[i].AccountId.Hex()] = als
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}), "GetAllRobotAccounts").Start()
|
||
}
|
||
|
||
PlayerMgrSington.LoadRobots()
|
||
}
|
||
|
||
func (this *LoginStateMgr) Update() {
|
||
// 定时清理已经登出的账号数据
|
||
curTs := time.Now().Unix()
|
||
var delAcc []*AccLoginState
|
||
for _, s := range this.statesByPlayer {
|
||
if s == nil {
|
||
continue
|
||
}
|
||
if len(s.lss) == 0 && curTs-s.lastLogoutTs > int64(model.GameParamData.LoginStateCacheSec) {
|
||
if s.acc != nil {
|
||
delAcc = append(delAcc, s)
|
||
}
|
||
}
|
||
}
|
||
for _, s := range delAcc {
|
||
this.DeleteAccount(s.acc.AccountId.Hex(), s)
|
||
}
|
||
}
|
||
|
||
func (this *LoginStateMgr) Shutdown() {
|
||
for _, s := range this.statesByName {
|
||
if s.acc != nil && s.acc.Platform != common.Platform_Rob {
|
||
model.LogoutAccount(s.acc) // 更新登录次数和登出时间
|
||
}
|
||
}
|
||
module.UnregisteModule(this)
|
||
}
|
||
|
||
func init() {
|
||
module.RegisteModule(LoginStateMgrSington, time.Minute, 0)
|
||
}
|