You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2015/06/29 23:46:37 UTC

[31/50] couch commit: updated refs/heads/COUCHDB-2734-header-date to f3e022c

add HTML for example


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/ecee927a
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/ecee927a
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/ecee927a

Branch: refs/heads/COUCHDB-2734-header-date
Commit: ecee927a04a51858677cd13def37f575ebbb33e7
Parents: 8ecae10
Author: Bob Ippolito <bo...@redivi.com>
Authored: Wed Dec 25 15:06:50 2013 -0800
Committer: Bob Ippolito <bo...@redivi.com>
Committed: Wed Dec 25 15:06:50 2013 -0800

----------------------------------------------------------------------
 .gitignore                       |   2 +
 examples/websocket/index.html    |  59 +++++++++++++++++
 examples/websocket/websocket.erl | 121 ++++++++++++++++++----------------
 src/mochiweb_websocket.erl       |  10 ++-
 4 files changed, 135 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ecee927a/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 09f877f..8f4edf4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,5 @@
 /TEST-*.xml
 /deps
 *.swp
+*.beam
+*.dump

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ecee927a/examples/websocket/index.html
----------------------------------------------------------------------
diff --git a/examples/websocket/index.html b/examples/websocket/index.html
new file mode 100644
index 0000000..6926aba
--- /dev/null
+++ b/examples/websocket/index.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<html>
+<head>
+  <title>Websockets With Mochiweb Demo</title>
+</head>
+<body>
+<h1>Mochiweb websocket demo</h1>
+
+  <div id="connect">
+     <button id="btnConn">Connect</button>
+     &nbsp; State: <span id="connstate" style="font-weight:bold;"></span>
+  </div>
+    <br/><i>Protip: open your javascript error console, just in case..</i><br/>
+  <hr/>
+  <div id="connected">
+    <form id="sendForm">
+      <input id="phrase" type="text"/>
+      <input id="btnSend" class="button" type="submit" name="connect"
+         value="Send"/>
+    </form>
+  </div>
+  <hr/>
+  <div id="msgs"></div>
+
+  <script type="text/javascript">
+    var ws;
+    if (!window.WebSocket) {
+      alert("WebSocket not supported by this browser");
+    }
+    function $(id) {
+      return document.getElementById(id);
+    }
+    function go() {
+        ws = new WebSocket("ws://" + location.host + "/");
+        ws.onopen = function () {
+          $('connstate').innerHTML = 'CONNECTED';
+        }
+        ws.onclose = function () {
+          $('connstate').innerHTML = 'CLOSED';
+        }
+        ws.onmessage = function (e) {
+          var p = document.createElement('pre');
+          p.appendChild(document.createTextNode(e.data));
+          $('msgs').appendChild(p);
+        }
+    }
+    $('sendForm').onsubmit = function (event) {
+      var p = $('phrase');
+      ws.send(p.value);
+      p.value='';
+      return false;
+    }
+    $('btnConn').onclick = function(event) {
+      go(); return false;
+    };
+  </script>
+  </body>
+</html>
+

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ecee927a/examples/websocket/websocket.erl
----------------------------------------------------------------------
diff --git a/examples/websocket/websocket.erl b/examples/websocket/websocket.erl
index b392a20..4049941 100644
--- a/examples/websocket/websocket.erl
+++ b/examples/websocket/websocket.erl
@@ -1,82 +1,93 @@
 -module(websocket).
 
-% The MIT License (MIT)
+%% To run: erlc websocket.erl && erl -pa ../../ebin -s websocket
+
+%% The MIT License (MIT)
 
 %% Copyright (c) 2012 Zadane.pl sp. z o.o.
 
-% Permission is hereby granted, free of charge, to any person obtaining a copy
-% of this software and associated documentation files (the "Software"), to deal
-% in the Software without restriction, including without limitation the rights
-% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-% copies of the Software, and to permit persons to whom the Software is
-% furnished to do so, subject to the following conditions:
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
 
-% The above copyright notice and this permission notice shall be included in
-% all copies or substantial portions of the Software.
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
 
-% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-% THE SOFTWARE.
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
 
--export([start_link/0, ws_loop/3, loop/1]).
+-export([start/0, start_link/0, ws_loop/3, loop/1]).
 
-%
-% Mochiweb websocket example
-%
-% [1]: At first you have to start HTTP server which will listen for HTTP requests
-%      and eventually upgrade connection to websocket
-% [2]: Attempt to upgrade connection to websocket.
-%      Function mochiweb_websocket:upgrade_connection/2:
-%      * first argument is mochiweb_request
-%      * second is M:F which will handle further websocket messages.
-%      Function return two funs:
-%      * ReentryWs/1 - use it to enter to messages handling loop (in this example ws_loop/3)
-%      * ReplyChannel/1 - use to send messages to client. May be passed to other processes
-% [3]: Example of sending message to client
-% [4]: State that will be passed to message handling loop
-% [5]: Pass controll to messages handling loop. From this moment each message received from client
-%      can be handled...
-% [6]: ...here as Payload. State is variable intended for holiding your custom state. ReplyChannel
-%      is the same function as in [3].
-%      Notice! Payload is list of messages received from client. Websocket framing mechanism
-%      concatenates messages which are sent one after another in short time.
-% [7]: Print payload received from client and send it back
-% [8]: Message handling function must return new state value
-start_link() ->
-    % [1]
-    Loop = fun (Req) ->
-            ?MODULE:loop(Req)
-        end,
+%%
+%% Mochiweb websocket example
+%%
+%% [1]: At first you have to start HTTP server which will listen for HTTP
+%%      requests and eventually upgrade connection to websocket
+%% [2]: Attempt to upgrade connection to websocket.
+%%      Function mochiweb_websocket:upgrade_connection/2:
+%%      * first argument is mochiweb_request
+%%      * second is M:F which will handle further websocket messages.
+%%      Function return two funs:
+%%      * ReentryWs/1 - use it to enter to messages handling loop
+%%        (in this example ws_loop/3)
+%%      * ReplyChannel/1 - use to send messages to client. May be passed to
+%%        other processes
+%% [3]: Example of sending message to client
+%% [4]: State that will be passed to message handling loop
+%% [5]: Pass control to messages handling loop. From this moment each message
+%%      received from client can be handled...
+%% [6]: ...here as Payload. State is variable intended for holding your custom
+%%      state. ReplyChannel is the same function as in [3].
+%%      Notice! Payload is list of messages received from client. Websocket
+%%      framing mechanism concatenates messages which are sent one after another
+%%      in short time.
+%% [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, []).
 
+start_link() ->
+    %% [1]
+    io:format("Listening at http://127.0.0.1:8080/~n"),
     mochiweb_http:start_link([
-                              {name,  client_access},
-                              {loop, Loop},
+                              {name, client_access},
+                              {loop, fun ?MODULE:loop/1},
                               {port, 8080}
                              ]).
 
 ws_loop(Payload, State, ReplyChannel) ->
-    % [6]
+    %% [6]
 
-    % [7]
+    %% [7]
     io:format("Received data: ~p~n", [Payload]),
     Received = list_to_binary(Payload),
     ReplyChannel(<<"Received ", Received/binary>>),
 
-    % [8]
+    %% [8]
     State.
 
 loop(Req) ->
-    % [2]
-    {ReentryWs, ReplyChannel} = mochiweb_websocket:upgrade_connection(Req, {?MODULE, ws_loop}),
+    H = mochiweb_request:get_header_value("Upgrade", Req),
+    loop(Req, H =/= undefined andalso string:to_lower(H) =:= "websocket").
 
-    % [3]
+loop(Req, false) ->
+    mochiweb_request:serve_file("index.html", "./", Req);
+loop(Req, true) ->
+    {ReentryWs, ReplyChannel} = mochiweb_websocket:upgrade_connection(
+                                  Req, fun ?MODULE:ws_loop/3),
+    %% [3]
     ReplyChannel(<<"Hello">>),
-
-    % [4]
+    %% [4]
     InitialState = [],
-    % [5]
+    %% [5]
     ReentryWs(InitialState).

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/ecee927a/src/mochiweb_websocket.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_websocket.erl b/src/mochiweb_websocket.erl
index 1880f86..8309a11 100644
--- a/src/mochiweb_websocket.erl
+++ b/src/mochiweb_websocket.erl
@@ -45,7 +45,6 @@ request(Socket, Body, State, WsVersion, ReplyChannel) ->
             exit(normal);
 
         {tcp, _, WsFrames} ->
-            {M, F} = Body,
             case parse_frames(WsVersion, WsFrames, Socket) of
                 close ->
                     mochiweb_socket:close(Socket),
@@ -56,7 +55,7 @@ request(Socket, Body, State, WsVersion, ReplyChannel) ->
                     exit(normal);
 
                 Payload ->
-                    NewState = M:F(Payload, State, ReplyChannel),
+                    NewState = call_body(Body, Payload, State, ReplyChannel),
                     loop(Socket, Body, NewState, WsVersion, ReplyChannel)
             end;
 
@@ -65,6 +64,13 @@ request(Socket, Body, State, WsVersion, ReplyChannel) ->
             exit(normal)
     end.
 
+call_body({M, F, A}, Payload, State, ReplyChannel) ->
+    erlang:apply(M, F, [Payload, State, ReplyChannel | A]);
+call_body({M, F}, Payload, State, ReplyChannel) ->
+    M:F(Payload, State, ReplyChannel);
+call_body(Body, Payload, State, ReplyChannel) ->
+    Body(Payload, State, ReplyChannel).
+
 send(Socket, Payload, hybi) ->
     Len = payload_length(iolist_size(Payload)),
     Data = <<1:1, 0:3, 1:4, 0:1, Len/bits, Payload/binary>>,