|
|
/** * Module dependencies. */
var Transport = require('../transport'); var parseqs = require('parseqs'); var parser = require('engine.io-parser'); var inherit = require('component-inherit'); var yeast = require('yeast'); var debug = require('debug')('engine.io-client:polling');
/** * Module exports. */
module.exports = Polling;
/** * Is XHR2 supported? */
var hasXHR2 = (function () { var XMLHttpRequest = require('xmlhttprequest-ssl'); 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 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'); };
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] = yeast(); }
if (!this.supportsBinary && !query.sid) { query.b64 = 1; }
query = parseqs.encode(query);
// avoid port if default for schema
if (this.port && (('https' === schema && Number(this.port) !== 443) || ('http' === schema && Number(this.port) !== 80))) { port = ':' + this.port; }
// prepend ? to query
if (query.length) { query = '?' + query; }
var ipv6 = this.hostname.indexOf(':') !== -1; return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query; };
|