Login function and pattern matching
Joel Reymont
joelr1@REDACTED
Fri Aug 26 11:44:21 CEST 2005
I have a whole bunch of conditions that need to be checked when a
player logs in. I can't use guards to pattern match the record fields
since only built-in guards are allowed. I came up with this for now,
any optimizations are welcome.
login(Nick, Pass, Socket)
when is_list(Nick),
is_list(Pass),
is_pid(Socket) -> % socket handler process
login(fetch(Nick), [Pass]).
login({atomic, []}, _) ->
%% player not found
{error, ?ERR_BAD_LOGIN};
Here I'm going running check_player() through a list of guards which
return {true|false, condition}. If any condition is true then
evaluation of the rest of the guards stops.
login({atomic, [Player]}, [Pass|Args])
when is_record(Player, player),
is_list(Pass),
is_pid(Socket) ->
%% replace dead pids with none
Player1 = Player#player {
socket = fix_pid(Player#player.socket),
pid = fix_pid(Player#player.pid)
},
%% check player state and login
Condition = check_player(Player1, [Pass],
[fun/2 is_bad_password,
fun/2 is_account_disabled,
fun/2 is_player_busy,
fun/2 is_player_online,
fun/2 is_client_down,
fun/2 is_offline]),
{Player, Result} = login(Player1, Condition, Args),
%% update player record
Player1 = Player#player {
last_seen = now()
},
F = fun() -> mnesia:write(Player) end,
case mnesia:transaction(F) of
{atomic, ok} ->
Result;
_ ->
{error, ?ERR_UNKNOWN}
end.
Then I just pattern-match on the condition and update the player
structure as needed.
login(Player, bad_password, _) ->
N = Player#player.failed_login_attempts + 1,
{atomic, MaxLoginErrors} =
db:get(cluster_config, 0, max_login_errors),
Player1 = if
N > MaxLoginErrors ->
%% disable account
Player#player {
disabled = true
};
true ->
Player
end,
Player2 = Player1#player {
login_errors = N
},
{Player2, {error, ?ERR_BAD_LOGIN}};
login(Player, account_disabled, _) ->
{Player, {error, ?ERR_ACCOUNT_DISABLED}};
login(Player, player_online, Args) ->
%% player is idle
logout(Player#player.oid),
login(Player, player_offline, Args);
etc.
The reason I return {error, ...} or {ok, pid} instead of using
exceptions is because I actually need to send the error code back to
the player through the socket. These are not exceptional conditions
either, they can be encountered in the normal course of operations.
Thanks, Joel
On Aug 26, 2005, at 5:29 AM, chandru wrote:
>
> You can do this thus.
>
> -record(login, {name, password, other_field1, other_field2}).
>
> auth_user(#login{name=Name, password=Password} = LoginRec) ->
> case my_password_db:auth_user(Name, Password) of
> ok ->
> extra_auth(LoginRec);
> Err ->
> Err
> end.
>
> extra_auth(#login{other_field1 = "val1"}) ->
> do_stuff;
> extra_auth(#login{other_field2 = "val2"}) ->
> do_someother_stuff.
>
> Or have I not understood your problem?
>
> cheers
> Chandru
>
--
http://wagerlabs.com/uptick
More information about the erlang-questions
mailing list