You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by be...@apache.org on 2014/02/13 17:06:38 UTC
[43/50] mochiweb commit: updated refs/heads/import-upstream to 8eb1f22
turn websocket demo into a simple chat client
Project: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/commit/d253ce86
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/tree/d253ce86
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/diff/d253ce86
Branch: refs/heads/import-upstream
Commit: d253ce86c16b92b499e7155711ff80ce89072c69
Parents: 49eaab9
Author: Bob Ippolito <bo...@redivi.com>
Authored: Thu Dec 26 13:07:04 2013 -0800
Committer: Bob Ippolito <bo...@redivi.com>
Committed: Thu Dec 26 13:07:04 2013 -0800
----------------------------------------------------------------------
examples/websocket/websocket.erl | 84 ++++++++++++++++++++++++++++-------
1 file changed, 69 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/d253ce86/examples/websocket/websocket.erl
----------------------------------------------------------------------
diff --git a/examples/websocket/websocket.erl b/examples/websocket/websocket.erl
index 4049941..4a782d8 100644
--- a/examples/websocket/websocket.erl
+++ b/examples/websocket/websocket.erl
@@ -24,7 +24,8 @@
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
--export([start/0, start_link/0, ws_loop/3, loop/1]).
+-export([start/0, start_link/0, ws_loop/3, loop/2]).
+-export([broadcast_server/1]).
%%
%% Mochiweb websocket example
@@ -52,42 +53,95 @@
%% [7]: Print payload received from client and send it back
%% [8]: Message handling function must return new state value
start() ->
- application:start(sasl),
- start_link(),
- erlang:hibernate(?MODULE, start, []).
+ spawn(
+ fun () ->
+ application:start(sasl),
+ start_link(),
+ receive
+ stop -> ok
+ end
+ end).
start_link() ->
%% [1]
io:format("Listening at http://127.0.0.1:8080/~n"),
+ Broadcaster = spawn_link(?MODULE, broadcast_server, [dict:new()]),
mochiweb_http:start_link([
{name, client_access},
- {loop, fun ?MODULE:loop/1},
+ {loop, {?MODULE, loop, [Broadcaster]}},
{port, 8080}
]).
-ws_loop(Payload, State, ReplyChannel) ->
+ws_loop(Payload, Broadcaster, _ReplyChannel) ->
%% [6]
%% [7]
io:format("Received data: ~p~n", [Payload]),
Received = list_to_binary(Payload),
- ReplyChannel(<<"Received ", Received/binary>>),
+ Broadcaster ! {broadcast, self(), Received},
%% [8]
- State.
+ Broadcaster.
-loop(Req) ->
+loop(Req, Broadcaster) ->
H = mochiweb_request:get_header_value("Upgrade", Req),
- loop(Req, H =/= undefined andalso string:to_lower(H) =:= "websocket").
+ loop(Req,
+ Broadcaster,
+ H =/= undefined andalso string:to_lower(H) =:= "websocket").
-loop(Req, false) ->
+loop(Req, _Broadcaster, false) ->
mochiweb_request:serve_file("index.html", "./", Req);
-loop(Req, true) ->
+loop(Req, Broadcaster, true) ->
{ReentryWs, ReplyChannel} = mochiweb_websocket:upgrade_connection(
Req, fun ?MODULE:ws_loop/3),
%% [3]
- ReplyChannel(<<"Hello">>),
+ Broadcaster ! {register, self(), ReplyChannel},
%% [4]
- InitialState = [],
%% [5]
- ReentryWs(InitialState).
+ ReentryWs(Broadcaster).
+
+
+%% This server keeps track of connected pids
+broadcast_server(Pids) ->
+ Pids1 = receive
+ {register, Pid, Channel} ->
+ broadcast_register(Pid, Channel, Pids);
+ {broadcast, Pid, Message} ->
+ broadcast_sendall(Pid, Message, Pids);
+ {'DOWN', MRef, process, Pid, _Reason} ->
+ broadcast_down(Pid, MRef, Pids);
+ Msg ->
+ io:format("Unknown message: ~p~n", [Msg])
+ end,
+ erlang:hibernate(?MODULE, broadcast_server, [Pids1]).
+
+broadcast_register(Pid, Channel, Pids) ->
+ MRef = erlang:monitor(process, Pid),
+ broadcast_sendall(
+ Pid, "connected", dict:store(Pid, {Channel, MRef}, Pids)).
+
+broadcast_down(Pid, MRef, Pids) ->
+ Pids1 = case dict:find(Pid, Pids) of
+ {ok, {_, MRef}} ->
+ dict:erase(Pid, Pids);
+ _ ->
+ Pids
+ end,
+ broadcast_sendall(Pid, "disconnected", Pids1).
+
+broadcast_sendall(Pid, Msg, Pids) ->
+ M = iolist_to_binary([pid_to_list(Pid), ": ", Msg]),
+ dict:fold(
+ fun (K, {Reply, MRef}, Acc) ->
+ try
+ begin
+ Reply(M),
+ dict:store(K, {Reply, MRef}, Acc)
+ end
+ catch
+ _:_ ->
+ Acc
+ end
+ end,
+ dict:new(),
+ Pids).