|
|
/** * Module dependencies. */
var Transport = require('../transport'); var parseqs = require('parseqs'); var parser = require('engine.io-parser'); var inherit = require('component-inherit'); var debug = require('debug')('engine.io-client:polling');
/** * Module exports. */
module.exports = Polling;
/** * Is XHR2 supported? */
var hasXHR2 = (function() { var XMLHttpRequest = require('xmlhttprequest'); var xhr = new XMLHttpRequest({ xdomain: false }); return null != xhr.responseType; })();
/** * Polling interface. * * @param {Object} opts * @api private */
function Polling(opts){ var forceBase64 = (opts && opts.forceBase64); if (!hasXHR2 || forceBase64) { this.supportsBinary = false; } Transport.call(this, opts); }
/** * Inherits from Transport. */
inherit(Polling, Transport);
/** * Transport name. */
Polling.prototype.name = 'polling';
/** * Opens the socket (triggers polling). We write a PING message to determine * when the transport is open. * * @api private */
Polling.prototype.doOpen = function(){ this.poll(); };
/** * Pauses polling. * * @param {Function} callback upon buffers are flushed and transport is paused * @api private */
Polling.prototype.pause = function(onPause){ var pending = 0; var self = this;
this.readyState = 'pausing';
function pause(){ debug('paused'); self.readyState = 'paused'; onPause(); }
if (this.polling || !this.writable) { var total = 0;
if (this.polling) { debug('we are currently polling - waiting to pause'); total++; this.once('pollComplete', function(){ debug('pre-pause polling complete'); --total || pause(); }); }
if (!this.writable) { debug('we are currently writing - waiting to pause'); total++; this.once('drain', function(){ debug('pre-pause writing complete'); --total || pause(); }); } } else { pause(); } };
/** * Starts polling cycle. * * @api public */
Polling.prototype.poll = function(){ debug('polling'); this.polling = true; this.doPoll(); this.emit('poll'); };
/** * Overloads onData to detect payloads. * * @api private */
Polling.prototype.onData = function(data){ var self = this; debug('polling got data %s', data); var callback = function(packet, index, total) { // if its the first message we consider the transport open
if ('opening' == self.readyState) { self.onOpen(); }
// if its a close packet, we close the ongoing requests
if ('close' == packet.type) { self.onClose(); return false; }
// otherwise bypass onData and handle the message
self.onPacket(packet); };
// decode payload
parser.decodePayload(data, this.socket.binaryType, callback);
// if an event did not trigger closing
if ('closed' != this.readyState) { // if we got data we're not polling
this.polling = false; this.emit('pollComplete');
if ('open' == this.readyState) { this.poll(); } else { debug('ignoring poll - transport state "%s"', this.readyState); } } };
/** * For polling, send a close packet. * * @api private */
Polling.prototype.doClose = function(){ var self = this;
function close(){ debug('writing close packet'); self.write([{ type: 'close' }]); }
if ('open' == this.readyState) { debug('transport open - closing'); close(); } else { // in case we're trying to close while
// handshaking is in progress (GH-164)
debug('transport not open - deferring close'); this.once('open', close); } };
/** * Writes a packets payload. * * @param {Array} data packets * @param {Function} drain callback * @api private */
Polling.prototype.write = function(packets){ var self = this; this.writable = false; var callbackfn = function() { self.writable = true; self.emit('drain'); };
var self = this; parser.encodePayload(packets, this.supportsBinary, function(data) { self.doWrite(data, callbackfn); }); };
/** * Generates uri for connection. * * @api private */
Polling.prototype.uri = function(){ var query = this.query || {}; var schema = this.secure ? 'https' : 'http'; var port = '';
// cache busting is forced
if (false !== this.timestampRequests) { query[this.timestampParam] = +new Date + '-' + Transport.timestamps++; }
if (!this.supportsBinary && !query.sid) { query.b64 = 1; }
query = parseqs.encode(query);
// avoid port if default for schema
if (this.port && (('https' == schema && this.port != 443) || ('http' == schema && this.port != 80))) { port = ':' + this.port; }
// prepend ? to query
if (query.length) { query = '?' + query; }
return schema + '://' + this.hostname + port + this.path + query; };
|