mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-11 16:08:24 -05:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d79de5aa56 | ||
|
|
06769c4ca7 | ||
|
|
df876e37df | ||
|
|
31d119740c | ||
|
|
f3c28e298a | ||
|
|
71d80181fa | ||
|
|
0e483a05a5 | ||
|
|
c1fca0c520 | ||
|
|
1918b75360 | ||
|
|
5e255ccdf9 | ||
|
|
9a306fddab | ||
|
|
dc593e9972 | ||
|
|
7f5228abc3 | ||
|
|
0ad237ddf5 | ||
|
|
3134940ed6 | ||
|
|
0f783bc06a | ||
|
|
dd3d829173 | ||
|
|
fbce6379a5 |
11
README.md
11
README.md
@@ -36,12 +36,15 @@ By default, the server will intercept requests that contain `socket.io` in the p
|
||||
|
||||
On the client side, you should use the [Socket.IO client](https://github.com/LearnBoost/Socket.IO) to connect.
|
||||
|
||||
## Checking out
|
||||
## Notes
|
||||
|
||||
After cloning the repository, remember to run
|
||||
IMPORTANT! When checking out the git repo, make sure to include the submodules. One way to do it is:
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
git clone [repo] --recursive
|
||||
|
||||
Another, once cloned
|
||||
|
||||
git submodule update --init --recursive
|
||||
|
||||
## Demo
|
||||
|
||||
|
||||
@@ -1,29 +1,37 @@
|
||||
var Options = require('./util/options').Options;
|
||||
var options = require('./util/options').options, urlparse = require('url').parse;
|
||||
|
||||
this.Client = Class({
|
||||
exports.Client = Class({
|
||||
|
||||
include: [Options],
|
||||
include: [options],
|
||||
|
||||
options: {
|
||||
closeTimeout: 0
|
||||
closeTimeout: 0,
|
||||
heartbeatInterval: 5000
|
||||
},
|
||||
|
||||
init: function(listener, req, res, options){
|
||||
init: function(listener, req, res, options, head){
|
||||
this.listener = listener;
|
||||
this.setOptions(options);
|
||||
this.connections = 0;
|
||||
this.connected = false;
|
||||
this.upgradeHead = head;
|
||||
this._onConnect(req, res);
|
||||
},
|
||||
|
||||
send: function(message){
|
||||
if (!this.connected || !(this.connection.readyState == 'open' || this.connection.readyState == 'writeOnly')) return this._queue(message);
|
||||
if (!this.connected || !(this.connection.readyState === 'open' ||
|
||||
this.connection.readyState === 'writeOnly')) {
|
||||
return this._queue(message);
|
||||
}
|
||||
|
||||
this._write(JSON.stringify({messages: [message]}));
|
||||
return this;
|
||||
},
|
||||
|
||||
broadcast: function(message){
|
||||
if (!('sessionId' in this)) return this;
|
||||
if (!('sessionId' in this)) {
|
||||
return this;
|
||||
}
|
||||
this.listener.broadcast(message, this.sessionId);
|
||||
return this;
|
||||
},
|
||||
@@ -44,7 +52,9 @@ this.Client = Class({
|
||||
this.request = req;
|
||||
this.response = res;
|
||||
this.connection = this.request.connection;
|
||||
if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
|
||||
if (this._disconnectTimeout) {
|
||||
clearTimeout(this._disconnectTimeout);
|
||||
}
|
||||
},
|
||||
|
||||
_payload: function(){
|
||||
@@ -64,12 +74,19 @@ this.Client = Class({
|
||||
payload = payload.concat(this._writeQueue || []);
|
||||
this._writeQueue = [];
|
||||
|
||||
if (payload.length) this._write(JSON.stringify({messages: payload}));
|
||||
if (this.connections == 1) this.listener._onClientConnect(this);
|
||||
if (payload.length) {
|
||||
this._write(JSON.stringify({messages: payload}));
|
||||
}
|
||||
if (this.connections === 1) {
|
||||
this.listener._onClientConnect(this);
|
||||
}
|
||||
},
|
||||
|
||||
_onClose: function(){
|
||||
var self = this;
|
||||
if (this._heartbeatInterval) {
|
||||
clearInterval(this._heartbeatInterval);
|
||||
}
|
||||
this.connected = false;
|
||||
this._disconnectTimeout = setTimeout(function(){
|
||||
self._onDisconnect();
|
||||
@@ -81,20 +98,34 @@ this.Client = Class({
|
||||
this._writeQueue = [];
|
||||
this.connected = false;
|
||||
this.finalized = true;
|
||||
if (this.handshaked) this.listener._onClientDisconnect(this);
|
||||
if (this.handshaked) {
|
||||
this.listener._onClientDisconnect(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_queue: function(message){
|
||||
if (!('_writeQueue' in this)) this._writeQueue = [];
|
||||
if (!('_writeQueue' in this)) {
|
||||
this._writeQueue = [];
|
||||
}
|
||||
this._writeQueue.push(message);
|
||||
return this;
|
||||
},
|
||||
|
||||
_generateSessionId: function(){
|
||||
if (this.sessionId) return this.listener.options.log('This client already has a session id');
|
||||
if (this.sessionId) {
|
||||
return this.listener.options.log('This client already has a session id');
|
||||
}
|
||||
this.sessionId = Math.random().toString().substr(2);
|
||||
return this;
|
||||
},
|
||||
|
||||
_verifyOrigin: function(origin){
|
||||
var parts = urlparse(origin), origins = this.listener.options.origins;
|
||||
return origins.indexOf('*:*') !== -1 ||
|
||||
origins.indexOf(parts.host + ':' + parts.port) !== -1 ||
|
||||
origins.indexOf(parts.host + ':*') !== -1 ||
|
||||
origins.indexOf('*:' + parts.port) !== -1;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,13 +1,11 @@
|
||||
var url = require('url'),
|
||||
sys = require('sys'),
|
||||
Options = require('./util/options').Options,
|
||||
Client = require('./client').Client,
|
||||
options = require('./util/options').options,
|
||||
Client = require('./client').Client,
|
||||
transports = {};
|
||||
|
||||
Transports = {};
|
||||
|
||||
Listener = this.Listener = Class({
|
||||
var Listener = exports.Listener = Class({
|
||||
|
||||
include: [process.EventEmitter.prototype, Options],
|
||||
include: [process.EventEmitter.prototype, options],
|
||||
|
||||
options: {
|
||||
origins: '*:*',
|
||||
@@ -15,7 +13,7 @@ Listener = this.Listener = Class({
|
||||
transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling'],
|
||||
transportOptions: {},
|
||||
log: function(message){
|
||||
sys.log(message);
|
||||
require('sys').log(message);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -27,28 +25,26 @@ Listener = this.Listener = Class({
|
||||
this.clients = [];
|
||||
this.clientsIndex = {};
|
||||
|
||||
var listener = (this.server._events['request'] instanceof Array)
|
||||
? this.server._events['request'][0]
|
||||
: this.server._events['request'];
|
||||
if (listener){
|
||||
this.server._events['request'] = function(req, res){
|
||||
if (self.check(req, res)) return;
|
||||
listener(req, res);
|
||||
};
|
||||
} else {
|
||||
throw new Error('Couldn\'t find the `request` event in the HTTP server.');
|
||||
}
|
||||
var listeners = this.server.listeners('request');
|
||||
this.server.removeAllListeners('request');
|
||||
|
||||
this.server.addListener('request', function(req, res){
|
||||
if (self.check(req, res)) return;
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
listeners[i].call(this, req, res);
|
||||
}
|
||||
});
|
||||
|
||||
this.server.addListener('upgrade', function(req, socket, head){
|
||||
if (!self.check(req, socket, true)){
|
||||
if (!self.check(req, socket, true, head)){
|
||||
socket.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
this.options.transports.forEach(function(t){
|
||||
if (!(t in Transports)){
|
||||
Transports[t] = require('./transports/' + t)[t];
|
||||
if (Transports[t].init) Transports[t].init(this);
|
||||
if (!(t in transports)){
|
||||
transports[t] = require('./transports/' + t)[t];
|
||||
if (transports[t].init) transports[t].init(this);
|
||||
}
|
||||
}, this);
|
||||
|
||||
@@ -64,7 +60,7 @@ Listener = this.Listener = Class({
|
||||
return this;
|
||||
},
|
||||
|
||||
check: function(req, res, httpUpgrade){
|
||||
check: function(req, res, httpUpgrade, head){
|
||||
var path = url.parse(req.url).pathname, parts, cn;
|
||||
if (path.indexOf('/' + this.options.resource) === 0){
|
||||
parts = path.substr(1).split('/');
|
||||
@@ -74,10 +70,10 @@ Listener = this.Listener = Class({
|
||||
cn._onConnect(req, res);
|
||||
} else {
|
||||
req.connection.end();
|
||||
sys.log('Couldnt find client with session id "' + parts[2] + '"');
|
||||
this.options.log('Couldnt find client with session id "' + parts[2] + '"');
|
||||
}
|
||||
} else {
|
||||
this._onConnection(parts[1], req, res, httpUpgrade);
|
||||
this._onConnection(parts[1], req, res, httpUpgrade, head);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -90,12 +86,12 @@ Listener = this.Listener = Class({
|
||||
|
||||
_onClientConnect: function(client){
|
||||
if (!(client instanceof Client) || !client.sessionId){
|
||||
return sys.log('Invalid client');
|
||||
return this.options.log('Invalid client');
|
||||
}
|
||||
client.i = this.clients.length;
|
||||
this.clients.push(client);
|
||||
this.clientsIndex[client.sessionId] = client;
|
||||
sys.log('Client '+ client.sessionId +' connected');
|
||||
this.options.log('Client '+ client.sessionId +' connected');
|
||||
this.emit('clientConnect', client);
|
||||
},
|
||||
|
||||
@@ -106,18 +102,18 @@ Listener = this.Listener = Class({
|
||||
_onClientDisconnect: function(client){
|
||||
this.clientsIndex[client.sessionId] = null;
|
||||
this.clients[client.i] = null;
|
||||
sys.log('Client '+ client.sessionId +' disconnected');
|
||||
this.options.log('Client '+ client.sessionId +' disconnected');
|
||||
this.emit('clientDisconnect', client);
|
||||
},
|
||||
|
||||
// new connections (no session id)
|
||||
_onConnection: function(transport, req, res, httpUpgrade){
|
||||
if (this.options.transports.indexOf(transport) === -1 || (httpUpgrade && !Transports[transport].httpUpgrade)){
|
||||
_onConnection: function(transport, req, res, httpUpgrade, head){
|
||||
if (this.options.transports.indexOf(transport) === -1 || (httpUpgrade && !transports[transport].httpUpgrade)){
|
||||
httpUpgrade ? res.destroy() : req.connection.destroy();
|
||||
return sys.log('Illegal transport "'+ transport +'"');
|
||||
return this.options.log('Illegal transport "'+ transport +'"');
|
||||
}
|
||||
sys.log('Initializing client with transport "'+ transport +'"');
|
||||
new Transports[transport](this, req, res, this.options.transportOptions[transport]);
|
||||
this.options.log('Initializing client with transport "'+ transport +'"');
|
||||
new transports[transport](this, req, res, this.options.transportOptions[transport], head);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,9 +2,9 @@ var websocket = require('./websocket').websocket,
|
||||
net = require('net'),
|
||||
listeners = [];
|
||||
|
||||
this.flashsocket = websocket.extend({});
|
||||
this.flashsocket.httpUpgrade = true;
|
||||
this.flashsocket.init = function(listener){
|
||||
exports.flashsocket = websocket.extend({});
|
||||
exports.flashsocket.httpUpgrade = true;
|
||||
exports.flashsocket.init = function(listener){
|
||||
listeners.push(listener);
|
||||
};
|
||||
|
||||
@@ -22,4 +22,4 @@ net.createServer(function(socket){
|
||||
|
||||
socket.write('</cross-domain-policy>\n');
|
||||
socket.end();
|
||||
}).listen(843);
|
||||
}).listen(843);
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
var Client = require('../client').Client,
|
||||
qs = require('querystring');
|
||||
|
||||
this['htmlfile'] = Client.extend({
|
||||
exports.htmlfile = Client.extend({
|
||||
|
||||
_onConnect: function(req, res){
|
||||
var self = this, body = '';
|
||||
switch (req.method){
|
||||
case 'GET':
|
||||
this.__super__(req, res);
|
||||
this.request.connection.addListener('end', function(){ self._onClose(); });
|
||||
this.response.useChunkedEncodingByDefault = false;
|
||||
this.request.connection.addListener('close', function(){ self._onClose(); });
|
||||
this.response.useChunkedEncodingByDefault = true;
|
||||
this.response.shouldKeepAlive = true;
|
||||
this.response.writeHead(200, { 'Content-type': 'text/html' });
|
||||
this.response.writeHead(200, {
|
||||
'Content-Type': 'text/html',
|
||||
'Connection': 'keep-alive',
|
||||
'Transfer-Encoding': 'chunked'
|
||||
});
|
||||
this.response.write('<html><body>' + new Array(244).join(' '));
|
||||
this.response.flush();
|
||||
this._payload();
|
||||
this._heartbeatInterval = setInterval(function(){
|
||||
self.response.write('<!-- heartbeat -->');
|
||||
self.response.flush();
|
||||
}, this.options.heartbeatInterval);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
@@ -24,7 +33,7 @@ this['htmlfile'] = Client.extend({
|
||||
try {
|
||||
var msg = qs.parse(body);
|
||||
self._onMessage(msg.data);
|
||||
} catch(e){}
|
||||
} catch(e){}
|
||||
res.writeHead(200);
|
||||
res.write('ok');
|
||||
res.end();
|
||||
@@ -34,8 +43,8 @@ this['htmlfile'] = Client.extend({
|
||||
},
|
||||
|
||||
_write: function(message){
|
||||
// not sure if this is enough escaping. looks lousy
|
||||
this.response.write("<script>parent.callback('"+ message.replace(/'/, "\'") +"')</script>");
|
||||
this.response.write('<script>parent.s._('+ message +', document);</script>');
|
||||
this.response.flush();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,15 +1,17 @@
|
||||
var Client = require('../client').Client,
|
||||
url = require('url');
|
||||
url = require('url'),
|
||||
Buffer = require('buffer').Buffer,
|
||||
crypto = require('crypto');
|
||||
|
||||
this.websocket = Client.extend({
|
||||
exports.websocket = Client.extend({
|
||||
|
||||
_onConnect: function(req, socket){
|
||||
var self = this;
|
||||
var self = this, headers = [];
|
||||
this.request = req;
|
||||
this.connection = socket;
|
||||
this.data = '';
|
||||
|
||||
if (this.request.headers['upgrade'] !== 'WebSocket' || !this._verifyOrigin(this.request.headers['origin'])){
|
||||
if (this.request.headers.upgrade !== 'WebSocket' || !this._verifyOrigin(this.request.headers.origin)){
|
||||
this.listener.options.log('WebSocket connection invalid');
|
||||
this.connection.end();
|
||||
}
|
||||
@@ -17,26 +19,37 @@ this.websocket = Client.extend({
|
||||
this.connection.setTimeout(0);
|
||||
this.connection.setEncoding('utf8');
|
||||
this.connection.setNoDelay(true);
|
||||
this.connection.write([
|
||||
|
||||
headers = [
|
||||
'HTTP/1.1 101 Web Socket Protocol Handshake',
|
||||
'Upgrade: WebSocket',
|
||||
'Connection: Upgrade',
|
||||
'WebSocket-Origin: ' + this.request.headers.origin,
|
||||
'WebSocket-Location: ws://' + this.request.headers.host + this.request.url,
|
||||
'', ''
|
||||
].join('\r\n'));
|
||||
'WebSocket-Location: ws://' + this.request.headers.host + this.request.url
|
||||
];
|
||||
|
||||
if ('sec-websocket-key1' in this.request.headers){
|
||||
headers.push(
|
||||
'Sec-WebSocket-Origin: ' + this.request.headers.origin,
|
||||
'Sec-WebSocket-Location: ws://' + this.request.headers.host + this.request.url);
|
||||
}
|
||||
|
||||
this.connection.write(headers.concat('', '').join('\r\n'));
|
||||
this.connection.addListener('end', function(){ self._onClose(); });
|
||||
this.connection.addListener('data', function(data){ self._handle(data); });
|
||||
this._payload();
|
||||
if (this._proveReception()) {
|
||||
this._payload();
|
||||
}
|
||||
},
|
||||
|
||||
_handle: function(data){
|
||||
var chunk, chunks, chunk_count;
|
||||
this.data += data;
|
||||
chunks = this.data.split('\ufffd');
|
||||
chunk_count = chunks.length - 1;
|
||||
for (var i = 0; i < chunk_count; i++) {
|
||||
chunk = chunks[i];
|
||||
if (chunk[0] != '\u0000') {
|
||||
if (chunk[0] !== '\u0000') {
|
||||
this.listener.options.log('Data incorrectly framed by UA. Dropping connection');
|
||||
this.connection.destroy();
|
||||
return false;
|
||||
@@ -45,21 +58,49 @@ this.websocket = Client.extend({
|
||||
}
|
||||
this.data = chunks[chunks.length - 1];
|
||||
},
|
||||
|
||||
_verifyOrigin: function(origin){
|
||||
var parts = url.parse(origin);
|
||||
return this.listener.options.origins.indexOf('*:*') !== -1
|
||||
|| this.listener.options.origins.indexOf(parts.host + ':' + parts.port) !== -1
|
||||
|| this.listener.options.origins.indexOf(parts.host + ':*') !== -1
|
||||
|| this.listener.options.origins.indexOf('*:' + parts.port) !== -1;
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/complete/network.html#opening-handshake
|
||||
_proveReception: function(){
|
||||
var k1 = this.request.headers['sec-websocket-key1'],
|
||||
k2 = this.request.headers['sec-websocket-key2'];
|
||||
if (k1 && k2) {
|
||||
var md5 = crypto.createHash('md5');
|
||||
|
||||
[k1, k2].forEach(function(k) {
|
||||
var n = k.replace(/[^\d]/g, ''),
|
||||
spaces = k.replace(/[^ ]/g, '').length,
|
||||
buf = new Buffer(4);
|
||||
if (spaces === 0) {
|
||||
this.listener.options.log('Invalid WebSocket key: "' + k + '". Dropping connection');
|
||||
this.connection.destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
n /= spaces;
|
||||
buf[3] = n & 0xff;
|
||||
buf[2] = (n >>= 8) & 0xff;
|
||||
buf[1] = (n >>= 8) & 0xff;
|
||||
buf[0] = (n >>= 8) & 0xff;
|
||||
|
||||
md5.update(buf.toString('binary'));
|
||||
});
|
||||
|
||||
md5.update(this.upgradeHead.toString('binary'));
|
||||
this.connection.write(md5.digest('binary'), 'binary');
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
|
||||
_write: function(message){
|
||||
this.connection.write('\u0000', 'binary');
|
||||
this.connection.write(message, 'utf8');
|
||||
this.connection.write('\uffff', 'binary');
|
||||
try {
|
||||
this.connection.write('\u0000', 'binary');
|
||||
this.connection.write(message, 'utf8');
|
||||
this.connection.write('\uffff', 'binary');
|
||||
} catch(e){
|
||||
this._onClose();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.websocket.httpUpgrade = true;
|
||||
exports.websocket.httpUpgrade = true;
|
||||
@@ -1,48 +1,69 @@
|
||||
var Client = require('../client').Client,
|
||||
qs = require('querystring');
|
||||
qs = require('querystring');
|
||||
|
||||
this['xhr-multipart'] = Client.extend({
|
||||
exports['xhr-multipart'] = Client.extend({
|
||||
|
||||
options: {
|
||||
pingInterval: 7000
|
||||
},
|
||||
|
||||
_pingInterval: null,
|
||||
|
||||
_onConnect: function(req, res){
|
||||
var self = this, body = '';
|
||||
var self = this, body = '', headers = {};
|
||||
// https://developer.mozilla.org/En/HTTP_Access_Control
|
||||
if (req.headers.origin && this._verifyOrigin(req.headers.origin)) {
|
||||
headers['Access-Control-Allow-Origin'] = req.headers.origin;
|
||||
headers['Access-Control-Allow-Credentials'] = 'true';
|
||||
}
|
||||
if (typeof req.headers['access-control-request-method'] !== 'undefined') {
|
||||
// CORS preflight message
|
||||
headers['Access-Control-Allow-Methods'] = req.headers['access-control-request-method'];
|
||||
res.writeHead(200, headers);
|
||||
res.write('ok');
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
switch (req.method){
|
||||
case 'GET':
|
||||
var self = this;
|
||||
this.__super__(req, res);
|
||||
headers['Content-Type'] = 'multipart/x-mixed-replace;boundary="socketio"';
|
||||
headers['Connection'] = 'keep-alive';
|
||||
this.request.connection.addListener('end', function(){ self._onClose(); });
|
||||
this.response.useChunkedEncodingByDefault = false;
|
||||
this.response.shouldKeepAlive = true;
|
||||
this.response.writeHead(200, {
|
||||
'Content-Type': 'multipart/x-mixed-replace;boundary=socketio',
|
||||
'Connection': 'keep-alive'
|
||||
});
|
||||
this.response.writeHead(200, headers);
|
||||
this.response.write("--socketio\n");
|
||||
this.response.flush();
|
||||
if ('flush' in this.response) this.response.flush();
|
||||
this._payload();
|
||||
this._heartbeatInterval = setInterval(function(){
|
||||
self._write(String.fromCharCode(6));
|
||||
}, this.options.heartbeatInterval);
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
req.addListener('data', function(message){
|
||||
body += message;
|
||||
body += message.toString();
|
||||
});
|
||||
req.addListener('end', function(){
|
||||
try {
|
||||
var msg = qs.parse(body);
|
||||
self._onMessage(msg.data);
|
||||
} catch(e){}
|
||||
res.writeHead(200);
|
||||
} catch(e){}
|
||||
res.writeHead(200, headers);
|
||||
res.write('ok');
|
||||
res.end();
|
||||
body = '';
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_write: function(message){
|
||||
this.response.write("Content-Type: text/plain\n\n");
|
||||
this.response.write("Content-Type: text/plain" + (message.length === 1 && message.charCodeAt(0) === 6 ? "; charset=us-ascii" : "") + "\n\n");
|
||||
this.response.write(message + "\n");
|
||||
this.response.write("--socketio\n");
|
||||
this.response.flush();
|
||||
if ('flush' in this.response) this.response.flush();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,8 +1,7 @@
|
||||
var Client = require('../client').Client,
|
||||
qs = require('querystring'),
|
||||
sys = require('sys');
|
||||
qs = require('querystring');
|
||||
|
||||
this['xhr-polling'] = Client.extend({
|
||||
exports['xhr-polling'] = Client.extend({
|
||||
|
||||
options: {
|
||||
closeTimeout: 5000,
|
||||
@@ -13,10 +12,10 @@ this['xhr-polling'] = Client.extend({
|
||||
var self = this, body = '';
|
||||
switch (req.method){
|
||||
case 'GET':
|
||||
this.__super__(req, res);
|
||||
this.__super__(req, res);
|
||||
this._closeTimeout = setTimeout(function(){
|
||||
self._write('');
|
||||
}, this.options.duration);
|
||||
}, this.options.duration);
|
||||
this._payload();
|
||||
break;
|
||||
|
||||
@@ -28,7 +27,7 @@ this['xhr-polling'] = Client.extend({
|
||||
try {
|
||||
var msg = qs.parse(body);
|
||||
self._onMessage(msg.data);
|
||||
} catch(e){}
|
||||
} catch(e){}
|
||||
res.writeHead(200);
|
||||
res.write('ok');
|
||||
res.end();
|
||||
@@ -38,8 +37,18 @@ this['xhr-polling'] = Client.extend({
|
||||
},
|
||||
|
||||
_write: function(message){
|
||||
if (this._closeTimeout) clearTimeout(this._closeTimeout);
|
||||
this.response.writeHead(200, {'Content-Type': 'text/plain', 'Content-Length': message.length});
|
||||
if (this._closeTimeout) {
|
||||
clearTimeout(this._closeTimeout);
|
||||
}
|
||||
var headers = {'Content-Type': 'text/plain', 'Content-Length': message.length};
|
||||
// https://developer.mozilla.org/En/HTTP_Access_Control
|
||||
if (this.request.headers.origin && this._verifyOrigin(this.request.headers.origin)) {
|
||||
headers['Access-Control-Allow-Origin'] = this.request.headersorigin;
|
||||
if (this.request.headers.cookie) {
|
||||
headers['Access-Control-Allow-Credentials'] = 'true';
|
||||
}
|
||||
}
|
||||
this.response.writeHead(200, headers);
|
||||
this.response.write(message);
|
||||
this.response.end();
|
||||
this._onClose();
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
// Based on Mixin.js from MooTools (MIT)
|
||||
// Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net/>
|
||||
|
||||
this.flatten = function(arr){
|
||||
exports.flatten = function(arr){
|
||||
var array = [];
|
||||
for (var i = 0, l = arr.length; i < l; i++){
|
||||
var item = arr[i];
|
||||
if (item != null) array = array.concat(item instanceof Array ? array.flatten(item) : item);
|
||||
if (item !== null) {
|
||||
array = array.concat(item instanceof Array ? array.flatten(item) : item);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
};
|
||||
|
||||
this.include = function(arr, item){
|
||||
if (arr.indexOf(item) == -1) arr.push(item);
|
||||
exports.include = function(arr, item){
|
||||
if (arr.indexOf(item) === -1) {
|
||||
arr.push(item);
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
@@ -1,38 +1,51 @@
|
||||
// Based on Mixin.js from MooTools (MIT)
|
||||
// Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net/>
|
||||
|
||||
var clone = this.clone = function(item){
|
||||
var clone;
|
||||
exports.clone = function(item) {
|
||||
var cloned;
|
||||
if (item instanceof Array){
|
||||
clone = [];
|
||||
for (var i = 0; i < item.length; i++) clone[i] = clone(item[i]);
|
||||
return clone;
|
||||
} else if (typeof item == 'object') {
|
||||
clone = {};
|
||||
for (var key in object) clone[key] = clone(object[key]);
|
||||
return clone;
|
||||
} else {
|
||||
return item;
|
||||
cloned = [];
|
||||
for (var i = 0; i < item.length; i++) {
|
||||
cloned[i] = exports.clone(item[i]);
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
},
|
||||
|
||||
if (typeof item === 'object') {
|
||||
cloned = {};
|
||||
for (var key in item) {
|
||||
cloned[key] = exports.clone(item[key]);
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
mergeOne = function(source, key, current){
|
||||
var mergeOne = function(source, key, current){
|
||||
if (current instanceof Array){
|
||||
source[key] = clone(current);
|
||||
} else if (typeof current == 'object'){
|
||||
if (typeof source[key] == 'object') object.merge(source[key], current);
|
||||
else source[key] = clone(current);
|
||||
source[key] = exports.clone(current);
|
||||
} else if (typeof current === 'object'){
|
||||
if (typeof source[key] === 'object') {
|
||||
exports.merge(source[key], current);
|
||||
} else {
|
||||
source[key] = exports.clone(current);
|
||||
}
|
||||
} else {
|
||||
source[key] = current;
|
||||
}
|
||||
return source;
|
||||
};
|
||||
|
||||
this.merge = function(source, k, v){
|
||||
if (typeof k == 'string') return mergeOne(source, k, v);
|
||||
exports.merge = function(source, k, v){
|
||||
if (typeof k === 'string') {
|
||||
return mergeOne(source, k, v);
|
||||
}
|
||||
for (var i = 1, l = arguments.length; i < l; i++){
|
||||
var object = arguments[i];
|
||||
for (var key in object) mergeOne(source, key, object[key]);
|
||||
for (var key in object) {
|
||||
mergeOne(source, key, object[key]);
|
||||
}
|
||||
}
|
||||
return source;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net/>
|
||||
var object = require('./object'), sys = require('sys');
|
||||
|
||||
this.Options = {
|
||||
exports.options = {
|
||||
|
||||
options: {},
|
||||
|
||||
@@ -12,13 +12,20 @@ this.Options = {
|
||||
},
|
||||
|
||||
setOptions: function(options){
|
||||
for (var key in options) this.setOption(key, options[key]);
|
||||
for (var key in options) {
|
||||
this.setOption(key, options[key]);
|
||||
}
|
||||
if (this.addListener){
|
||||
var first_lower = function(full, first){
|
||||
return first.toLowerCase();
|
||||
};
|
||||
|
||||
// Automagically register callbacks if the varname starts with on
|
||||
for (var i in this.options){
|
||||
if (!(/^on[A-Z]/).test(i) || typeof this.options[i] != 'function') continue;
|
||||
this.addListener(i.replace(/^on([A-Z])/, function(full, first){
|
||||
return first.toLowerCase();
|
||||
}), this.options[i]);
|
||||
if (!(/^on[A-Z]/).test(i) || typeof this.options[i] !== 'function') {
|
||||
continue;
|
||||
}
|
||||
this.addListener(i.replace(/^on([A-Z])/, first_lower), this.options[i]);
|
||||
this.options[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
document.getElementById('text').value = '';
|
||||
}
|
||||
|
||||
var socket = new io.Socket('localhost', {rememberTransport: false, port: 8080});
|
||||
var socket = new io.Socket(null, {rememberTransport: false, port: 8080});
|
||||
socket.connect();
|
||||
socket.addEvent('message', function(data){
|
||||
var obj = JSON.parse(data);
|
||||
|
||||
Submodule test/client updated: 1e0e9fb87d...d643e6029c
@@ -23,8 +23,8 @@ server = http.createServer(function(req, res){
|
||||
default:
|
||||
if (/\.(js|html|swf)$/.test(path)){
|
||||
try {
|
||||
var swf = path.substr(-4) == '.swf';
|
||||
res.writeHead(200, {'Content-Type': swf ? 'application/x-shockwave-flash' : ('text/' + (path.substr(-3) == '.js' ? 'javascript' : 'html'))});
|
||||
var swf = path.substr(-4) === '.swf';
|
||||
res.writeHead(200, {'Content-Type': swf ? 'application/x-shockwave-flash' : ('text/' + (path.substr(-3) === '.js' ? 'javascript' : 'html'))});
|
||||
res.write(fs.readFileSync(__dirname + path, swf ? 'binary' : 'utf8'), swf ? 'binary' : 'utf8');
|
||||
res.end();
|
||||
} catch(e){
|
||||
@@ -58,7 +58,9 @@ io.listen(server, {
|
||||
onClientMessage: function(message, client){
|
||||
var msg = { message: [client.sessionId, message] };
|
||||
buffer.push(msg);
|
||||
if (buffer.length > 15) buffer.shift();
|
||||
if (buffer.length > 15) {
|
||||
buffer.shift();
|
||||
}
|
||||
client.broadcast(json(msg));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user