The Chicago Boss API is mostly stable, but still might change before 1.0.

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. Note that WebSockets are only supported with Cowboy, so put {server, cowboy} in your boss.config before attempting anything on this page.

Server code

The server WebSocket API is based around Erlang message-passing; to send a message to a particular client, simply send it a message like:

WebSocket ! {text, <<"some text">>}

Furthermore, you can broadcast a message that will be handled by your handle_broadcast/2 function by using the module name of your websocket module and the proper method of the boss_service_worker module:

boss_service_worker:broadcast(myapp_myservice_websocket, MyMessage).

To handle incoming messages from clients, you'll need to create WebSocket controllers in your project's src/websocket directory. Each controller module should have a name of the form <app name>_<service name>_websocket.erl and be a parameterized module with parameters for Req and SessionId, e.g.:

-module(myapp_myservice_websocket, [Req, SessionId]).

The module should implement the boss_service_handler behavior. The boss_service_handler behavior consists of the following six functions:

init() -> {ok, InitialState}

Initialize the service.

handle_join(ServiceURL::string(), WebSocket::pid(), State) ->
  {noreply, NewState} |
  {noreply, NewState, Timeout} |
  {stop, Reason, NewState

Handle a client joining a service.

handle_close(Reason::terminate_reason(), ServiceURL::string(), WebSocket::pid(), State) ->
  {noreply, NewState} |
  {noreply, NewState, Timeout} |
  {stop, Reason, NewState}

  -type terminate_reason() :: {normal, shutdown}
  | {normal, timeout}
  | {error, closed}
  | {remote, closed}
  | {remote, cowboy_websocket:close_code(), binary()}
  | {error, badencoding}
  | {error, badframe}
  | {error, atom()}.

Handle a client leaving a service.

handle_incoming(ServiceURL::string(), WebSocket::pid(), Message, State) ->
  {noreply, NewState} |
  {noreply, NewState, Timeout} |
  {stop, Reason, NewState}

Handle an incoming message from a client.

handle_broadcast(Message::term(), State) ->
  {noreply, NewState} |
  {noreply, NewState, Timeout} |
  {stop, Reason, NewState}

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.

handle_info(Info, State) ->
  {noreply, NewState} |
  {noreply, NewState, Timeout} |
  {stop, Reason, NewState}

Handle an informational message sent to the underlying gen_server process.

terminate(Reason, State) -> ok

Perform any cleanup before shutting down the service.

Client code

WebSocket URLs are automatically generated from the WebSocket controllers in your project's src/websocket directory. For example, if you have myapp_foobar_websocket.erl, then to create a new WebSocket on the client:

<script type="text/javascript">
  wsc = new WebSocket("ws://localhost:8001/websocket/foobar", "some_service_name");
</script>

The WebSocket URLs respect the base_url config parameter. For example, if the base_url is set to "/chat", then you would use this code instead:

<script type="text/javascript">
  wsc = new WebSocket("ws://localhost:8001/chat/websocket/foobar", "some_service_name");
</script>

For a reference on the WebSocket client programming, see Mozilla's WebSockets page.