New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add send
callback feature + change README sample
#63
Changes from 8 commits
634b11a
5d846e1
1434eaf
cb02a97
347639b
d5dff2d
9073a07
ab4393f
23004e8
8f4d6f9
c81cf61
51f110f
893a9f3
2125d0b
514e728
148a102
1e3a0ef
934d323
175a3f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,8 @@ function Socket (id, server, transport) { | |
this.upgraded = false; | ||
this.readyState = 'opening'; | ||
this.writeBuffer = []; | ||
|
||
this.packetSeq = 0; | ||
this.packetsFn = {}; | ||
this.setTransport(transport); | ||
this.onOpen(); | ||
} | ||
|
@@ -95,6 +96,8 @@ Socket.prototype.onPacket = function (packet) { | |
}; | ||
|
||
Socket.prototype.onError = function (err) { | ||
this.packetsFn = {}; | ||
this.packetSeq = 0; | ||
debug('transport error'); | ||
this.onClose('transport error', err); | ||
}; | ||
|
@@ -132,6 +135,8 @@ Socket.prototype.setTransport = function (transport) { | |
this.transport.on('packet', this.onPacket.bind(this)); | ||
this.transport.on('drain', this.flush.bind(this)); | ||
this.transport.once('close', this.onClose.bind(this, 'transport close')); | ||
//this function will manage packet events (also message callbacks) | ||
this.setupSendCallback(); | ||
}; | ||
|
||
/** | ||
|
@@ -207,22 +212,43 @@ Socket.prototype.clearTransport = function () { | |
|
||
Socket.prototype.onClose = function (reason, description) { | ||
if ('closed' != this.readyState) { | ||
this.packetsFn = {}; | ||
this.packetSeq = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bad indentation |
||
this.clearTransport(); | ||
this.readyState = 'closed'; | ||
this.emit('close', reason, description); | ||
} | ||
}; | ||
|
||
/** | ||
* Setup and manage send callback | ||
* | ||
* @api private | ||
*/ | ||
|
||
Socket.prototype.setupSendCallback = function () { | ||
var self = this; | ||
//the message was sent successfully, execute the callback | ||
this.transport.on("drain", function(seq){ | ||
if('function' == typeof self.packetsFn[seq]) { | ||
debug('executing send callback'); | ||
self.packetsFn[seq](self.transport); | ||
delete self.packetsFn[seq]; | ||
} | ||
}); | ||
}; | ||
|
||
/** | ||
* Sends a message packet. | ||
* | ||
* @param {String} message | ||
* @param {Function} callback | ||
* @return {Socket} for chaining | ||
* @api public | ||
*/ | ||
|
||
Socket.prototype.send = function (data) { | ||
this.sendPacket('message', data); | ||
Socket.prototype.send = function (data, callback) { | ||
this.sendPacket('message', data, callback); | ||
return this; | ||
}; | ||
|
||
|
@@ -234,10 +260,16 @@ Socket.prototype.send = function (data) { | |
* @api private | ||
*/ | ||
|
||
Socket.prototype.sendPacket = function (type, data) { | ||
Socket.prototype.sendPacket = function (type, data, callback) { | ||
if ('closing' != this.readyState) { | ||
debug('sending packet "%s" (%s)', type, data); | ||
this.writeBuffer.push({ type: type, data: data }); | ||
this.writeBuffer.push({ seq: this.packetSeq, type: type, data: data }); | ||
//add send callback to object | ||
if('undefined' != typeof callback){ | ||
this.packetsFn[this.packetSeq] = callback; | ||
} | ||
//increase the packet acks | ||
this.packetSeq++; | ||
this.flush(); | ||
} | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,8 @@ module.exports = Polling; | |
|
||
function Polling (req) { | ||
Transport.call(this, req); | ||
//save sequence ids state | ||
this.seqIds = []; | ||
}; | ||
|
||
/** | ||
|
@@ -96,7 +98,16 @@ Polling.prototype.onPollRequest = function (req, res) { | |
req.on('close', onClose); | ||
|
||
this.writable = true; | ||
this.emit('drain'); | ||
//decide to send empty `drain` or not | ||
if (req.query.sid && this.writable && this.seqIds.length > 0) { | ||
debug("acks received from client, emit drain"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. single quotes |
||
var singleItem = this.seqIds.splice(0,1); | ||
for (var i = 0, l = singleItem[0].length; i < l; ++i) { | ||
this.emit('drain', singleItem[0][i]); | ||
} | ||
} else { | ||
this.emit('drain'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it necessary that the polling transport reports what sequence id it's flushed? If you think about it, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, Actually any transport has two type of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure but the transports don't really need to know about sequence ids. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean always emit an empty There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as |
||
} | ||
|
||
// if we're still writable but had a pending close, trigger an empty send | ||
if (this.writable && this.shouldClose) { | ||
|
@@ -195,7 +206,13 @@ Polling.prototype.send = function (packets) { | |
this.shouldClose(); | ||
this.shouldClose = null; | ||
} | ||
|
||
var pushTo = []; | ||
for (var i = 0, l = packets.length; i < l; ++i) { | ||
if (typeof packets[i].seq != "undefined" && packets[i].type == "message") { | ||
pushTo.push(packets[i].seq); | ||
} | ||
} | ||
if (pushTo.length > 0) this.seqIds.push(pushTo); | ||
this.write(parser.encodePayload(packets)); | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -389,6 +389,8 @@ describe('server', function () { | |
}); | ||
}); | ||
|
||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unneeded \n's |
||
it('should arrive from server to client (multiple)', function (done) { | ||
var engine = listen({ allowUpgrades: false }, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)) | ||
|
@@ -493,6 +495,143 @@ describe('server', function () { | |
}); | ||
}); | ||
|
||
describe('send', function(){ | ||
describe('callback', function(){ | ||
it('should execute when message sent (polling)', function (done) { | ||
var engine = listen({ allowUpgrades: false }, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] }), | ||
i = 0; | ||
engine.on('connection', function (conn) { | ||
conn.send('a', function(transport) { | ||
i++; | ||
}); | ||
}); | ||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
i++; | ||
}); | ||
}); | ||
|
||
setTimeout(function(){ | ||
expect(i).to.be(2); | ||
done(); | ||
},10); | ||
}); | ||
}); | ||
|
||
it('should execute when message sent (websocket)', function (done) { | ||
var engine = listen({ allowUpgrades: false }, function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] }), | ||
i = 0; | ||
engine.on('connection', function (conn) { | ||
conn.send('a', function(transport) { | ||
i++; | ||
}); | ||
}); | ||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
i++; | ||
}); | ||
}); | ||
|
||
setTimeout(function(){ | ||
expect(i).to.be(2); | ||
done(); | ||
},10); | ||
}); | ||
}); | ||
|
||
it('should execute once for each send', function (done) { | ||
var engine = listen(function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)), | ||
i = 0, | ||
j = 0; | ||
engine.on('connection', function (conn) { | ||
conn.send('b', function (transport) { | ||
j++; | ||
}); | ||
|
||
conn.send('a', function (transport) { | ||
i++; | ||
}); | ||
|
||
}); | ||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
if (msg == "a") { | ||
i++; | ||
} else if (msg == "b") { | ||
j++; | ||
} | ||
}); | ||
}); | ||
|
||
setTimeout(function () { | ||
expect(i).to.be(2); | ||
expect(j).to.be(2); | ||
done(); | ||
}, 50); | ||
}); | ||
}); | ||
|
||
it('should execute in mutlipart packet', function (done) { | ||
var engine = listen(function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port)), | ||
i = 0; | ||
engine.on('connection', function (conn) { | ||
conn.send('b', function (transport) { | ||
i++; | ||
}); | ||
|
||
conn.send('a', function(transport) { | ||
i++; | ||
}); | ||
|
||
}); | ||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
i++; | ||
}); | ||
}); | ||
|
||
setTimeout(function () { | ||
expect(i).to.be(4); | ||
done(); | ||
}, 50); | ||
}); | ||
}); | ||
|
||
it('should execute in separate message', function (done) { | ||
var engine = listen(function (port) { | ||
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] }), | ||
i = 0; | ||
engine.on('connection', function (conn) { | ||
|
||
conn.send('a', function(transport) { | ||
i++; | ||
|
||
conn.send('b', function (transport) { | ||
i++; | ||
}); | ||
}); | ||
}); | ||
|
||
socket.on('open', function () { | ||
socket.on('message', function (msg) { | ||
i++; | ||
}); | ||
}); | ||
|
||
setTimeout(function () { | ||
expect(i).to.be(4); | ||
done(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indent |
||
}, 10); | ||
}); | ||
}); | ||
|
||
}); | ||
}); | ||
|
||
describe('upgrade', function () { | ||
it('should upgrade', function (done) { | ||
var engine = listen(function (port) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to show this so prominently. It's kindof an advanced-ish feature