Added the server side to the web sockets demo
This commit is contained in:
parent
c8668385d4
commit
6db5a39974
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/sh
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
echo "Running node"
|
||||||
|
node server.js $1
|
||||||
|
done
|
|
@ -0,0 +1,41 @@
|
||||||
|
var sys = require("sys"),
|
||||||
|
ws = require("./ws");
|
||||||
|
|
||||||
|
function broadcast(data, from) {
|
||||||
|
clients.forEach(function (client) {
|
||||||
|
if (client != from) {
|
||||||
|
try {
|
||||||
|
client.write(data);
|
||||||
|
} catch (e) {
|
||||||
|
clients.remove(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.prototype.remove = function(e) {
|
||||||
|
for (var i = 0; i < this.length; i++)
|
||||||
|
if (e == this[i]) return this.splice(i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var clients = [];
|
||||||
|
|
||||||
|
ws.createServer(function (websocket) {
|
||||||
|
clients.push(websocket);
|
||||||
|
|
||||||
|
websocket.addListener("connect", function (resource) {
|
||||||
|
// emitted after handshake
|
||||||
|
sys.debug("connect: " + resource);
|
||||||
|
broadcast(clients.length+'');
|
||||||
|
}).addListener("data", function (data) {
|
||||||
|
// send data to attached clients
|
||||||
|
sys.puts('sending data...');
|
||||||
|
broadcast(data, websocket);
|
||||||
|
}).addListener("close", function () {
|
||||||
|
// emitted when server or client closes connection
|
||||||
|
sys.debug("close");
|
||||||
|
clients.remove(websocket);
|
||||||
|
broadcast(clients.length+'');
|
||||||
|
});
|
||||||
|
}).listen(parseInt(process.ARGV[2]) || 8000);
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
// Github: http://github.com/ncr/node.ws.js
|
||||||
|
// Compatible with node v0.1.91
|
||||||
|
// Author: Jacek Becela
|
||||||
|
// License: MIT
|
||||||
|
// Based on: http://github.com/Guille/node.websocket.js
|
||||||
|
|
||||||
|
function nano(template, data) {
|
||||||
|
return template.replace(/\{([\w\.]*)}/g, function (str, key) {
|
||||||
|
var keys = key.split("."), value = data[keys.shift()];
|
||||||
|
keys.forEach(function (key) { value = value[key] });
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var sys = require("sys"),
|
||||||
|
net = require("net"),
|
||||||
|
headerExpressions = [
|
||||||
|
/^GET (\/[^\s]*) HTTP\/1\.1$/,
|
||||||
|
/^Upgrade: WebSocket$/,
|
||||||
|
/^Connection: Upgrade$/,
|
||||||
|
/^Host: (.+)$/,
|
||||||
|
/^Origin: (.+)$/
|
||||||
|
],
|
||||||
|
handshakeTemplate = [
|
||||||
|
'HTTP/1.1 101 Web Socket Protocol Handshake',
|
||||||
|
'Upgrade: WebSocket',
|
||||||
|
'Connection: Upgrade',
|
||||||
|
'WebSocket-Origin: {origin}',
|
||||||
|
'WebSocket-Location: ws://{host}{resource}',
|
||||||
|
'',
|
||||||
|
''
|
||||||
|
].join("\r\n"),
|
||||||
|
policy_file = '<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>';
|
||||||
|
|
||||||
|
exports.createServer = function (websocketListener) {
|
||||||
|
return net.createServer(function (socket) {
|
||||||
|
socket.setTimeout(0);
|
||||||
|
socket.setNoDelay(true);
|
||||||
|
socket.setEncoding("utf8");
|
||||||
|
|
||||||
|
var emitter = new process.EventEmitter(),
|
||||||
|
handshaked = false,
|
||||||
|
buffer = "";
|
||||||
|
|
||||||
|
function handle(data) {
|
||||||
|
buffer += data;
|
||||||
|
|
||||||
|
var chunks = buffer.split("\ufffd"),
|
||||||
|
count = chunks.length - 1; // last is "" or a partial packet
|
||||||
|
|
||||||
|
for(var i = 0; i < count; i++) {
|
||||||
|
var chunk = chunks[i];
|
||||||
|
if(chunk[0] == "\u0000") {
|
||||||
|
emitter.emit("data", chunk.slice(1));
|
||||||
|
} else {
|
||||||
|
socket.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = chunks[count];
|
||||||
|
}
|
||||||
|
|
||||||
|
function handshake(data) {
|
||||||
|
var headers = data.split("\r\n");
|
||||||
|
|
||||||
|
if(/<policy-file-request.*>/.exec(headers[0])) {
|
||||||
|
socket.write(policy_file);
|
||||||
|
socket.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var matches = [], match;
|
||||||
|
for (var i = 0, l = headerExpressions.length; i < l; i++) {
|
||||||
|
match = headerExpressions[i].exec(headers[i]);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
if(match.length > 1) {
|
||||||
|
matches.push(match[1]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
socket.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.write(nano(handshakeTemplate, {
|
||||||
|
resource: matches[0],
|
||||||
|
host: matches[1],
|
||||||
|
origin: matches[2],
|
||||||
|
}));
|
||||||
|
|
||||||
|
handshaked = true;
|
||||||
|
emitter.emit("connect", matches[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.addListener("data", function (data) {
|
||||||
|
if(handshaked) {
|
||||||
|
handle(data);
|
||||||
|
} else {
|
||||||
|
handshake(data);
|
||||||
|
}
|
||||||
|
}).addListener("end", function () {
|
||||||
|
socket.end();
|
||||||
|
}).addListener("close", function () {
|
||||||
|
if (handshaked) { // don't emit close from policy-requests
|
||||||
|
emitter.emit("close");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.remoteAddress = socket.remoteAddress;
|
||||||
|
|
||||||
|
emitter.write = function (data) {
|
||||||
|
try {
|
||||||
|
socket.write('\u0000', 'binary');
|
||||||
|
socket.write(data, 'utf8');
|
||||||
|
socket.write('\uffff', 'binary');
|
||||||
|
} catch(e) {
|
||||||
|
// Socket not open for writing,
|
||||||
|
// should get "close" event just before.
|
||||||
|
socket.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.end = function () {
|
||||||
|
socket.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
websocketListener(emitter); // emits: "connect", "data", "close", provides: write(data), end()
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue