Skip to content

Instantly share code, notes, and snippets.

@noggs
Created May 16, 2012 08:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save noggs/2708744 to your computer and use it in GitHub Desktop.
Save noggs/2708744 to your computer and use it in GitHub Desktop.
node.js echo test
"use strict";
var http = require('http');
var fs = require('fs');
var WebSocketServer = require('websocket').server;
var clients = [];
var next_client = 0;
var mainHtml = (function () {
var f;
try {
f = fs.readFileSync('main.html');
} catch (e) {}
return f;
}());
var server = http.createServer(function (req, res) {
// send our only page!
if (mainHtml !== undefined) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(mainHtml);
} else {
res.writeHead(404);
res.end();
}
}).listen(1337);
console.log('Server running');
var wsServer = new WebSocketServer({
httpServer : server
});
// WebSocket server
wsServer.on('request', function (request) {
var connection = request.accept(null, request.origin),
client_id,
sendClientList = function () {
// send client_list to everyone
var i,
msg = {
type : 'client_list',
clients : []
};
for (i in clients) {
if (clients.hasOwnProperty(i)) {
msg.clients.push(i);
}
}
for (i in clients) {
if (clients.hasOwnProperty(i)) {
msg.own_client_id = parseInt(i, 10);
clients[i].sendUTF(JSON.stringify(msg));
}
}
};
client_id = next_client += 1;
clients[client_id] = connection;
// This is the most important callback for us, we'll handle
// all messages from users here.
connection.on('message', function (message) {
var i,
response;
if (message.type === 'utf8') {
response = JSON.parse(message.utf8Data);
response.client_id = client_id;
response.type = 'echo';
// echo message to all clients
response = JSON.stringify(response);
for (i in clients) {
if (clients.hasOwnProperty(i)) {
clients[i].sendUTF(response);
}
}
}
});
connection.on('close', function (connection) {
// close user connection
delete clients[client_id];
sendClientList();
});
// send updated client_list to everyone
sendClientList();
});
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Google App Engine - Channel API Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
</head>
<body>
<div id="loggingArea" style="overflow:auto; height:400px;">
</div>
<div id="results" style="height:200px;">
<div>
<button type="button" id="send_button">SEND</button>
<button type="button" id="send5_button">SEND 5</button>
<input type="text" id="message" value="echo!" style="width:300px;"/>
</div>
<div>
<div>
Missing replies: <span id="missing_replies"></span>
</div>
<div>
Average latency: <span id="average_latency"></span>
</div>
<div>
Clients: [<span id="client_list"></span>]
</div>
</div>
</div>
<script>
/*global jQuery*/
/*jslint browser: true, maxerr: 50, indent: 4*/
(function () {
"use strict";
jQuery(function () {
var logging = function (msg) {
var e = document.getElementById("loggingArea");
e.innerHTML += '<br>' + msg;
e.scrollTop = e.scrollHeight; // auto scroll
},
connected = false,
connection,
client_id,
clientSequence = 0,
clientSequences = [],
updateMissingReplies = function () {
var missingRepliesElement = document.getElementById("missing_replies"),
i;
missingRepliesElement.innerHTML = clientSequences.length.toString();
for (i = 0; i < clientSequences.length; i += 1) {
if (i === 0) {
missingRepliesElement.innerHTML += " [";
}
missingRepliesElement.innerHTML += clientSequences[i].toString();
if (i === clientSequences.length - 1) {
missingRepliesElement.innerHTML += "]";
} else {
missingRepliesElement.innerHTML += ", ";
}
}
},
latencies = [],
updateAverageLatency = function (latency) {
var element = document.getElementById("average_latency"),
i,
avgStart,
runningAvg = 0,
runningAvgLength = 0,
numLatencies;
latencies.push(latency);
numLatencies = latencies.length;
avgStart = Math.max(0, numLatencies - 5);
runningAvgLength = numLatencies - avgStart;
for (i = avgStart; i < numLatencies; i += 1) {
runningAvg += latencies[i];
}
runningAvg /= runningAvgLength;
element.innerHTML = runningAvg.toFixed(1) + 'ms';
},
sendMessage = function (msg) {
var data;
if (connected) {
data = {
clientSeq : clientSequence,
timestamp : Date.now(),
msg : msg
};
connection.send(JSON.stringify(data));
clientSequence += 1;
logging("SEND [" + data.clientSeq.toString() + "] \"" + data.msg + "\"");
clientSequences.push(data.clientSeq);
updateMissingReplies();
}
},
handleEcho = function (msg) {
var log_entry,
time = Date.now(),
total_latency,
replyIndex;
if (msg) {
msg.server_time = parseInt(msg.server_time, 10);
msg.timestamp = parseInt(msg.timestamp, 10);
total_latency = time - msg.timestamp;
log_entry = "RECV [" + msg.client_id + " " + msg.clientSeq.toString() + "]" +
" (" + total_latency.toString() + "ms)" +
" \"" + msg.msg + "\"";
logging(log_entry);
if (msg.client_id === client_id) {
replyIndex = clientSequences.indexOf(msg.clientSeq);
if (replyIndex !== -1) {
clientSequences.splice(replyIndex, 1);
} else {
logging("DUPLICATE MESSAGE RECEIVED");
}
updateMissingReplies();
updateAverageLatency(total_latency);
}
}
},
handleClientList = function (msg) {
var element = document.getElementById('client_list'),
i,
str = "",
own_id_str = "";
if (msg.clients instanceof Array) {
for (i = 0; i < msg.clients.length; i += 1) {
if (i > 0) {
str += ", ";
}
str += msg.clients[i];
}
}
if (msg.own_client_id !== undefined) {
client_id = msg.own_client_id;
own_id_str = client_id.toString();
}
element.innerHTML = str;
logging("RECV client_list [" + str + "] (" + own_id_str + ")");
},
message_handlers = {
'echo' : handleEcho,
'client_list' : handleClientList
},
WebSocket = window.WebSocket || window.MozWebSocket;
logging("Connecting to server...");
connection = new WebSocket('ws://echo_test.jit.su');
//connection = new WebSocket('ws://127.0.0.1:1337');
connection.onopen = function () {
connected = true;
logging("===============================================");
logging("Connected");
};
connection.onerror = function (error) {
logging("error (" + error.code + ": " + error.description);
};
connection.onclose = function () {
connected = false;
logging("Disconnected from [" + client_id + "]");
logging("===============================================");
};
connection.onmessage = function (msg) {
var data = jQuery.parseJSON(msg.data),
handler;
if (data !== undefined) {
handler = message_handlers[data.type];
if (handler !== undefined) {
handler(data);
} else {
logging("unhandled message type: " + data.type);
}
} else {
logging("ignoring malformed message: " + msg);
}
};
document.getElementById('send_button').onclick = function () {
var msg = document.getElementById('message').value;
sendMessage(msg);
};
document.getElementById('send5_button').onclick = function () {
var msg = document.getElementById('message').value,
i;
for (i = 0; i < 5; i += 1) {
sendMessage(msg);
}
};
});
}());
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment