Permalink
Fetching contributors…
Cannot retrieve contributors at this time
115 lines (99 sloc) 4.97 KB
{% extends "api.html" %}
{% block api_content %}
<p>WebSockets are an HTML5 technology used for two-way messaging from inside a web page. As of version 0.8.0,
Chicago Boss provides infrastructure for defining one or more WebSocket controllers.</p>
<h2>Server code</h2>
<p>The server WebSocket API is based around Erlang message-passing; to send a message to a particular client, simply send it a message like:</p>
<div class="code">
WebSocket ! {text, &lt;&lt;"some text"&gt;&gt;}
</div>
<p>Furthermore, you can broadcast a message that will be handled by your <em>handle_broadcast/2</em> function by using the module name of your websocket module and the proper method of the <em>boss_service_worker</em> module:</p>
<div class="code">
boss_service_worker:broadcast(myapp_myservice_websocket, MyMessage).
</div>
<p>To handle incoming messages from clients, you'll need to create WebSocket controllers in your project's <code>src/websocket</code> directory. Each controller module should have a name of the form <code>&lt;app name&gt;_&lt;service name&gt;_websocket.erl</code> and be a parameterized module with parameters for <code>Req</code> and <code>SessionId</code>, e.g.:</p>
<div class="code">
-module(myapp_myservice_websocket, [Req, SessionId]).
</div>
<p>The module should implement the <code>boss_service_handler</code> behavior. The <code>boss_service_handler</code> behavior consists of the following six functions:</p>
<div class="code spec">
init() -&gt; {ok, InitialState}
</div>
<p>Initialize the service.</p>
<div class="code spec">
handle_join(ServiceURL::string(), WebSocket::pid(), State) -&gt; <br>
&nbsp;&nbsp;{noreply, NewState} |<br>
&nbsp;&nbsp;{noreply, NewState, Timeout} |<br>
&nbsp;&nbsp;{stop, Reason, NewState
</div>
<p>Handle a client joining a service.</p>
<div class="code spec">
handle_close(Reason::terminate_reason(), ServiceURL::string(), WebSocket::pid(), State) -&gt; <br>
&nbsp;&nbsp;{noreply, NewState} |<br>
&nbsp;&nbsp;{noreply, NewState, Timeout} |<br>
&nbsp;&nbsp;{stop, Reason, NewState}
<br><br>
&nbsp;&nbsp;-type terminate_reason() :: {normal, shutdown}<br>
&nbsp;&nbsp;| {normal, timeout}<br>
&nbsp;&nbsp;| {error, closed}<br>
&nbsp;&nbsp;| {remote, closed}<br>
&nbsp;&nbsp;| {remote, cowboy_websocket:close_code(), binary()}<br>
&nbsp;&nbsp;| {error, badencoding}<br>
&nbsp;&nbsp;| {error, badframe}<br>
&nbsp;&nbsp;| {error, atom()}.<br>
</div>
<p>Handle a client leaving a service.</p>
<div class="code spec">
handle_incoming(ServiceURL::string(), WebSocket::pid(), Message, State) -&gt;<br>
&nbsp;&nbsp;{noreply, NewState} |<br>
&nbsp;&nbsp;{noreply, NewState, Timeout} |<br>
&nbsp;&nbsp;{stop, Reason, NewState}
</div>
<p>Handle an incoming message from a client.</p>
<div class="code spec">
handle_broadcast(Message::term(), State) -&gt;<br>
&nbsp;&nbsp;{noreply, NewState} |<br>
&nbsp;&nbsp;{noreply, NewState, Timeout} |<br>
&nbsp;&nbsp;{stop, Reason, NewState}
</div>
<p>Handle an outgoing broadcast message from some Erlang process to
the connected web sockets. It is your responsibility to keep track of
the web sockets (via handle_join and handle_close) and send the
outgoing messages as you see fit.</p>
<div class="code spec">
handle_info(Info, State) -&gt;<br>
&nbsp;&nbsp;{noreply, NewState} |<br>
&nbsp;&nbsp;{noreply, NewState, Timeout} |<br>
&nbsp;&nbsp;{stop, Reason, NewState}
</div>
<p>Handle an informational message sent to the underlying gen_server process.</p>
<div class="code spec">
terminate(Reason, State) -&gt; ok
</div>
<p>Perform any cleanup before shutting down the service.</p>
<h2>Client code</h2>
<p>WebSocket URLs are automatically generated from the WebSocket controllers in your project's <code>src/websocket</code> directory. For example, if you have <code>myapp_foobar_websocket.erl</code>, then to create a new WebSocket on the client:</p>
<div class="code">
&lt;script type="text/javascript"&gt;<br>
&nbsp;&nbsp;wsc = new WebSocket("ws://localhost:8001/websocket/foobar", "some_service_name");<br>
&lt;/script&gt;
</div>
<p>The WebSocket URLs respect the <code>base_url</code> config parameter. For example, if the <code>base_url</code> is set to "/chat", then you would use this code instead:</p>
<div class="code">
&lt;script type="text/javascript"&gt;<br>
&nbsp;&nbsp;wsc = new WebSocket("ws://localhost:8001/chat/websocket/foobar", "some_service_name");<br>
&lt;/script&gt;
</div>
<p>For a reference on the WebSocket client programming, see <a href="https://developer.mozilla.org/en/WebSockets/">Mozilla's WebSockets page</a>.</p>
<h2>Configuration</h2>
If you're behind a reverse proxy like nginx, you need to make sure nginx is properly forwarding the websocket requests by adding the following rules:
<code>
<pre>
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
</pre>
</code>
{% endblock %}