diff --git a/priv/chat.html b/priv/chat.html new file mode 100644 index 0000000..895393b --- /dev/null +++ b/priv/chat.html @@ -0,0 +1,100 @@ + + + + + Chat with Websockets + + + +
+

Chat with websockets

+ +
+ + + +
+
+ + + + diff --git a/priv/index.html b/priv/index.html index d1870aa..134d28a 100644 --- a/priv/index.html +++ b/priv/index.html @@ -10,9 +10,8 @@

WFC Demo

diff --git a/src/fd_chat.erl b/src/fd_chat.erl index 3788677..5fb3098 100644 --- a/src/fd_chat.erl +++ b/src/fd_chat.erl @@ -9,12 +9,15 @@ -export([ join/1, + relay/1, nick_available/1 ]). -export([start_link/0]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]). +-include("$zx_include/zx_logger.hrl"). + -record(o, {pid :: pid(), nick :: string()}). @@ -46,6 +49,14 @@ nick_available(Nick) -> gen_server:call(?MODULE, {nick_available, Nick}). + +-spec relay(Message) -> ok + when Message :: string(). + +relay(Message) -> + gen_server:cast(?MODULE, {relay, self(), Message}). + + %%% Startup Functions @@ -65,7 +76,7 @@ start_link() -> %% preparatory work necessary for proper function. init(none) -> - ok = io:format("Starting.~n"), + ok = tell("~p Starting.", [?MODULE]), State = #s{}, {ok, State}. @@ -88,12 +99,12 @@ init(none) -> handle_call({join, Nick}, {Pid, _}, State) -> {Reply, NewState} = do_join(Pid, Nick, State), - {reply, Reply, NewState}. + {reply, Reply, NewState}; handle_call({nick_available, Nick}, _, State = #s{orators = Orators}) -> Reply = is_nick_available(Nick, Orators), - {reply, Reply, State}. + {reply, Reply, State}; handle_call(Unexpected, From, State) -> - ok = io:format("~p Unexpected call from ~tp: ~tp~n", [self(), From, Unexpected]), + ok = tell("~p Unexpected call from ~tp: ~tp~n", [?MODULE, From, Unexpected]), {noreply, State}. @@ -105,8 +116,11 @@ handle_call(Unexpected, From, State) -> %% The gen_server:handle_cast/2 callback. %% See: http://erlang.org/doc/man/gen_server.html#Module:handle_cast-2 +handle_cast({relay, From, Message}, State = #s{orators = Orators}) -> + do_relay(From, Message, Orators), + {noreply, State}; handle_cast(Unexpected, State) -> - ok = io:format("~p Unexpected cast: ~tp~n", [self(), Unexpected]), + ok = tell("~p Unexpected cast: ~tp~n", [?MODULE, Unexpected]), {noreply, State}. @@ -118,11 +132,11 @@ handle_cast(Unexpected, State) -> %% The gen_server:handle_info/2 callback. %% See: http://erlang.org/doc/man/gen_server.html#Module:handle_info-2 -handle_info(Msg = {'DOWN', Mon, process, Pid, Reason}, State) -> +handle_info(Msg = {'DOWN', _Mon, process, _Pid, _Reason}, State) -> NewState = handle_down(Msg, State), {noreply, NewState}; handle_info(Unexpected, State) -> - ok = io:format("~p Unexpected info: ~tp~n", [self(), Unexpected]), + ok = tell("~p Unexpected info: ~tp~n", [?MODULE, Unexpected]), {noreply, State}. @@ -177,15 +191,15 @@ do_join(Pid, Nick, State = #s{orators = Orators}) -> do_join2(Pid, Nick, State = #s{orators = Orators}) -> _Monitor = erlang:monitor(process, Pid), NewOrator = #o{pid = Pid, nick = Nick}, - NewOrators = [NewOrator | NewOrators], + NewOrators = [NewOrator | Orators], NewState = State#s{orators = NewOrators}, {ok, NewState}. --spec ensure_can_join(Pid, Nick, Orators) -> Result. +-spec ensure_can_join(Pid, Nick, Orators) -> Result when Pid :: pid(), Nick :: string(), - Orators :: [orator()] + Orators :: [orator()], Result :: ok | {error, Reason}, Reason :: any(). @@ -195,7 +209,7 @@ do_join2(Pid, Nick, State = #s{orators = Orators}) -> ensure_can_join(Pid, _ , [#o{pid = Pid} | _ ]) -> {error, already_joined}; ensure_can_join(_ , Nick, [#o{nick = Nick} | _ ]) -> {error, {nick_taken, Nick}}; ensure_can_join(Pid, Nick, [_ | Rest]) -> ensure_can_join(Pid, Nick, Rest); -ensure_can_join(Pid, _, _, [] ) -> ok. +ensure_can_join(_ , _ , [] ) -> ok. -spec is_nick_available(Nick, Orators) -> boolean() @@ -204,13 +218,13 @@ ensure_can_join(Pid, _, _, [] ) -> ok. is_nick_available(Nick, [#o{nick = Nick} | _ ]) -> false; is_nick_available(Nick, [_ | Rest]) -> is_nick_available(Nick, Rest); -is_nick_available(Nick, [] ) -> true. +is_nick_available(_ , [] ) -> true. -spec handle_down(Msg, State) -> NewState when Msg :: {'DOWN', Mon, process, Pid, Reason}, - Mon :: monitor(), + Mon :: erlang:monitor(), Pid :: pid(), Reason :: any(), State :: state(), @@ -224,6 +238,25 @@ handle_down(Msg = {'DOWN', _, process, Pid, _}, State = #s{orators = Orators}) - % encountered item, removing hdn(_, Pid, [#o{pid = Pid} | Rest], Acc) -> Rest ++ Acc; hdn(Msg, Pid, [Skip | Rest], Acc) -> hdn(Msg, Pid, Rest, [Skip | Acc]); -hdn(Msg, Pid, [] , Acc) -> +hdn(Msg, _, [] , Acc) -> log("~tp: Unexpected message: ~tp", [?MODULE, Msg]), Acc. + + +do_relay(Pid, Message, Orators) -> + case lists:keyfind(Pid, #o.pid, Orators) of + #o{nick = Nick} -> + do_relay2(Nick, Message, Orators); + false -> + tell("~tp: Message received from outsider ~tp: ~tp", [?MODULE, Pid, Message]), + error + end. + +% skip +do_relay2(Nick, Msg, [#o{nick = Nick} | Rest]) -> + do_relay2(Nick, Msg, Rest); +do_relay2(Nick, Msg, [#o{pid = Pid} | Rest]) -> + Pid ! {chat, {relay, Nick, Msg}}, + do_relay2(Nick, Msg, Rest); +do_relay2(_, _, []) -> + ok. diff --git a/src/fd_client.erl b/src/fd_client.erl index c254e74..c50d18a 100644 --- a/src/fd_client.erl +++ b/src/fd_client.erl @@ -226,6 +226,7 @@ route(Sock, get, Route, Request) -> case Route of <<"/">> -> home(Sock); <<"/default.css">> -> default_css(Sock); + <<"/chat.html">> -> chat_html(Sock); <<"/ws-test-echo.html">> -> ws_test_echo_html(Sock); <<"/ws/echo">> -> ws_echo(Sock, Request); _ -> http_err(Sock, 404) @@ -318,6 +319,19 @@ ws_test_echo_html(Sock) -> http_err(Sock, 500) end. +chat_html(Sock) -> + %% fixme: cache + Path_IH = filename:join([zx:get_home(), "priv", "chat.html"]), + case file:read_file(Path_IH) of + {ok, Body} -> + Resp = #response{headers = [{"content-type", "text/html"}], + body = Body}, + respond(Sock, Resp); + Error -> + io:format("~p error: ~p~n", [self(), Error]), + http_err(Sock, 500) + end. + wfcin(Sock, #request{enctype = json, cookies = Cookies, body = #{"wfcin" := Input}}) ->