Example #1
0
        // 세션을 정리합니다.
        public static void FreeUser(Session session)
        {
            // 유저를 정리하기 위한 Context 를 읽어옵니다.
            string matching_state;
            string id;

            session.GetFromContext("matching", out matching_state);
            session.GetFromContext("id", out id);

            // Session Context 를 초기화 합니다.
            session.Context = new JObject();

            // 로그아웃하고 세션을 종료합니다.
            if (id != string.Empty)
            {
                AccountManager.LogoutCallback logout_cb = (string param_account_id,
                                                           Session param_session,
                                                           bool param_result) => {
                    Log.InfoIf(param_result, "Logged out(local) by session close: id={0}", param_account_id);
                };
                AccountManager.SetLoggedOutAsync(id, logout_cb);
            }

            // 매치메이킹이 진행 중이면 취소합니다.
            if (matching_state == "doing")
            {
                // Matchmaking cancel 결과를 처리할 람다 함수입니다.
                funapi.Matchmaking.Client.CancelCallback cancel_cb =
                    (string player_id, funapi.Matchmaking.CancelResult result) => {
                    if (result == funapi.Matchmaking.CancelResult.kSuccess)
                    {
                        Log.Info("Succeed to cancel matchmaking by session close: id={0}", id);
                    }
                    else
                    {
                        Log.Info("Failed to cancel matchmaking by session close: id={0}", id);
                    }
                };
                funapi.Matchmaking.Client.Cancel((long)MatchmakingType.kMatch1vs1, id, cancel_cb);
            }
        }
Example #2
0
        public static void Logout(Session session, SessionResponse.SessionResponseHandler logout_handler)
        {
            Log.Assert(session != null);
            Log.Assert(logout_handler != null);

            string account_id = AccountManager.FindLocalAccount(session);

            if (String.IsNullOrEmpty(account_id))
            {
                // 이 세션으로 로그인한 적이 없습니다.
                Log.Info("This session was not used for login: session_id={0}", session.Id);
                return;
            }

            // 분산 환경이라면 SetLoggedOutGlobalAsync() 함수를 사용해주세요.
            AccountManager.LogoutCallback logout_cb = new AccountManager.LogoutCallback(
                (string account_id2, Session session2, bool logged_out2) => {
                OnLoggedOut(account_id2, session2, logged_out2, logout_handler);
            });

            AccountManager.SetLoggedOutAsync(account_id, logout_cb);
        }
Example #3
0
        public static void OnLoggedIn(
            string account_id, Session session, bool logged_in, string platform, long try_count,
            SessionResponse.SessionResponseHandler login_handler,
            SessionResponse.SessionResponseHandler logout_handler)
        {
            if (!logged_in)
            {
                if (try_count == 0)
                {
                    // 로그인에 실패했습니다. 누군가 먼저 로그인 하거나, 시스템 장애일 수 있습니다.
                    // 처음에는 강제로 로그아웃 후 재시도합니다.
                    Log.Info("Already logged in: session_id={0}, account_id={1}, platform={2}, try_count={3}",
                             session.Id, account_id, platform, try_count);

                    AccountManager.LogoutCallback on_logged_out =
                        new AccountManager.LogoutCallback((string account_id2, Session session_logged_out2, bool logged_out2) => {
                        AccountManager.LoginCallback on_logged_in =
                            new AccountManager.LoginCallback((string account_id3, Session session3, bool logged_in3) => {
                            OnLoggedIn(account_id3, session3, logged_in3, platform, try_count, login_handler, logout_handler);
                        });
                        AccountManager.CheckAndSetLoggedInAsync(account_id2, session, on_logged_in);

                        // 기존 세션에 로그아웃 메시지를 보냅니다.
                        if (logged_out2)
                        {
                            logout_handler(SessionResponse.ResponseResult.OK,
                                           new SessionResponse(session_logged_out2, 200, "Duplicated login", new JObject()));
                        }
                    });

                    // 분산 환경이라면 SetLoggedOutGlobalAsync() 함수를 사용해주세요.
                    AccountManager.SetLoggedOutAsync(account_id, on_logged_out);
                    return;
                }
                else
                {
                    // 로그인을 두 번 이상 실패했습니다.
                    // 만약 SetLoggedOutGlobalAsync() 함수를 사용 중이라면 분산 환경을
                    // 구성하는 Zookeeper / Redis 서비스가 제대로 동작하지 않을 가능성도
                    // 있습니다. 그러나 이 경우 엔진 내부적으로 조치한 후 에러를 출력하기
                    // 때문에 여기서는 클라이언트 처리만 하는 게 좋습니다.
                    Log.Error("Login failed: session_id={0}, account_id={1}, platform={2}, try_count={3}",
                              session.Id, account_id, platform, try_count);
                    login_handler(SessionResponse.ResponseResult.FAILED,
                                  new SessionResponse(session, 500, "Internal server error.", new JObject()));
                    return;
                }
            }              // if (not logged_in)

            // 로그인 성공
            Log.Info("Login succeed: session_id={0}, account_id={1}, platform={2}, try_count={3}",
                     session.Id, account_id, platform, try_count);

            // 클라이언트에게 보낼 응답은 이 곳에 설정합니다.
            JObject response_data = new JObject();

            response_data["key1"] = "value1";
            response_data["key2"] = "value2";
            response_data["key3"] = "value3";

            login_handler(SessionResponse.ResponseResult.OK, new SessionResponse(session, 200, "OK", response_data));
        }
Example #4
0
        private static void OnLogin_Completed(string account_id, Session session, bool success, Session.EncodingScheme encoding)
        {
            if (!success)
            {
                // 로그인에 실패 응답을 보냅니다. 중복 로그인이 원인입니다.
                // (1. 같은 ID 로 이미 다른 Session 이 로그인 했거나,
                //  2. 이 Session 이 이미 로그인 되어 있는 경우)
                Log.Info("Failed to login: id={0}", account_id);
                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    session.SendMessage("login",
                                        Utility.MakeResponse("nop", "failed to login"),
                                        Session.Encryption.kDefault);
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage      funmsg = new FunMessage();
                    LobbyLoginReply reply  = new LobbyLoginReply();
                    reply.result = "nop";
                    reply.msg    = "failed to login";
                    funmsg.AppendExtension_lobby_login_repl(reply);
                    session.SendMessage("login", funmsg);
                }

                // 아래 로그아웃 처리를 한 후 자동으로 로그인 시킬 수 있지만
                // 일단 클라이언트에서 다시 시도하도록 합니다.

                // 1. 이 ID 의 로그인을 풀어버립니다.(로그아웃)
                AccountManager.LogoutCallback logout_cb = (string param_account_id, Session param_session, bool param_success) => {
                    if (!param_success)
                    {
                        return;
                    }
                    if (param_session != null)
                    {
                        // 같은 서버에 로그인 되어 있었습니다.
                        Log.Info("Logged out(local) by duplicated login request: id={0}", param_account_id);
                        session.Close();
                    }
                    else
                    {
                        // 다른 서버에 로그인 되어 있었습니다.
                        // 해당 서버의 OnLoggedOutRemotely() 에서 처리합니다.
                        Log.Info("Logged out(remote) by duplicated login request: id={0}", param_account_id);
                    }
                };

                AccountManager.SetLoggedOutGlobalAsync(account_id, new AccountManager.LogoutCallback(logout_cb));

                // 2. 이 Session 의 로그인을 풀어버립니다.(로그아웃)
                string account_id_logged_in = AccountManager.FindLocalAccount(session);
                if (account_id_logged_in != string.Empty)
                {
                    // OnSessionClosed 에서 처리합니다.
                    Log.Info("Close session. by duplicated login request: id={0}", account_id);
                    session.Close();
                }

                return;
            }

            // User Object 를 가져옵니다.
            User user = User.FetchById(account_id);

            if (user == null)
            {
                // 새로운 유저를 생성합니다.
                user = User.Create(account_id);
                Log.Info("Registered new user: id={0}", account_id);
            }

            Event.AssertNoRollback();

            Log.Info("Succeed to login: id={0}", account_id);

            // 로그인 Activitiy Log 를 남깁니다.
            ActivityLog.PlayerLoggedIn(session.Id.ToString(), account_id, WallClock.Now);

            // Session 에 Login 한 ID 를 저장합니다.
            session.AddToContext("id", account_id);

            if (encoding == Session.EncodingScheme.kJsonEncoding)
            {
                JObject response = Utility.MakeResponse("ok");
                response ["id"]              = account_id;
                response ["winCount"]        = user.GetWinCount();
                response ["loseCount"]       = user.GetLoseCount();
                response ["curRecord"]       = Leaderboard.GetRecord(account_id);
                response ["singleWinCount"]  = user.GetWinCountSingle();
                response ["singleLoseCount"] = user.GetLoseCountSingle();
                response ["singleCurRecord"] = Leaderboard.GetRecord(account_id, true);

                session.SendMessage("login", response, Session.Encryption.kDefault);
            }
            else
            {
                Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                FunMessage      funmsg = new FunMessage();
                LobbyLoginReply reply  = new LobbyLoginReply();
                reply.result            = "ok";
                reply.id                = account_id;
                reply.win_count         = (int)user.GetWinCount();
                reply.lose_count        = (int)user.GetLoseCount();
                reply.cur_record        = (int)Leaderboard.GetRecord(account_id);
                reply.win_count_single  = (int)user.GetWinCountSingle();
                reply.lose_count_single = (int)user.GetLoseCountSingle();
                reply.cur_record_single = Leaderboard.GetRecord(account_id, true);
                funmsg.AppendExtension_lobby_login_repl(reply);

                session.SendMessage("login", funmsg, Session.Encryption.kDefault);
            }
        }
        // 세션을 정리합니다.
        public static void FreeUser(Session session, Session.EncodingScheme encoding)
        {
            // 유저를 정리하기 위한 Context 를 읽어옵니다.
            string id;
            string opponent_id;

            session.GetFromContext("id", out id);
            session.GetFromContext("opponent", out opponent_id);

            // Session Context 를 초기화 합니다.
            session.Context = new JObject();

            // 로그아웃하고 세션을 종료합니다.
            if (id != string.Empty)
            {
                AccountManager.LogoutCallback logout_cb = (string param_account_id,
                                                           Session param_session,
                                                           bool param_result) => {
                    Log.InfoIf(param_result, "Logged out(local) by session close: id={0}", param_account_id);
                };
                AccountManager.SetLoggedOutAsync(id, logout_cb);
            }

            // 대전 상대가 있는 경우, 상대가 승리한 것으로 처리하고 로비서버로 보냅니다.
            if (opponent_id == string.Empty)
            {
                return;
            }
            Session opponent_session = AccountManager.FindLocalSession(opponent_id);

            if (opponent_session == null)
            {
                return;
            }

            Event.EventFunction update = () => {
                User user          = User.FetchById(id);
                User opponent_user = User.FetchById(opponent_id);

                Event.AssertNoRollback();

                // 편의상 아래 함수에서 ORM 데이터 업데이트 처리도 합니다.
                Leaderboard.OnWin(opponent_user);
                Leaderboard.OnLose(user);

                if (encoding == Session.EncodingScheme.kJsonEncoding)
                {
                    opponent_session.SendMessage("result", Utility.MakeResponse("win"));
                }
                else
                {
                    Log.Assert(encoding == Session.EncodingScheme.kProtobufEncoding);
                    FunMessage        funmsg = new FunMessage();
                    GameResultMessage msg    = new GameResultMessage();
                    msg.result = "win";
                    funmsg.AppendExtension_game_result(msg);
                    opponent_session.SendMessage("result", funmsg);
                }

                Common.Redirect(opponent_session, "lobby");
            };

            Event.Invoke(update);
        }