package user import ( actorRemote "f1-game/internal/actor_remote" "f1-game/internal/code" "f1-game/internal/constant" "f1-game/internal/data" "f1-game/internal/extend/token" nameActor "f1-game/internal/name/actor" nameLocal "f1-game/internal/name/local" nameRemote "f1-game/internal/name/remote" "f1-game/internal/pb" "f1-game/internal/sessions" "f1-game/nodes/gate/cache" "time" cstring "github.com/cherry-game/cherry/extend/string" ctime "github.com/cherry-game/cherry/extend/time" cfacade "github.com/cherry-game/cherry/facade" clog "github.com/cherry-game/cherry/logger" "github.com/cherry-game/cherry/net/parser/pomelo" cproto "github.com/cherry-game/cherry/net/proto" cprofile "github.com/cherry-game/cherry/profile" "go.uber.org/zap/zapcore" ) type ( actorAgent struct { pomelo.ActorBase agent *pomelo.Agent } ) func newChildAgent(agent *pomelo.Agent) *actorAgent { return &actorAgent{ agent: agent, } } func (p *actorAgent) AliasID() string { return p.agent.SID() } func (p *actorAgent) OnInit() { p.agent.AddOnClose(p.OnSessionClose) p.Local().Register(nameLocal.User_Login, p.login) p.Remote().Register(nameRemote.User_SetSession, p.setSession) p.Remote().Register(nameRemote.Game_UpdateTimeOffset, p.updateTimeOffset) } func (p *actorAgent) login(session *cproto.Session, req *pb.UserLoginRequest) { if p.agent == nil { p.ResponseCode(session, code.AccountLoginBindUserError) return } // debug模式是前端选服,验证gameNodeID 是否传值 if cprofile.Debug() { if req.GameNodeID == "" { p.ResponseCode(session, code.NodeGameNodeIDIsEmpty) return } } // 验证token userToken, errCode := p.validateToken(req.Token) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } // 验证pid 是否配置 sdkRow := data.SDK.Get(userToken.PID) if sdkRow == nil { p.ResponseCode(session, code.AccountLoginPIDError) return } // 根据pid openid获取uid uid, errCode := actorRemote.CenterPlayer.GetUID(sdkRow.SdkID, userToken.PID, userToken.OpenID) if uid < 1 || code.IsFail(errCode) { p.ResponseCode(session, errCode) return } // 检查game节点是否可以进入 errCode = checkNodeState(constant.NodeGame, req.GameNodeID, nameActor.GameOps, uid, session.Ip) if code.IsFail(errCode) { p.ResponseCode(session, errCode) return } // uid和session绑定 oldAgent, err := pomelo.Bind(session.Sid, uid) if err != nil { clog.Warn(err) p.ResponseCode(session, code.AccountLoginBindUserError) return } // 踢掉旧的agent if oldAgent != nil { oldAgent.Kick(upa.duplicateLoginCode, true) } p.kickGateSession(uid) // 在agent存储当前player相关的信息,用于路由、日志记录等 p.agent.Session().Set(sessions.GameNodeID, cstring.ToString(req.GameNodeID)) p.agent.Session().Set(sessions.PID, cstring.ToString(userToken.PID)) p.agent.Session().Set(sessions.OpenID, userToken.OpenID) response := &pb.UserLoginResponse{ Uid: uid, Pid: userToken.PID, OpenID: userToken.OpenID, GameNodeID: req.GameNodeID, Params: req.GetParams(), // TODO 后续可以针对 pid读取一些参数返回给客户端 } if clog.Enable(zapcore.DebugLevel) { clog.Debugf("user login. gameNodeID = %s, pid = %d, open_id = %s, response = %v", req.GameNodeID, userToken.PID, userToken.OpenID, response, ) } p.Response(session, response) } func (p *actorAgent) setSession(req *pb.StrStrList) { if p.agent == nil { clog.Warnf("agent is nil. sid = %s", p.AliasID()) return } for _, param := range req.List { if cstring.IsBlank(param.Value) { p.agent.Session().Remove(param.Key) } else { p.agent.Session().Set(param.Key, param.Value) } } // 更新agnet缓存 cache.UpdateAgent(p.agent) // 推送session到目标节点 for _, param := range req.List { if parserFunc, found := upa.GetSyncParser(param.Key); found { parserFunc(p, p.agent.Session(), true) } } } func (p *actorAgent) validateToken(base64Token string) (*token.Token, int32) { userToken, ok := token.DecodeToken(base64Token) if !ok || userToken.PID < 1 || len(userToken.OpenID) < 1 { clog.Warnf("base64Token = %s", base64Token) return nil, code.AccountUnmarshalError } sdkRow := data.SDK.Get(userToken.PID) if sdkRow == nil { return nil, code.PIDError } statusCode, ok := token.Validate(userToken, sdkRow.Salt) if !ok { return nil, statusCode } return userToken, code.OK } func (p *actorAgent) kickGateSession(uid cfacade.UID) { // 遍历所有网关节点,踢除旧的session uids := []int64{uid} sessions.KickUIDS(uids, upa.duplicateLoginCode, true, p.App().NodeID()) } func (p *actorAgent) OnSessionClose(_ *pomelo.Agent) { cache.RemoveAgent(p.agent) // 推送session到目标节点 for _, parserFunc := range upa.nodeSyncMap { parserFunc(p, p.agent.Session(), false) } // 释放agenet p.agent = nil // 自己退出 p.Exit() } // 更新时间偏移量 func (p *actorAgent) updateTimeOffset(req *pb.I64) { offset := req.Value ctime.AddOffsetTime(time.Duration(offset) * time.Second) clog.Warn("[updateTimeOffset] offset = %d, time = %d", offset, ctime.Now().ToSecond()) } func (p *actorAgent) GetPlayerID() int64 { return sessions.GetPlayerID(p.agent.Session()) } func (p *actorAgent) GetGameNodeID() string { return sessions.GetGameNodeID(p.agent.Session()) } func (p *actorAgent) GetMapNodeID() string { return sessions.GetMapNodeID(p.agent.Session()) }