Vibe.d Websockets Tutorial

This tutorial is extended from here. Instead of a simple counter, this provides a functioning web chat application.

WebSockets overview

WebSocket: First and foremost, a WebSocket starts with a secret WebSocket handshake for you. This secret handshake basically allows us to treat our previous HTTP(S) connection as a stateful connection. Having a stateful connection allows us to do things previously unavailable on our webpage. This connection could handle something from the simple chat client in this example, to an entire realtime video game. Additionally, the entire connection is handled over port 80, which is generally open, so there's little concern there. As of May 16, 2015, all major browsers support the upgrade request required to establish the socket connection.

NOTE The URI Scheme changes from http/https to ws/wss respectively. Without this, you're not using websockets.





Vibe API

Vibe handles everything within vibe.http.websockets. When you implement a Websocket listener you need to specify scope. This is because you're dealing with a single websocket.

The main methods you use on a websocket are:

read() : Read incoming data from the connection.

: Read incoming data from the connection. send(): Send data to the connection.

In the example we send all our data as text.

Code

As with any code example, you've probably skipped the text above, and just want a quick example of how things work. This is perfectly fine, just read the javascript function connect() and handleWebSocketConnection() from the d code.

Files

. ├── public/ | ├── index.html | └── scripts/ | └── websocket.js ├── source/ | └── app.d

index.html

<!DOCTYPE html> < html > < head > < title > WebSockets Client </ title > < style > # chatLog { height : 400 px ; padding-bottom : 20 px ; overflow-y : scroll ; } </ style > </ head > < body > < h1 > WebSockets Client </ h1 > < div id = "chatLog" ></ div > <!-- this is where we'll insert chat into --> < div id = "login" > <!-- {which: 13} is a hack to make the button function the same as onkeypress --> < input id = "name" type = "text" placeholder = "Your Name" onkeypress = "startConnection(event);" /> < button id = "connect" onclick = "startConnection({which: 13});" > Connect </ button > </ div > < div id = "chat" style = "display:none;" > < input id = "text" type = "text" placeholder = "press enter to submit" onkeypress = "chat(event);" /> < button id = "send" onclick = "chat({which: 13});" > Send </ button >< br /> < button id = "disconnect" onclick = "endConnection();" > Disconnect </ button > </ div > < script src = "/scripts/websocket.js" ></ script > </ body > </ html >

websocket.js

// Keep socket variable at global level var socket = {}; function connect ( name ) { try { // Test if websocket doesn't exist, and if not, create a new connection if ( ! ( 'readyState' in socket )) { socket = new WebSocket ( getBaseURL () + '/ws' ); } socket . onopen = function () { try { socket . send ( name ); // Tell the server who you are, handle validation server side! // Swap the chat and login divs around document . getElementById ( 'name' ). value = '' ; document . getElementById ( 'login' ). style . display = 'none' ; document . getElementById ( 'chat' ). style . display = 'block' ; document . getElementById ( 'text' ). focus (); } catch ( exception ) { alert ( exception ); } } socket . onmessage = function ( msg ) { var msgVal = JSON . parse ( msg . data ); // We're anticipating messages formatted as "{'name':'Csmith1991', 'text':'example'}" var chatLog = document . getElementById ( 'chatLog' ); chatLog . innerHTML += '<p>' + msgVal . name + ': ' + msgVal . text + '</p>' ; // Add to the chatLog chatLog . scrollTop = chatLog . scrollHeight ; // Scroll chatLog to bottom } socket . onclose = function () { socket = {}; // Remove socket connection // Swap the chat and login divs around. Note we don't do this until the connection has closed. document . getElementById ( 'chat' ). style . display = 'none' ; document . getElementById ( 'login' ). style . display = 'block' ; document . getElementById ( 'name' ). focus (); } } catch ( exception ) { alert ( exception ); } } function startConnection ( event ) { // 13 = enter button if ( event . which === 13 || event . keyCode === 13 ) { // Connect to WebSocket server connect ( document . getElementById ( 'name' ). value ); } } function chat ( event ) { if ( event . which === 13 || event . keyCode === 13 ) { var myObj = document . getElementById ( 'text' ); socket . send ( myObj . value ); myObj . value = '' ; myObj . focus (); } } function endConnection () { // We want to close the connection on the server, so we create a message that the server listens for to close on socket . send ( '/close' ); } function getBaseURL () { // Get the WebSocket server address e.g. ws://127.0.0.1:8080 var href = window . location . href . substring ( 7 ); // strip "http://" var idx = href . indexOf ( '/' ); return 'ws://' + href . substring ( 0 , idx ); }

app.d