User:Csmith1991/Vibe.d Documentation/websocket
< User:Csmith1991 | Vibe.d Documentation
Revision as of 02:21, 12 May 2015 by Csmith1991 (talk | contribs) (→Vibe.d Websocket's Tutorial -- added code)
Contents
Vibe.d Websocket's Tutorial
This tutorial is extended from here. Instead of a simple counter, this provides a functioning web chat application.
Folder Structure
. ├── public/ | ├── index.html | └── scripts/ | └── websocket.js ├── source/ | └── app.d
index.html
<!DOCTYPE html>
<html>
<head>
<title>WebSockets Client</title>
<style>
#chatLog {
height: 400px;
padding-bottom: 20px;
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
module webSocketExample;
import vibe.d;
import vibe.utils.array;
private WebSocket[] sockets;
shared static this()
{
/// Use /ws to identify websocket requests, serve files out of the public folder otherwise
auto router = new URLRouter;
router.get("/", staticRedirect("/index.html"));
router.get("/ws", handleWebSockets(&handleWebSocketConnection));
router.get("*", serveStaticFiles("public/"));
auto settings = new HTTPServerSettings;
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
listenHTTP(settings, router);
}
void handleWebSocketConnection(scope WebSocket socket)
{
// Add socket to sockets list
sockets ~= socket;
// Get username
socket.waitForData(1.seconds);
string name = socket.receiveText;
// Server-side validation of results
if (name !is null)
{
logInfo("%s connected @ %s.", name, socket.request.peer);
sendTextToOtherClients(null, "System", name ~ " connected to the chat.");
}
else
{
// Kick person out
socket.send("{\"name\":\"System\", \"text\":\"Invalid name.\"}");
socket.close;
sockets.removeFromArray!WebSocket(socket);
logInfo("%s disconnected.", name);
return;
}
// message loop
while (socket.waitForData)
{
if (!socket.connected) break;
// we got something
auto text = socket.receiveText;
// Close if recieve "/close"
if (text == "/close") break;
logInfo("Received: \"%s\" from %s.", text, name);
// Relay text to everyone else
sendTextToOtherClients(socket, name, text);
}
// Remove socket from sockets list and close socket
socket.close;
sockets.removeFromArray!WebSocket(socket);
logInfo("%s disconnected.", name);
sendTextToOtherClients(null, "System", name ~ " disconnected to the chat.");
}
void sendTextToOtherClients(scope WebSocket src_socket, string name, string text)
{
foreach (socket; sockets)
{
// Don't send it to people who won't get it.
if (!socket.connected) continue;
logInfo("Sending: \"%s\" to %s.", text, socket.request.peer);
// JSON encoding for simplicity
socket.send("{\"name\":\"" ~ name ~ "\", \"text\":\"" ~ text ~ "\"}");
}
}