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
+
+
+
+
+
+
+
+
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}}) ->