socket.io
Advanced tools
Comparing version 0.7.2 to 0.7.3
0.7.3 / 2011-06-30 | ||
================== | ||
* Exposed handshake data to clients. | ||
* Refactored dispatcher interface. | ||
* Changed; Moved id generation method into the manager. | ||
* Added sub-namespace authorization. [3rd-Eden] | ||
* Changed; normalized SocketNamespace local eventing [dvv] | ||
* Changed; Use packet.reason or default to 'packet' [3rd-Eden] | ||
* Changed console.error to console.log. | ||
* Fixed; bind both servers at the same time do that the test never times out. | ||
* Added 304 support. | ||
* Removed `Transport#name` for abstract interface. | ||
* Changed; lazily require http and https module only when needed. [3rd-Eden] | ||
0.7.2 / 2011-06-22 | ||
@@ -3,0 +18,0 @@ ================== |
@@ -77,3 +77,3 @@ | ||
console.error.apply( | ||
console.log.apply( | ||
console | ||
@@ -80,0 +80,0 @@ , [this.colors |
@@ -82,4 +82,8 @@ | ||
, 'browser client etag': false | ||
, 'browser client handler': false | ||
, 'client store expiration': 15 | ||
}; | ||
this.initStore(); | ||
// reset listeners | ||
@@ -221,2 +225,261 @@ this.oldListeners = server.listeners('request'); | ||
/** | ||
* Initializes everything related to the message dispatcher. | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.initStore = function () { | ||
this.handshaken = {}; | ||
this.connected = {}; | ||
this.open = {}; | ||
this.closed = {}; | ||
this.closedA = []; | ||
this.rooms = {}; | ||
this.roomClients = {}; | ||
var self = this; | ||
this.store.subscribe('handshake', function (id, data) { | ||
self.onHandshake(id, data); | ||
}); | ||
this.store.subscribe('connect', function (id) { | ||
self.onConnect(id); | ||
}); | ||
this.store.subscribe('open', function (id) { | ||
self.onOpen(id); | ||
}); | ||
this.store.subscribe('join', function (id, room) { | ||
self.onJoin(id, room); | ||
}); | ||
this.store.subscribe('leave', function (id, room) { | ||
self.onLeave(id, room); | ||
}); | ||
this.store.subscribe('close', function (id) { | ||
self.onClose(id); | ||
}); | ||
this.store.subscribe('dispatch', function (room, packet, volatile, exceptions) { | ||
self.onDispatch(room, packet, volatile, exceptions); | ||
}); | ||
this.store.subscribe('disconnect', function (id) { | ||
self.onDisconnect(id); | ||
}); | ||
}; | ||
/** | ||
* Called when a client handshakes. | ||
* | ||
* @param text | ||
*/ | ||
Manager.prototype.onHandshake = function (id, data) { | ||
this.handshaken[id] = data; | ||
}; | ||
/** | ||
* Called when a client connects (ie: transport first opens) | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.onConnect = function (id) { | ||
this.connected[id] = true; | ||
}; | ||
/** | ||
* Called when a client opens a request in a different node. | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.onOpen = function (id) { | ||
this.open[id] = true; | ||
// if we were buffering messages for the client, clear them | ||
if (this.closed[id]) { | ||
var self = this; | ||
this.closedA.splice(this.closedA.indexOf(id), 1); | ||
this.store.unsubscribe('dispatch:' + id, function () { | ||
delete self.closed[id]; | ||
}); | ||
} | ||
// clear the current transport | ||
if (this.transports[id]) { | ||
this.transports[id].discard(); | ||
this.transports[id] = null; | ||
} | ||
}; | ||
/** | ||
* Called when a message is sent to a namespace and/or room. | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.onDispatch = function (room, packet, volatile, exceptions) { | ||
// go through the users who have pending buffers | ||
for (var i = 0, l = this.closedA.length; i < l; i++) { | ||
if (this.roomClients[this.closedA[i]][room]) { | ||
if (!~exceptions.indexOf(this.closedA[i])) { | ||
this.closed[this.closedA[i]].push(packet); | ||
} | ||
} | ||
} | ||
// go through room clients | ||
if (this.rooms[room]) { | ||
for (var i = 0, l = this.rooms[room].length; i < l; i++) { | ||
var id = this.rooms[room][i]; | ||
if (!~exceptions.indexOf(id)) { | ||
if (this.transports[id] && this.transports[id].open) { | ||
this.transports[id].onDispatch(packet, volatile); | ||
} else if (!volatile) { | ||
this.onClientDispatch(id, packet); | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* Called when a client joins a nsp / room. | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.onJoin = function (id, name) { | ||
if (!this.roomClients[id]) { | ||
this.roomClients[id] = []; | ||
} | ||
if (!this.rooms[name]) { | ||
this.rooms[name] = []; | ||
} | ||
this.rooms[name].push(id); | ||
this.roomClients[id][name] = true; | ||
}; | ||
/** | ||
* Called when a client leaves a nsp / room. | ||
* | ||
* @param private | ||
*/ | ||
Manager.prototype.onLeave = function (id, room) { | ||
if (this.rooms[room]) { | ||
this.rooms[room].splice(this.rooms[room].indexOf(id), 1); | ||
delete this.roomClients[id][room]; | ||
} | ||
}; | ||
/** | ||
* Called when a client closes a request in different node. | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.onClose = function (id) { | ||
this.closed[id] = []; | ||
this.closedA.push(id); | ||
var self = this; | ||
this.store.subscribe('dispatch:' + id, function (packet, volatile) { | ||
if (!volatile) { | ||
self.onClientDispatch(id, packet); | ||
} | ||
}); | ||
}; | ||
/** | ||
* Dispatches a message for a closed client. | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.onClientDispatch = function (id, packet) { | ||
this.closed[id].push(packet); | ||
}; | ||
/** | ||
* Receives a message for a client. | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.onClientMessage = function (id, packet) { | ||
if (this.namespaces[packet.endpoint]) { | ||
this.namespaces[packet.endpoint].handlePacket(id, packet); | ||
} | ||
}; | ||
/** | ||
* Fired when a client disconnects (not triggered). | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.onClientDisconnect = function (id, reason) { | ||
for (var name in this.namespaces) { | ||
if (this.roomClients[id][name]) { | ||
this.namespaces[name].handleDisconnect(id, reason); | ||
} | ||
} | ||
}; | ||
/** | ||
* Called when a client disconnects. | ||
* | ||
* @param text | ||
*/ | ||
Manager.prototype.onDisconnect = function (id, local) { | ||
delete this.handshaken[id]; | ||
if (this.open[id]) { | ||
delete this.open[id]; | ||
} | ||
if (this.connected[id]) { | ||
delete this.connected[id]; | ||
} | ||
if (this.transports[id]) { | ||
this.transports[id].discard(); | ||
delete this.transports[id]; | ||
} | ||
if (this.closed[id]) { | ||
delete this.closed[id]; | ||
this.closedA.splice(this.closedA.indexOf(id), 1); | ||
} | ||
if (this.roomClients[id]) { | ||
for (var room in this.roomClients[id]) { | ||
this.rooms[room].splice(this.rooms.indexOf(id), 1); | ||
} | ||
} | ||
this.store.destroyClient(id, this.get('client store expiration')); | ||
this.store.unsubscribe('dispatch:' + id); | ||
if (local) { | ||
this.store.unsubscribe('message:' + id); | ||
this.store.unsubscribe('disconnect:' + id); | ||
} | ||
}; | ||
/** | ||
* Handles an HTTP request. | ||
@@ -307,8 +570,11 @@ * | ||
var socket = req.socket | ||
, newTransport = false | ||
, store = this.store | ||
, self = this; | ||
if (undefined != data.query.disconnect) { | ||
self.log.debug('handling disconnection url'); | ||
self.store.disconnect(data.id, true); | ||
if (this.transports[data.id] && this.transports[data.id].open) { | ||
this.transports[data.id].onForcedDisconnect(); | ||
} else { | ||
this.store.publish('disconnect-force:' + data.id); | ||
} | ||
return; | ||
@@ -323,39 +589,45 @@ } | ||
var transport = new transports[data.transport](this, data); | ||
transport.pause(); | ||
transport.request = req; | ||
var transport = new transports[data.transport](this, data, req); | ||
if (!transport.open) { | ||
this.log.debug('transport not writeable, not subscribing'); | ||
return; | ||
} | ||
if (this.handshaken[data.id]) { | ||
if (transport.open) { | ||
if (this.closed[data.id] && this.closed[data.id].length) { | ||
transport.payload(this.closed[data.id]); | ||
this.closed[data.id] = []; | ||
} | ||
this.store.isHandshaken(data.id, function (err, handshaken) { | ||
if (err || !handshaken) { | ||
if (err) console.error(err); | ||
transport.error('client not handshaken', 'reconnect'); | ||
return; | ||
this.onOpen(data.id); | ||
this.store.publish('open', data.id); | ||
this.transports[data.id] = transport; | ||
} | ||
self.store.client(data.id).count(function (err, count) { | ||
transport.resume(); | ||
if (!this.connected[data.id]) { | ||
this.onConnect(data.id); | ||
this.store.publish('connect', data.id); | ||
if (count == 1) { | ||
// initialize the socket for all namespaces | ||
for (var i in self.namespaces) { | ||
var socket = self.namespaces[i].socket(data.id, true); | ||
// initialize the socket for all namespaces | ||
for (var i in this.namespaces) { | ||
var socket = this.namespaces[i].socket(data.id, true); | ||
// echo back connect packet and fire connection event | ||
if (i === '') { | ||
self.namespaces[i].handlePacket(data.id, { type: 'connect' }); | ||
} | ||
// echo back connect packet and fire connection event | ||
if (i === '') { | ||
this.namespaces[i].handlePacket(data.id, { type: 'connect' }); | ||
} | ||
} | ||
// handle packets for the client (all namespaces) | ||
self.store.on('message:' + data.id, function (packet) { | ||
self.handlePacket(data.id, packet); | ||
}); | ||
} | ||
}); | ||
}); | ||
this.store.subscribe('message:' + data.id, function (packet) { | ||
self.onClientMessage(data.id, packet); | ||
}); | ||
this.store.subscribe('disconnect:' + data.id, function (reason) { | ||
self.onClientDisconnect(data.id, reason); | ||
}); | ||
} | ||
} else { | ||
if (transport.open) { | ||
transport.error('client not handshaken', 'reconnect'); | ||
} | ||
transport.discard(); | ||
} | ||
}; | ||
@@ -370,17 +642,20 @@ | ||
Manager.static = { | ||
cache:{} | ||
, paths: { | ||
'/static/flashsocket/WebSocketMain.swf': client.dist + '/WebSocketMain.swf' | ||
, '/static/flashsocket/WebSocketMainInsecure.swf': client.dist + '/WebSocketMainInsecure.swf' | ||
, '/socket.io.js': client.dist + '/socket.io.js' | ||
, '/socket.io.js.min': client.dist + '/socket.io.min.js' | ||
} | ||
, contentType: { | ||
'js': 'application/javascript' | ||
, 'swf': 'application/x-shockwave-flash' | ||
} | ||
, encoding:{ | ||
'js': 'utf8' | ||
, 'swf': 'binary' | ||
} | ||
cache: {} | ||
, paths: { | ||
'/static/flashsocket/WebSocketMain.swf': client.dist + '/WebSocketMain.swf' | ||
, '/static/flashsocket/WebSocketMainInsecure.swf': | ||
client.dist + '/WebSocketMainInsecure.swf' | ||
, '/socket.io.js': client.dist + '/socket.io.js' | ||
, '/socket.io.js.min': client.dist + '/socket.io.min.js' | ||
} | ||
, mime: { | ||
'js': { | ||
contentType: 'application/javascript' | ||
, encoding: 'utf8' | ||
} | ||
, 'swf': { | ||
contentType: 'application/x-shockwave-flash' | ||
, encoding: 'binary' | ||
} | ||
} | ||
}; | ||
@@ -397,3 +672,4 @@ | ||
, extension = data.path.split('.').pop() | ||
, file = data.path + (this.enabled('browser client minification') && extension == 'js' ? '.min' : '') | ||
, file = data.path + (this.enabled('browser client minification') | ||
&& extension == 'js' ? '.min' : '') | ||
, location = static.paths[file] | ||
@@ -404,5 +680,23 @@ , cache = static.cache[file]; | ||
/** | ||
* Writes a response, safely | ||
* | ||
* @api private | ||
*/ | ||
function write (status, headers, content, encoding) { | ||
try { | ||
res.writeHead(status, headers || null); | ||
res.end(content || '', encoding || null); | ||
} catch (e) {} | ||
} | ||
function serve () { | ||
var headers = { | ||
'Content-Type': static.contentType[extension] | ||
if (req.headers['if-none-match'] === cache.Etag) { | ||
return write(304); | ||
} | ||
var mime = static.mime[extension] | ||
, headers = { | ||
'Content-Type': mime.contentType | ||
, 'Content-Length': cache.length | ||
@@ -415,5 +709,3 @@ }; | ||
res.writeHead(200, headers); | ||
res.end(cache.content, cache.encoding); | ||
write(200, headers, cache.content, mime.encoding); | ||
self.log.debug('served static ' + data.path); | ||
@@ -427,6 +719,4 @@ } | ||
if (err) { | ||
res.writeHead(500); | ||
res.end('Error serving socket.io client.'); | ||
self.log.warn('Can\'t cache socket.io client, ' + err.message); | ||
write(500, null, 'Error serving static ' + data.path); | ||
self.log.warn('Can\'t cache '+ data.path +', ' + err.message); | ||
return; | ||
@@ -439,3 +729,2 @@ } | ||
, Etag: client.version | ||
, encoding: static.encoding[extension] | ||
}; | ||
@@ -451,2 +740,13 @@ | ||
/** | ||
* Generates a session id. | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.generateId = function () { | ||
return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString() | ||
+ Math.abs(Math.random() * Math.random() * Date.now() | 0).toString(); | ||
}; | ||
/** | ||
* Handles a handshake request. | ||
@@ -480,30 +780,32 @@ * | ||
this.authorize(data, function (err, authorized) { | ||
var handshakeData = this.handshakeData(data); | ||
this.authorize(handshakeData, function (err, authorized, newData) { | ||
if (err) return error(err); | ||
self.log.info('handshake ' + (authorized ? 'authorized' : 'unauthorized')); | ||
if (authorized) { | ||
self.store.handshake(data, function (err, id) { | ||
if (err) return error(err); | ||
var id = self.generateId() | ||
, hs = [ | ||
id | ||
, self.get('heartbeat timeout') || '' | ||
, self.get('close timeout') || '' | ||
, self.transports(data).join(',') | ||
].join(':'); | ||
var hs = [ | ||
id | ||
, self.get('heartbeat timeout') || '' | ||
, self.get('close timeout') || '' | ||
, self.transports(data).join(',') | ||
].join(':'); | ||
if (data.query.jsonp) { | ||
hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');'; | ||
res.writeHead(200, { 'Content-Type': 'application/javascript' }); | ||
} else { | ||
res.writeHead(200); | ||
} | ||
if (data.query.jsonp) { | ||
hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');'; | ||
res.writeHead(200, { 'Content-Type': 'application/javascript' }); | ||
} else { | ||
res.writeHead(200); | ||
} | ||
res.end(hs); | ||
res.end(hs); | ||
self.log.info('handshaken', id); | ||
}); | ||
self.onHandshake(id, newData || handshakeData); | ||
self.store.publish('handshake', id, newData || handshakeData); | ||
self.log.info('handshake authorized', id); | ||
} else { | ||
writeErr(403, 'handshake unauthorized'); | ||
self.log.info('handshake unauthorized'); | ||
} | ||
@@ -514,2 +816,22 @@ }) | ||
/** | ||
* Gets normalized handshake data | ||
* | ||
* @api private | ||
*/ | ||
Manager.prototype.handshakeData = function (data) { | ||
var connectionAddress = null; | ||
if (data.request.connection.address) { | ||
connectionAddress = data.request.connection.address(); | ||
} | ||
return { | ||
headers: data.headers | ||
, address: connectionAddress | ||
, time: (new Date).toString() | ||
, xdomain: !!data.request.headers.origin | ||
, secure: data.request.connection.secure | ||
}; | ||
}; | ||
/** | ||
* Verifies the origin of a request. | ||
@@ -516,0 +838,0 @@ * |
@@ -1,2 +0,1 @@ | ||
/** | ||
@@ -27,2 +26,3 @@ * Module dependencies. | ||
this.sockets = {}; | ||
this.auth = false; | ||
this.setFlags(); | ||
@@ -38,2 +38,29 @@ }; | ||
/** | ||
* Copies emit since we override it | ||
* | ||
* @api private | ||
*/ | ||
SocketNamespace.prototype.$emit = EventEmitter.prototype.emit; | ||
/** | ||
* Retrieves all clients as Socket instances as an array. | ||
* | ||
* @api public | ||
*/ | ||
SocketNamespace.prototype.clients = function (room) { | ||
var room = this.name + (room !== undefined ? | ||
(this.name !== '' ? '/' : '') + room : ''); | ||
if (!this.manager.rooms[room]) { | ||
return []; | ||
} | ||
return this.manager.rooms[room].map(function (id) { | ||
return this.socket(id); | ||
}, this); | ||
}; | ||
/** | ||
* Access logger interface. | ||
@@ -131,17 +158,5 @@ * | ||
store.clients(this.flags.endpoint, function (clients) { | ||
clients.forEach(function (id) { | ||
if (~exceptions.indexOf(id)) { | ||
log.debug('ignoring packet to ', id); | ||
return; | ||
} | ||
this.manager.onDispatch(this.flags.endpoint, packet, volatile, exceptions); | ||
this.store.publish('dispatch', this.flags.endpoint, packet, volatile, exceptions); | ||
if (volatile) { | ||
store.publish('volatile:' + id, packet); | ||
} else { | ||
store.client(id).publish(packet); | ||
} | ||
}); | ||
}); | ||
this.setFlags(); | ||
@@ -173,3 +188,3 @@ | ||
if (name == 'connection' || name == 'newListener') { | ||
return EventEmitter.prototype.emit.apply(this, arguments); | ||
return this.$emit.apply(this, arguments); | ||
} | ||
@@ -200,2 +215,49 @@ | ||
/** | ||
* Sets authorization for this namespace | ||
* | ||
* @api public | ||
*/ | ||
SocketNamespace.prototype.authorization = function (fn) { | ||
this.auth = fn; | ||
return this; | ||
}; | ||
/** | ||
* Called when a socket disconnects entirely. | ||
* | ||
* @api private | ||
*/ | ||
SocketNamespace.prototype.handleDisconnect = function (sid, reason) { | ||
if (this.sockets[sid] && this.sockets[sid].readable) { | ||
this.sockets[sid].onDisconnect(reason); | ||
} | ||
}; | ||
/** | ||
* Performs authentication. | ||
* | ||
* @param Object client request data | ||
* @api private | ||
*/ | ||
SocketNamespace.prototype.authorize = function (data, fn) { | ||
if (this.auth) { | ||
var self = this; | ||
this.auth.call(this, data, function (err, authorized) { | ||
self.log.debug('client ' + | ||
(authorized ? '' : 'un') + 'authorized for ' + self.name); | ||
fn(err, authorized); | ||
}); | ||
} else { | ||
this.log.debug('client authorized for ' + this.name); | ||
fn(null, true); | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Handles a packet. | ||
@@ -220,9 +282,38 @@ * | ||
function error (err) { | ||
self.log.warn('handshake error ' + err + ' for ' + self.name); | ||
socket.packet({ type: 'error', reason: err }); | ||
}; | ||
function connect () { | ||
self.manager.onJoin(sessid, self.name); | ||
self.store.publish('join', sessid, self.name); | ||
// packet echo | ||
socket.packet({ type: 'connect' }); | ||
// emit connection event | ||
self.emit('connection', socket); | ||
}; | ||
switch (packet.type) { | ||
case 'connect': | ||
this.store.join(sessid, this.name, function () { | ||
// packet echo | ||
socket.packet({ type: 'connect' }); | ||
self.emit('connection', socket); | ||
}); | ||
if (packet.endpoint == '') { | ||
connect(); | ||
} else { | ||
var manager = this.manager | ||
, handshakeData = manager.handshaken[sessid]; | ||
this.authorize(handshakeData, function (err, authorized, newData) { | ||
if (err) return error(err); | ||
if (authorized) { | ||
manager.onHandshake(sessid, newData || handshakeData); | ||
self.store.publish('handshake', sessid, newData || handshakeData); | ||
connect(); | ||
} else { | ||
error('unauthorized'); | ||
} | ||
}); | ||
} | ||
break; | ||
@@ -248,3 +339,6 @@ | ||
case 'disconnect': | ||
socket.emit('disconnect'); | ||
this.manager.onLeave(sessid, this.name); | ||
this.store.publish('leave', sessid, this.name); | ||
socket.emit('disconnect', packet.reason || 'packet'); | ||
break; | ||
@@ -251,0 +345,0 @@ |
@@ -12,5 +12,3 @@ | ||
var http = require('http') | ||
, https = require('https') | ||
, client = require('socket.io-client'); | ||
var client = require('socket.io-client'); | ||
@@ -21,3 +19,3 @@ /** | ||
exports.version = '0.7.2'; | ||
exports.version = '0.7.3'; | ||
@@ -58,5 +56,5 @@ /** | ||
if (options && options.key) | ||
server = https.createServer(options, server); | ||
server = require('https').createServer(options); | ||
else | ||
server = http.createServer(); | ||
server = require('http').createServer(); | ||
@@ -109,2 +107,18 @@ // default response | ||
/** | ||
* Memory Store constructor. | ||
* | ||
* @api public | ||
*/ | ||
exports.MemoryStore = require('./stores/memory'); | ||
/** | ||
* Redis Store constructor. | ||
* | ||
* @api public | ||
*/ | ||
exports.RedisStore = require('./stores/redis'); | ||
/** | ||
* Parser. | ||
@@ -111,0 +125,0 @@ * |
@@ -56,10 +56,4 @@ | ||
this.setFlags(); | ||
if (readable) { | ||
var self = this; | ||
this.store.once('disconnect:' + id, function (reason) { | ||
self.onDisconnect(reason); | ||
}); | ||
} | ||
this.readable = readable; | ||
this.store = this.manager.store.client(this.id); | ||
}; | ||
@@ -74,3 +68,3 @@ | ||
/** | ||
* Accessor shortcut for the store. | ||
* Accessor shortcut for the handshake data | ||
* | ||
@@ -80,4 +74,4 @@ * @api private | ||
Socket.prototype.__defineGetter__('store', function () { | ||
return this.manager.store; | ||
Socket.prototype.__defineGetter__('handshake', function () { | ||
return this.manager.handshaken[this.id]; | ||
}); | ||
@@ -173,4 +167,13 @@ | ||
Socket.prototype.join = function (name, fn) { | ||
var nsp = this.namespace.name; | ||
this.store.join(this.id, (nsp === '' ? '' : (nsp + '/')) + name, fn); | ||
var nsp = this.namespace.name | ||
, name = (nsp === '' ? '' : (nsp + '/')) + name; | ||
this.manager.onJoin(this.id, name); | ||
this.manager.store.publish('join', this.id, name); | ||
if (fn) { | ||
this.log.warn('Client#join callback is deprecated'); | ||
fn(); | ||
} | ||
return this; | ||
@@ -186,4 +189,13 @@ }; | ||
Socket.prototype.leave = function (name, fn) { | ||
var nsp = this.namespace.name; | ||
this.store.leave(this.id, (nsp === '' ? '' : (nsp + '/')) + name, fn); | ||
var nsp = this.namespace.name | ||
, name = (nsp === '' ? '' : (nsp + '/')) + name; | ||
this.manager.onLeave(this.id, name); | ||
this.manager.store.publish('leave', this.id, name); | ||
if (fn) { | ||
this.log.warn('Client#leave callback is deprecated'); | ||
fn(); | ||
} | ||
return this; | ||
@@ -206,7 +218,3 @@ }; | ||
if (this.flags.volatile) { | ||
this.store.publish('volatile:' + this.id, packet); | ||
} else { | ||
this.store.client(this.id).publish(packet); | ||
} | ||
this.dispatch(packet, this.flags.volatile); | ||
} | ||
@@ -220,2 +228,20 @@ | ||
/** | ||
* Dispatches a packet | ||
* | ||
* @api private | ||
*/ | ||
Socket.prototype.dispatch = function (packet, volatile) { | ||
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) { | ||
this.manager.transports[this.id].onDispatch(packet, volatile); | ||
} else { | ||
if (!volatile) { | ||
this.manager.onClientDispatch(this.id, packet, volatile); | ||
} | ||
this.manager.store.publish('dispatch:' + this.id, packet, volatile); | ||
} | ||
}; | ||
/** | ||
* Stores data for the client. | ||
@@ -227,3 +253,3 @@ * | ||
Socket.prototype.set = function (key, value, fn) { | ||
this.store.client(this.id).set(key, value, fn); | ||
this.store.set(key, value, fn); | ||
return this; | ||
@@ -239,3 +265,3 @@ }; | ||
Socket.prototype.get = function (key, fn) { | ||
this.store.client(this.id).get(key, fn); | ||
this.store.get(key, fn); | ||
return this; | ||
@@ -245,2 +271,24 @@ }; | ||
/** | ||
* Checks data for the client | ||
* | ||
* @api public | ||
*/ | ||
Socket.prototype.has = function (key, fn) { | ||
this.store.has(key, fn); | ||
return this; | ||
}; | ||
/** | ||
* Deletes data for the client | ||
* | ||
* @api public | ||
*/ | ||
Socket.prototype.del = function (key, fn) { | ||
this.store.del(key, fn); | ||
return this; | ||
}; | ||
/** | ||
* Kicks client | ||
@@ -254,3 +302,14 @@ * | ||
this.log.info('booting client'); | ||
this.store.disconnect(this.id, true); | ||
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) { | ||
this.manager.transports[this.id].onForcedDisconnect(); | ||
} else { | ||
if (this.manager.open[this.id]) { | ||
// if the connection is open in a different node | ||
this.manager.store.publish('disconnect-force:' + this.id); | ||
} else { | ||
this.manager.onClientDisconnect(this.id); | ||
this.manager.store.publish('disconnect:' + this.id); | ||
} | ||
} | ||
} | ||
@@ -257,0 +316,0 @@ |
@@ -9,12 +9,12 @@ | ||
/** | ||
* Module dependencies. | ||
* Expose the constructor. | ||
*/ | ||
var EventEmitter = process.EventEmitter; | ||
exports = module.exports = Store; | ||
/** | ||
* Expose the constructor. | ||
* Module dependencies. | ||
*/ | ||
exports = module.exports = Store; | ||
var EventEmitter = process.EventEmitter; | ||
@@ -27,6 +27,9 @@ /** | ||
function Store () {}; | ||
function Store (options) { | ||
this.options = options; | ||
this.clients = {}; | ||
}; | ||
/** | ||
* Inherits from EventEmitter | ||
* Inherit from EventEmitter. | ||
*/ | ||
@@ -37,12 +40,54 @@ | ||
/** | ||
* Log accessor. | ||
* Initializes a client store | ||
* | ||
* @param {String} id | ||
* @api public | ||
*/ | ||
Store.prototype.__defineGetter__('log', function () { | ||
return this.manager.log; | ||
}); | ||
Store.prototype.client = function (id) { | ||
if (!this.clients[id]) { | ||
this.clients[id] = new (this.constructor.Client)(this, id); | ||
} | ||
return this.clients[id]; | ||
}; | ||
/** | ||
* Destroys a client | ||
* | ||
* @api {String} sid | ||
* @param {Number} number of seconds to expire client data | ||
* @api private | ||
*/ | ||
Store.prototype.destroyClient = function (id, expiration) { | ||
if (this.clients[id]) { | ||
this.clients[id].destroy(expiration); | ||
delete this.clients[id]; | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Destroys the store | ||
* | ||
* @param {Number} number of seconds to expire client data | ||
* @api private | ||
*/ | ||
Store.prototype.destroy = function (clientExpiration) { | ||
var keys = Object.keys(this.clients) | ||
, count = keys.length; | ||
for (var i = 0, l = count; i < l; i++) { | ||
this.destroyClient(keys[i], clientExpiration); | ||
} | ||
this.clients = {}; | ||
return this; | ||
}; | ||
/** | ||
* Client. | ||
@@ -56,4 +101,2 @@ * | ||
this.id = id; | ||
this.buffer = []; | ||
this.dict = {}; | ||
}; |
@@ -13,3 +13,3 @@ | ||
var crypto = require('crypto') | ||
, Store = require('../store') | ||
, Store = require('../store'); | ||
@@ -30,5 +30,3 @@ /** | ||
function Memory (opts) { | ||
this.handshaken = []; | ||
this.clientsMap = {}; | ||
this.rooms = {}; | ||
Store.call(this, opts); | ||
}; | ||
@@ -43,88 +41,19 @@ | ||
/** | ||
* Handshake a client. | ||
* Publishes a message. | ||
* | ||
* @param {Object} client request object | ||
* @param {Function} callback | ||
* @api public | ||
*/ | ||
Memory.prototype.handshake = function (data, fn) { | ||
var id = this.generateId(); | ||
this.handshaken.push(id); | ||
fn(null, id); | ||
return this; | ||
}; | ||
/** | ||
* Checks if a client is handshaken. | ||
* | ||
* @api public | ||
*/ | ||
Memory.prototype.isHandshaken = function (id, fn) { | ||
fn(null, ~this.handshaken.indexOf(id)); | ||
return this; | ||
}; | ||
/** | ||
* Generates a random id. | ||
* | ||
* @api private | ||
*/ | ||
Memory.prototype.generateId = function () { | ||
var rand = String(Math.random() * Math.random() * Date.now()); | ||
return crypto.createHash('md5').update(rand).digest('hex'); | ||
}; | ||
Memory.prototype.publish = function () { }; | ||
/** | ||
* Retrieves a client store instance. | ||
* Subscribes to a channel | ||
* | ||
* @api public | ||
*/ | ||
Memory.prototype.client = function (id) { | ||
if (!this.clientsMap[id]) { | ||
this.clientsMap[id] = new Memory.Client(this, id); | ||
this.log.debug('initializing client store for', id); | ||
} | ||
return this.clientsMap[id]; | ||
}; | ||
/** | ||
* Called when a client disconnects. | ||
* | ||
* @api public | ||
*/ | ||
Memory.prototype.disconnect = function (id, force, reason) { | ||
if (~this.handshaken.indexOf(id)) { | ||
this.log.debug('destroying dispatcher for', id); | ||
this.handshaken.splice(this.handshaken.indexOf(id), 1); | ||
this.clientsMap[id].destroy(); | ||
this.clientsMap[id] = null; | ||
if (force) | ||
this.publish('disconnect-force:' + id, reason); | ||
this.publish('disconnect:' + id, reason); | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Relays a heartbeat message. | ||
* | ||
* @api private | ||
*/ | ||
Memory.prototype.heartbeat = function (id) { | ||
return this.publish('heartbeat-clear:' + id); | ||
}; | ||
Memory.prototype.subscribe = function () { }; | ||
/** | ||
* Relays a packet | ||
* Unsubscribes | ||
* | ||
@@ -134,100 +63,5 @@ * @api private | ||
Memory.prototype.message = function (id, packet) { | ||
return this.publish('message:' + id, packet); | ||
}; | ||
Memory.prototype.unsubscribe = function () { }; | ||
/** | ||
* Returns client ids in a particular room | ||
* | ||
* @api public | ||
*/ | ||
Memory.prototype.clients = function (room, fn) { | ||
if ('function' == typeof room) { | ||
fn = room; | ||
room = ''; | ||
} | ||
fn && fn(this.rooms[room] || []); | ||
}; | ||
/** | ||
* Joins a user to a room | ||
* | ||
* @api private | ||
*/ | ||
Memory.prototype.join = function (sid, room, fn) { | ||
if (!this.rooms[room]) { | ||
this.rooms[room] = []; | ||
} | ||
this.client(sid).rooms[room] = this.rooms[room].length; | ||
this.rooms[room].push(sid); | ||
fn && fn(); | ||
return this; | ||
}; | ||
/** | ||
* Removes a user from a room | ||
* | ||
* @api private | ||
*/ | ||
Memory.prototype.leave = function (sid, room, fn) { | ||
if (!this.rooms[room] || this.client(sid).rooms[room] === undefined) { | ||
return this; | ||
} | ||
var i = this.client(sid).rooms[room]; | ||
this.rooms[room][i] = null; | ||
delete this.client(sid).rooms[room]; | ||
fn && fn(); | ||
return this; | ||
}; | ||
/** | ||
* Simple publish | ||
* | ||
* @api public | ||
*/ | ||
Memory.prototype.publish = function (ev, data, fn) { | ||
if ('function' == typeof data) { | ||
fn = data; | ||
data = undefined; | ||
} | ||
this.emit(ev, data); | ||
if (fn) fn(); | ||
return this; | ||
}; | ||
/** | ||
* Simple subscribe | ||
* | ||
* @api public | ||
*/ | ||
Memory.prototype.subscribe = function (chn, fn) { | ||
this.on(chn, fn); | ||
return this; | ||
}; | ||
/** | ||
* Simple unsubscribe | ||
* | ||
* @api public | ||
*/ | ||
Memory.prototype.unsubscribe = function (chn) { | ||
this.removeAllListeners(chn); | ||
}; | ||
/** | ||
* Client constructor | ||
@@ -240,5 +74,3 @@ * | ||
Store.Client.apply(this, arguments); | ||
this.reqs = 0; | ||
this.paused = true; | ||
this.rooms = {}; | ||
this.data = {}; | ||
}; | ||
@@ -253,3 +85,3 @@ | ||
/** | ||
* Counts transport requests. | ||
* Gets a key | ||
* | ||
@@ -259,4 +91,4 @@ * @api public | ||
Client.prototype.count = function (fn) { | ||
fn(null, ++this.reqs); | ||
Client.prototype.get = function (key, fn) { | ||
fn(null, this.data[key] === undefined ? null : this.data[key]); | ||
return this; | ||
@@ -266,3 +98,3 @@ }; | ||
/** | ||
* Sets up queue consumption | ||
* Sets a key | ||
* | ||
@@ -272,11 +104,5 @@ * @api public | ||
Client.prototype.consume = function (fn) { | ||
this.consumer = fn; | ||
this.paused = false; | ||
if (this.buffer.length) { | ||
fn(this.buffer, null); | ||
this.buffer = []; | ||
} | ||
Client.prototype.set = function (key, value, fn) { | ||
this.data[key] = value; | ||
fn && fn(null); | ||
return this; | ||
@@ -286,20 +112,13 @@ }; | ||
/** | ||
* Publishes a message to be sent to the client. | ||
* Has a key | ||
* | ||
* @String encoded message | ||
* @api public | ||
*/ | ||
Client.prototype.publish = function (msg) { | ||
if (this.paused) { | ||
this.buffer.push(msg); | ||
} else { | ||
this.consumer(null, msg); | ||
} | ||
return this; | ||
Client.prototype.has = function (key, fn) { | ||
fn(null, key in this.data); | ||
}; | ||
/** | ||
* Pauses the stream. | ||
* Deletes a key | ||
* | ||
@@ -309,4 +128,5 @@ * @api public | ||
Client.prototype.pause = function () { | ||
this.paused = true; | ||
Client.prototype.del = function (key, fn) { | ||
delete this.data[key]; | ||
fn && fn(null); | ||
return this; | ||
@@ -318,41 +138,18 @@ }; | ||
* | ||
* @api public | ||
* @param {Number} number of seconds to expire data | ||
* @api private | ||
*/ | ||
Client.prototype.destroy = function () { | ||
this.buffer = null; | ||
}; | ||
Client.prototype.destroy = function (expiration) { | ||
if ('number' != typeof expiration) { | ||
this.data = {}; | ||
} else { | ||
var self = this; | ||
/** | ||
* Gets a key | ||
* | ||
* @api public | ||
*/ | ||
setTimeout(function () { | ||
self.data = {}; | ||
}, expiration * 1000); | ||
} | ||
Client.prototype.get = function (key, fn) { | ||
fn(null, this.dict[key]); | ||
return this; | ||
}; | ||
/** | ||
* Sets a key | ||
* | ||
* @api public | ||
*/ | ||
Client.prototype.set = function (key, value, fn) { | ||
this.dict[key] = value; | ||
fn && fn(null); | ||
return this; | ||
}; | ||
/** | ||
* Emits a message incoming from client. | ||
* | ||
* @api private | ||
*/ | ||
Client.prototype.onMessage = function (msg) { | ||
this.store.emit('message:' + id, msg); | ||
}; | ||
@@ -26,20 +26,12 @@ | ||
function Transport (mng, data) { | ||
function Transport (mng, data, req) { | ||
this.manager = mng; | ||
this.id = data.id; | ||
this.paused = true; | ||
this.disconnected = false; | ||
this.drained = true; | ||
this.buffer = []; | ||
this.handleRequest(req); | ||
}; | ||
/** | ||
* Sets the corresponding request object. | ||
*/ | ||
Transport.prototype.__defineSetter__('request', function (req) { | ||
this.log.debug('setting request', req.method, req.url); | ||
this.handleRequest(req); | ||
}); | ||
/** | ||
* Access the logger. | ||
@@ -71,2 +63,3 @@ * | ||
Transport.prototype.handleRequest = function (req) { | ||
this.log.debug('setting request', req.method, req.url); | ||
this.req = req; | ||
@@ -78,20 +71,4 @@ | ||
this.drained = true; | ||
this.setHeartbeatInterval(); | ||
this.log.debug('publishing that', this.id, 'connected'); | ||
var self = this; | ||
this.store.publish('open:' + this.id, function () { | ||
self.store.once('open:' + self.id, function () { | ||
self.log.info('request for existing session connection change'); | ||
self.close(); | ||
self.clearTimeouts(); | ||
self.clearHandlers(); | ||
}); | ||
if (!self.paused) { | ||
self.subscribe(); | ||
} | ||
}); | ||
this.setHandlers(); | ||
@@ -119,13 +96,14 @@ this.onSocketConnect(); | ||
this.store.once('disconnect-force:' + this.id, function () { | ||
self.onForcedDisconnect(); | ||
// we need to do this in a pub/sub way since the client can POST the message | ||
// over a different socket (ie: different Transport instance) | ||
this.store.subscribe('heartbeat-clear:' + this.id, function () { | ||
self.onHeartbeatClear(); | ||
}); | ||
this.store.on('heartbeat-clear:' + this.id, function () { | ||
self.clearHeartbeatTimeout(); | ||
self.setHeartbeatInterval(); | ||
this.store.subscribe('disconnect-force:' + this.id, function () { | ||
self.onForcedDisconnect(); | ||
}); | ||
this.store.on('volatile:' + this.id, function (packet) { | ||
self.writeVolatile(packet); | ||
this.store.subscribe('dispatch:' + this.id, function (packet, volatile) { | ||
self.onDispatch(packet, volatile); | ||
}); | ||
@@ -155,3 +133,3 @@ | ||
this.store.unsubscribe('heartbeat-clear:' + this.id); | ||
this.store.unsubscribe('volatile:' + this.id); | ||
this.store.unsubscribe('dispatch:' + this.id); | ||
@@ -171,6 +149,3 @@ this.socket.removeListener('end', this.bound.end); | ||
Transport.prototype.onSocketEnd = function () { | ||
// we check that the socket wasn't swapped | ||
// we don't want to sever a connection that's not active, since we don't kill | ||
// inactive sockets that the browser might reuse for other purposes | ||
this.end(false, 'socket end'); | ||
this.end('socket end'); | ||
}; | ||
@@ -185,3 +160,3 @@ | ||
Transport.prototype.onSocketClose = function (error) { | ||
this.end(false, error ? 'socket error' : 'socket close'); | ||
this.end(error ? 'socket error' : 'socket close'); | ||
}; | ||
@@ -215,2 +190,13 @@ | ||
/** | ||
* Called upon receiving a heartbeat packet. | ||
* | ||
* @api private | ||
*/ | ||
Transport.prototype.onHeartbeatClear = function () { | ||
this.clearHeartbeatTimeout(); | ||
this.setHeartbeatInterval(); | ||
}; | ||
/** | ||
* Called upon a forced disconnection. | ||
@@ -227,3 +213,3 @@ * | ||
} | ||
this.end(true); | ||
this.end('booted'); | ||
} | ||
@@ -233,2 +219,16 @@ }; | ||
/** | ||
* Dispatches a packet. | ||
* | ||
* @api private | ||
*/ | ||
Transport.prototype.onDispatch = function (packet, volatile) { | ||
if (volatile) { | ||
this.writeVolatile(packet); | ||
} else { | ||
this.write(packet); | ||
} | ||
}; | ||
/** | ||
* Sets the close timeout. | ||
@@ -244,3 +244,3 @@ */ | ||
self.closeTimeout = null; | ||
self.end(false, 'close timeout'); | ||
self.end('close timeout'); | ||
}, this.manager.get('close timeout') * 1000); | ||
@@ -276,3 +276,3 @@ | ||
self.heartbeatTimeout = null; | ||
self.end(false, 'heartbeat timeout'); | ||
self.end('heartbeat timeout'); | ||
}, this.manager.get('heartbeat timeout') * 1000); | ||
@@ -306,3 +306,3 @@ | ||
Transport.prototype.setHeartbeatInterval = function () { | ||
if (!this.heartbeatTimeout) { | ||
if (!this.heartbeatInterval) { | ||
var self = this; | ||
@@ -312,2 +312,3 @@ | ||
self.heartbeat(); | ||
self.heartbeatInterval = null; | ||
}, this.manager.get('heartbeat interval') * 1000); | ||
@@ -355,21 +356,46 @@ | ||
Transport.prototype.onMessage = function (packet) { | ||
var current = this.manager.transports[this.id]; | ||
if ('heartbeat' == packet.type) { | ||
this.log.debug('got heartbeat packet'); | ||
this.store.heartbeat(this.id); | ||
} else if ('disconnect' == packet.type && packet.endpoint == '') { | ||
this.log.debug('got disconnection packet'); | ||
this.store.disconnect(this.id, true); | ||
if (current && current.open) { | ||
current.onHeartbeatClear(); | ||
} else { | ||
this.store.publish('heartbeat-clear:' + this.id); | ||
} | ||
} else { | ||
this.log.debug('got packet'); | ||
if ('disconnect' == packet.type && packet.endpoint == '') { | ||
this.log.debug('got disconnection packet'); | ||
if (current && current.open) { | ||
current.onForcedDisconnect(); | ||
} else { | ||
this.store.publish('disconnect-force:' + this.id); | ||
} | ||
} | ||
if (packet.id && packet.ack != 'data') { | ||
this.log.debug('acknowledging packet automatically'); | ||
this.store.client(this.id).publish(parser.encodePacket({ | ||
var ack = parser.encodePacket({ | ||
type: 'ack' | ||
, ackId: packet.id | ||
, endpoint: packet.endpoint || '' | ||
})); | ||
}); | ||
if (current && current.open) { | ||
current.onDispatch(ack); | ||
} else { | ||
this.manager.onClientDispatch(this.id, ack); | ||
this.store.publish('dispatch:' + this.id, ack); | ||
} | ||
} | ||
this.store.message(this.id, packet); | ||
// handle packet locally or publish it | ||
if (current) { | ||
this.manager.onClientMessage(this.id, packet); | ||
} else { | ||
this.store.publish('message:' + this.id, packet); | ||
} | ||
} | ||
@@ -400,3 +426,3 @@ }; | ||
this.packet({ type: 'disconnect' }); | ||
this.end(false, reason); | ||
this.end(reason); | ||
@@ -428,4 +454,5 @@ return this; | ||
this.setCloseTimeout(); | ||
this.unsubscribe(); | ||
this.open = false; | ||
this.manager.onClose(this.id); | ||
this.store.publish('close', this.id); | ||
} | ||
@@ -440,29 +467,18 @@ }; | ||
Transport.prototype.end = function (forced, reason) { | ||
Transport.prototype.end = function (reason) { | ||
if (!this.disconnected) { | ||
this.log.info('ending socket'); | ||
var local = this.manager.transports[this.id]; | ||
this.close(); | ||
this.clearTimeouts(); | ||
if (!forced) | ||
this.store.disconnect(this.id, false, reason); | ||
this.disconnected = true; | ||
} | ||
}; | ||
/** | ||
* Signals that the transport can start flushing buffers. | ||
* | ||
* @api public | ||
*/ | ||
Transport.prototype.resume = function () { | ||
if (!this.disconnected) { | ||
this.paused = false; | ||
this.setHeartbeatInterval(); | ||
this.subscribe(); | ||
if (local) { | ||
this.manager.onClientDisconnect(this.id, reason, true); | ||
} else { | ||
this.store.publish('disconnect:' + this.id, reason); | ||
} | ||
} | ||
return this; | ||
}; | ||
@@ -476,4 +492,9 @@ | ||
Transport.prototype.pause = function () { | ||
this.paused = true; | ||
Transport.prototype.discard = function () { | ||
this.log.debug('discarding transport'); | ||
this.discarded = true; | ||
this.clearTimeouts(); | ||
this.clearHandlers(); | ||
this.buffer = []; | ||
return this; | ||
@@ -498,3 +519,3 @@ }; | ||
this.log.warn(reason, advice ? ('client should ' + advice) : ''); | ||
this.end(false, 'error'); | ||
this.end('error'); | ||
}; | ||
@@ -513,40 +534,2 @@ | ||
/** | ||
* Subscribe client. | ||
* | ||
* @api private | ||
*/ | ||
Transport.prototype.subscribe = function () { | ||
if (!this.subscribed) { | ||
this.log.debug('subscribing', this.id); | ||
var self = this; | ||
// subscribe to buffered + normal messages | ||
this.store.client(this.id).consume(function (payload, packet) { | ||
if (payload) { | ||
self.payload(payload); | ||
} else { | ||
self.write(packet); | ||
} | ||
}); | ||
this.subscribed = true; | ||
} | ||
}; | ||
/** | ||
* Unsubscribe client. | ||
* | ||
* @api private | ||
*/ | ||
Transport.prototype.unsubscribe = function () { | ||
this.log.info('unsubscribing', this.id); | ||
this.store.client(this.id).pause(); | ||
this.subscribed = false; | ||
}; | ||
/** | ||
* Writes a volatile message. | ||
@@ -553,0 +536,0 @@ * |
@@ -26,4 +26,4 @@ | ||
function FlashSocket () { | ||
WebSocket.apply(this, arguments); | ||
function FlashSocket (mng, data, req) { | ||
WebSocket.call(this, mng, data, req); | ||
} | ||
@@ -38,2 +38,10 @@ | ||
/** | ||
* Transport name | ||
* | ||
* @api public | ||
*/ | ||
FlashSocket.prototype.name = 'flashsocket'; | ||
/** | ||
* Listens for new configuration changes of the Manager | ||
@@ -40,0 +48,0 @@ * this way we can enable and disable the flash server. |
@@ -26,4 +26,4 @@ | ||
function HTMLFile (mng, data) { | ||
HTTPTransport.call(this, mng, data); | ||
function HTMLFile (mng, data, req) { | ||
HTTPTransport.call(this, mng, data, req); | ||
}; | ||
@@ -38,2 +38,10 @@ | ||
/** | ||
* Transport name | ||
* | ||
* @api public | ||
*/ | ||
HTMLFile.prototype.name = 'htmlfile'; | ||
/** | ||
* Handles the request. | ||
@@ -75,3 +83,3 @@ * | ||
this.log.debug('htmlfile writing', data); | ||
this.log.debug(this.name + ' writing', data); | ||
}; |
@@ -26,4 +26,4 @@ | ||
function HTTPPolling (mng, data) { | ||
HTTPTransport.call(this, mng, data); | ||
function HTTPPolling (mng, data, req) { | ||
HTTPTransport.call(this, mng, data, req); | ||
}; | ||
@@ -40,2 +40,10 @@ | ||
/** | ||
* Transport name | ||
* | ||
* @api public | ||
*/ | ||
HTTPPolling.prototype.name = 'httppolling'; | ||
/** | ||
* Removes heartbeat timeouts for polling. | ||
@@ -62,3 +70,3 @@ */ | ||
self.packet({ type: 'noop' }); | ||
self.log.debug('polling closed due to exceeded duration'); | ||
self.log.debug(self.name + ' closed due to exceeded duration'); | ||
}, this.manager.get('polling duration') * 1000); | ||
@@ -65,0 +73,0 @@ |
@@ -28,4 +28,4 @@ | ||
function HTTPTransport (mng, data) { | ||
Transport.call(this, mng, data); | ||
function HTTPTransport (mng, data, req) { | ||
Transport.call(this, mng, data, req); | ||
}; | ||
@@ -89,3 +89,3 @@ | ||
for (var i = 0, l = messages.length; i < l; i++) { | ||
this.log.debug('xhr received data packet', data); | ||
this.log.debug(this.name + ' received data packet', data); | ||
this.onMessage(messages[i]); | ||
@@ -92,0 +92,0 @@ } |
@@ -26,4 +26,4 @@ | ||
function JSONPPolling (mng, data) { | ||
HTTPPolling.call(this, mng, data); | ||
function JSONPPolling (mng, data, req) { | ||
HTTPPolling.call(this, mng, data, req); | ||
@@ -45,2 +45,10 @@ this.head = 'io.j[0]('; | ||
/** | ||
* Transport name | ||
* | ||
* @api public | ||
*/ | ||
JSONPPolling.prototype.name = 'jsonppolling'; | ||
/** | ||
* Make sure POST are decoded. | ||
@@ -70,3 +78,3 @@ */ | ||
this.response.write(data); | ||
this.log.debug('json-p writing', data); | ||
this.log.debug(this.name + ' writing', data); | ||
}; |
@@ -30,3 +30,3 @@ | ||
function WebSocket (mng, data) { | ||
function WebSocket (mng, data, req) { | ||
// parser | ||
@@ -37,3 +37,3 @@ var self = this; | ||
this.parser.on('data', function (packet) { | ||
self.log.debug('websocket received data packet', packet); | ||
self.log.debug(self.name + ' received data packet', packet); | ||
self.onMessage(parser.decodePacket(packet)); | ||
@@ -48,3 +48,3 @@ }); | ||
Transport.call(this, mng, data); | ||
Transport.call(this, mng, data, req); | ||
}; | ||
@@ -59,2 +59,10 @@ | ||
/** | ||
* Transport name | ||
* | ||
* @api public | ||
*/ | ||
WebSocket.prototype.name = 'websocket'; | ||
/** | ||
* Called when the socket connects. | ||
@@ -74,3 +82,3 @@ * | ||
if (this.req.headers.upgrade !== 'WebSocket') { | ||
this.log.warn('WebSocket connection invalid'); | ||
this.log.warn(this.name + ' connection invalid'); | ||
this.end(); | ||
@@ -188,3 +196,3 @@ return; | ||
this.log.debug('websocket writing', data); | ||
this.log.debug(this.name + ' writing', data); | ||
} | ||
@@ -203,3 +211,3 @@ }; | ||
for (var i = 0, l = this.buffered.length; i < l; i++) { | ||
this.write(this.buffered.splice(0, 1)); | ||
this.write(this.buffered.splice(0, 1)[0]); | ||
} | ||
@@ -227,3 +235,3 @@ }; | ||
if (spaces === 0 || n % spaces !== 0){ | ||
self.log.warn('Invalid WebSocket key: "' + k + '".'); | ||
self.log.warn('Invalid ' + self.name + ' key: "' + k + '".'); | ||
self.end(); | ||
@@ -230,0 +238,0 @@ return false; |
@@ -26,4 +26,4 @@ | ||
function XHRPolling (mng, data) { | ||
HTTPPolling.call(this, mng, data); | ||
function XHRPolling (mng, data, req) { | ||
HTTPPolling.call(this, mng, data, req); | ||
}; | ||
@@ -38,2 +38,10 @@ | ||
/** | ||
* Transport name | ||
* | ||
* @api public | ||
*/ | ||
XHRPolling.prototype.name = 'xhr-polling'; | ||
/** | ||
* Frames data prior to write. | ||
@@ -65,3 +73,3 @@ * | ||
this.response.write(data); | ||
this.log.debug('xhr-polling writing', data); | ||
this.log.debug(this.name + ' writing', data); | ||
}; |
{ | ||
"name": "socket.io" | ||
, "version": "0.7.2" | ||
, "version": "0.7.3" | ||
, "description": "Realtime apps made cross-browser & easy with a WebSocket-like API" | ||
@@ -18,4 +18,5 @@ , "homepage": "http://socket.io" | ||
, "dependencies": { | ||
"socket.io-client": "0.7.2" | ||
, "policyfile": ">= 0.0.3" | ||
"socket.io-client": "0.7.3" | ||
, "policyfile": "0.0.3" | ||
, "redis": "0.6.0" | ||
} | ||
@@ -22,0 +23,0 @@ , "devDependencies": { |
@@ -1,2 +0,1 @@ | ||
# Socket.IO | ||
@@ -92,3 +91,3 @@ | ||
socket.on('msg', function () { | ||
socket.get('nickname', function (name) { | ||
socket.get('nickname', function (err, name) { | ||
console.log('Chat message by ', name); | ||
@@ -153,5 +152,4 @@ }); | ||
<script> | ||
var socket = io.connect('http://localhost/') | ||
, chat = socket.of('/chat') | ||
, news = socket.of('/news'); | ||
var chat = io.connect('http://localhost/chat') | ||
, news = io.connect('http://localhost/news'); | ||
@@ -282,3 +280,3 @@ chat.on('connect', function () { | ||
```js | ||
var io = require('socket.io-node').listen(80); | ||
var io = require('socket.io').listen(80); | ||
@@ -313,3 +311,3 @@ io.sockets.on('connection', function (socket) { | ||
```js | ||
var io = require('socket.io-node').listen(80); | ||
var io = require('socket.io').listen(80); | ||
@@ -316,0 +314,0 @@ io.configure(function () { |
300435
7334
3
344
+ Addedredis@0.6.0
+ Addedpolicyfile@0.0.3(transitive)
+ Addedredis@0.6.0(transitive)
+ Addedsocket.io-client@0.7.3(transitive)
- Removedpolicyfile@0.0.6(transitive)
- Removedsocket.io-client@0.7.2(transitive)
Updatedpolicyfile@0.0.3
Updatedsocket.io-client@0.7.3