I want to make an emoji server in Erlang.
Bellow is the code of my emoji.erl file:
-module(emoji).
-export([start/1, new_shortcode/3, alias/3, delete/2, lookup/2,
analytics/5, get_analytics/2, remove_analytics/3,
stop/1]).
-record(emoji_state, {
shortcodes = dict:new(),
aliases = dict:new(),
analytics = dict:new()
}).
-type shortcode() :: string().
-type emoji() :: binary().
-type analytic_fun(State) :: fun((shortcode(), State) -> State).
-spec start(Initial :: [{shortcode(), emoji()}]) -> {ok, pid()} | {error, Reason :: term()}.
start(Initial) when is_list(Initial) ->
{ok, spawn(fun() -> emoji_loop(#emoji_state{shortcodes = dict:from_list(Initial)}) end)};
start(_) ->
{error, invalid_argument}.
-spec new_shortcode(Pid :: pid(), Short :: shortcode(), Emo :: emoji()) -> ok | {error, Reason :: term()}.
new_shortcode(Pid, Short, Emo) when is_pid(Pid), is_binary(Emo), is_list(Short) ->
Pid ! {new_shortcode, Short, Emo},
receive
{ok, Short} -> ok;
{error, Reason} -> {error, Reason}
after 5000 -> {error, timeout}
end.
-spec alias(Pid :: pid(), Short1 :: shortcode(), Short2 :: shortcode()) -> ok | {error, Reason :: term()}.
alias(Pid, Short1, Short2) when is_pid(Pid), is_list(Short1), is_list(Short2) ->
Pid ! {alias, Short1, Short2},
receive
{ok, Short2} -> ok;
{error, Reason} -> {error, Reason}
after 5000 -> {error, timeout}
end.
-spec delete(Pid :: pid(), Short :: shortcode()) -> ok.
delete(Pid, Short) when is_pid(Pid), is_list(Short) ->
Pid ! {delete, Short},
ok.
-spec lookup(Pid :: pid(), Short :: shortcode()) -> {ok, emoji()} | no_emoji.
lookup(Pid, Short) when is_pid(Pid), is_list(Short) ->
Pid ! {lookup, Short},
receive
{ok, Emo} -> {ok, Emo};
no_emoji -> no_emoji
after 5000 -> {error, timeout}
end.
-spec analytics(Pid :: pid(), Short :: shortcode(), Fun :: analytic_fun(State :: any()), Label :: string(), Init :: any()) -> ok | {error, Reason :: term()}.
analytics(Pid, Short, Fun, Label, Init) when is_pid(Pid), is_list(Short), is_function(Fun, 2) ->
Pid ! {analytics, Short, Fun, Label, Init},
receive
{ok, Label} -> ok;
{error, Reason} -> {error, Reason}
after 5000 -> {error, timeout}
end.
-spec get_analytics(Pid :: pid(), Short :: shortcode()) -> {ok, [{string(), any()}]} | {error, Reason :: term()}.
get_analytics(Pid, Short) when is_pid(Pid), is_list(Short) ->
Pid ! {get_analytics, Short},
receive
{ok, Stats} -> {ok, Stats};
{error, Reason} -> {error, Reason}
after 5000 -> {error, timeout}
end.
-spec remove_analytics(Pid :: pid(), Short :: shortcode(), Label :: string()) -> ok.
remove_analytics(Pid, Short, Label) when is_pid(Pid), is_list(Short), is_list(Label) ->
Pid ! {remove_analytics, Short, Label},
ok.
-spec stop(Pid :: pid()) -> ok | {error, Reason :: term()}.
stop(Pid) when is_pid(Pid) ->
Pid ! stop,
receive
ok -> ok;
{error, Reason} -> {error, Reason}
after 5000 -> {error, timeout}
end.
emoji_loop(State = #emoji_state{}) ->
receive
{new_shortcode, Short, Emo} ->
case dict:find(Short, State#emoji_state.shortcodes) of
{ok, _} -> emoji_loop(State);
error ->
NewShortcodes = dict:store(Short, Emo, State#emoji_state.shortcodes),
emoji_loop(State#emoji_state{shortcodes = NewShortcodes})
end;
{alias, Short1, Short2} ->
case dict:find(Short1, State#emoji_state.shortcodes) of
{ok, _} ->
case dict:find(Short2, State#emoji_state.aliases) of
{ok, _} -> emoji_loop(State);
error ->
NewAliases = dict:store(Short2, Short1, State#emoji_state.aliases),
emoji_loop(State#emoji_state{aliases = NewAliases})
end;
error -> emoji_loop(State)
end;
{delete, Short} ->
NewShortcodes = dict:erase(Short, State#emoji_state.shortcodes),
NewAliases = dict:filter(fun(_, S) -> S /= Short end, State#emoji_state.aliases),
emoji_loop(State#emoji_state{shortcodes = NewShortcodes, aliases = NewAliases});
{lookup, Short} ->
case dict:find(Short, State#emoji_state.shortcodes) of
{ok, Emo} -> emoji_loop(State);
error ->
case dict:find(Short, State#emoji_state.aliases) of
{ok, Alias} -> emoji_loop(State#emoji_state{shortcodes = State#emoji_state.shortcodes, aliases = State#emoji_state.aliases});
error -> emoji_loop(State)
end
end;
{analytics, Short, Fun, Label, Init} ->
case dict:find(Short, State#emoji_state.analytics) of
{ok, _} -> emoji_loop(State);
error ->
NewAnalytics = dict:store(Short, [{Label, Fun, Init}], State#emoji_state.analytics),
emoji_loop(State#emoji_state{analytics = NewAnalytics})
end;
{get_analytics, Short} ->
case dict:find(Short, State#emoji_state.analytics) of
{ok, Analytics} ->
Stats = [{Label, Fun(Short, Init)} || {Label, Fun, Init} <- Analytics],
emoji_loop(State);
error -> emoji_loop(State)
end;
{remove_analytics, Short, Label} ->
case dict:find(Short, State#emoji_state.analytics) of
{ok, Analytics} ->
NewAnalytics = dict:store(Short, [], State#emoji_state.analytics),
%%NewAnalytics = dict:update_counter(Short, [{Label, _, _}] --> [], State#emoji_state.analytics),
emoji_loop(State#emoji_state{analytics = NewAnalytics});
error -> emoji_loop(State)
end;
stop ->
exit(normal)
end.
My server runs fine, but whenever I am trying to test any of the following inputs in the terminal, i am getting timeout errors as attached bellow;
6> emoji:new_shortcode(Pid, "love", <<"❤️">>). {error,timeout}
7> emoji:alias(Pid, "happy", "joy"). {error,timeout}
8> emoji:new_shortcode(Pid, "love", <<"❤️">>). {error,timeout}
9> emoji:lookup(Pid, "happy"). {error,timeout}
10> Fun = fun(_, State) -> State + 1 end, .. emoji:analytics(Pid, "happy", Fun, "counter", 0). {error,timeout}
11> emoji:get_analytics(Pid, "happy"). {error,timeout}
12> emoji:remove_analytics(Pid, "happy", "counter"). ok
13> emoji:stop(Pid). {error,timeout}
Can anyone guide me on how to solve these timeout errors?