diff --git a/include/records.hrl b/include/records.hrl index 1c7b9f7..ce44cd8 100644 --- a/include/records.hrl +++ b/include/records.hrl @@ -19,4 +19,4 @@ %% EGS database schema. -record(ids, {type, id}). --record(users, {gid, pid, socket, auth, folder, charnumber, charname, lid, map, entry, coords}). +-record(users, {gid, pid, socket, auth, time, folder, charnumber, charname, lid, map, entry, coords}). diff --git a/src/egs_cron.erl b/src/egs_cron.erl index 30097e8..7e440a8 100644 --- a/src/egs_cron.erl +++ b/src/egs_cron.erl @@ -26,7 +26,20 @@ start() -> KeepAlivePid = spawn_link(?MODULE, keepalive, []), - [{keepalive, KeepAlivePid}]. + CleanupPid = spawn_link(?MODULE, cleanup, []), + [{keepalive, KeepAlivePid}, {cleanup, CleanupPid}]. + +%% @doc Cleanup the users table of failures to log into the game server. + +cleanup() -> + receive + _ -> + ?MODULE:cleanup() + after 300000 -> + egs_db:users_cleanup(), + reload, + ?MODULE:cleanup() + end. %% @doc Keep connected players alive. %% @todo Don't even need to send a keepalive packet if we sent a packet in the last Timeout milliseconds. diff --git a/src/egs_db.erl b/src/egs_db.erl index 03e63a4..ae657da 100644 --- a/src/egs_db.erl +++ b/src/egs_db.erl @@ -74,3 +74,13 @@ users_insert(User) -> users_delete(GID) -> mnesia:transaction(fun() -> mnesia:delete({users, GID}) end). + +%% @doc Cleanup the disconnected users who failed after the login stage but before the game stage. + +users_cleanup() -> + Timeout = calendar:datetime_to_gregorian_seconds(calendar:universal_time()) - 300, + Users = do(qlc:q([X#users.gid || X <- mnesia:table(users), + X#users.auth /= success, X#users.time < Timeout])), + mnesia:transaction(fun() -> + lists:foreach(fun(GID) -> users_delete(GID) end, Users) + end). diff --git a/src/egs_game.erl b/src/egs_game.erl index f74b8b2..c202da2 100644 --- a/src/egs_game.erl +++ b/src/egs_game.erl @@ -79,7 +79,8 @@ process_handle(16#020d, CSocket, Version, Packet) -> Auth -> log(GID, "good auth, proceed"), LID = egs_db:next(lobby), - egs_db:users_insert(#users{gid=GID, pid=self(), socket=CSocket, auth= << 0:32 >>, folder=User#users.folder, lid=LID}), + Time = calendar:datetime_to_gregorian_seconds(calendar:universal_time()), + egs_db:users_insert(#users{gid=GID, pid=self(), socket=CSocket, auth=success, time=Time, folder=User#users.folder, lid=LID}), egs_proto:send_flags(CSocket, GID), ?MODULE:char_select(CSocket, GID, Version); _ -> diff --git a/src/egs_login.erl b/src/egs_login.erl index 4bd0593..55006b5 100644 --- a/src/egs_login.erl +++ b/src/egs_login.erl @@ -98,8 +98,8 @@ handle(16#0219, CSocket, SessionID, Packet) -> log(SessionID, io_lib:format("auth success for ~s ~s", [Username, Password])), Auth = crypto:rand_bytes(4), Folder = << Username/binary, "-", Password/binary >>, - log(SessionID, Folder), - egs_db:users_insert(#users{gid=SessionID, pid=self(), socket=CSocket, auth=Auth, folder=Folder}), + Time = calendar:datetime_to_gregorian_seconds(calendar:universal_time()), + egs_db:users_insert(#users{gid=SessionID, pid=self(), socket=CSocket, auth=Auth, time=Time, folder=Folder}), egs_proto:send_auth_success(CSocket, SessionID, SessionID, Auth); %% @doc MOTD request handler. Handles both forms of MOTD requests, US and JP.