5 var Transport = require('../transport');
6 var parseqs = require('parseqs');
7 var parser = require('engine.io-parser');
8 var inherit = require('component-inherit');
9 var yeast = require('yeast');
10 var debug = require('debug')('engine.io-client:polling');
16 module.exports = Polling;
22 var hasXHR2 = (function () {
23 var XMLHttpRequest = require('xmlhttprequest-ssl');
24 var xhr = new XMLHttpRequest({ xdomain: false });
25 return null != xhr.responseType;
31 * @param {Object} opts
35 function Polling (opts) {
36 var forceBase64 = (opts && opts.forceBase64);
37 if (!hasXHR2 || forceBase64) {
38 this.supportsBinary = false;
40 Transport.call(this, opts);
44 * Inherits from Transport.
47 inherit(Polling, Transport);
53 Polling.prototype.name = 'polling';
56 * Opens the socket (triggers polling). We write a PING message to determine
57 * when the transport is open.
62 Polling.prototype.doOpen = function () {
69 * @param {Function} callback upon buffers are flushed and transport is paused
73 Polling.prototype.pause = function (onPause) {
76 this.readyState = 'pausing';
80 self.readyState = 'paused';
84 if (this.polling || !this.writable) {
88 debug('we are currently polling - waiting to pause');
90 this.once('pollComplete', function () {
91 debug('pre-pause polling complete');
97 debug('we are currently writing - waiting to pause');
99 this.once('drain', function () {
100 debug('pre-pause writing complete');
110 * Starts polling cycle.
115 Polling.prototype.poll = function () {
123 * Overloads onData to detect payloads.
128 Polling.prototype.onData = function (data) {
130 debug('polling got data %s', data);
131 var callback = function (packet, index, total) {
132 // if its the first message we consider the transport open
133 if ('opening' === self.readyState && packet.type === 'open') {
137 // if its a close packet, we close the ongoing requests
138 if ('close' === packet.type) {
143 // otherwise bypass onData and handle the message
144 self.onPacket(packet);
148 parser.decodePayload(data, this.socket.binaryType, callback);
150 // if an event did not trigger closing
151 if ('closed' !== this.readyState) {
152 // if we got data we're not polling
153 this.polling = false;
154 this.emit('pollComplete');
156 if ('open' === this.readyState) {
159 debug('ignoring poll - transport state "%s"', this.readyState);
165 * For polling, send a close packet.
170 Polling.prototype.doClose = function () {
174 debug('writing close packet');
175 self.write([{ type: 'close' }]);
178 if ('open' === this.readyState) {
179 debug('transport open - closing');
182 // in case we're trying to close while
183 // handshaking is in progress (GH-164)
184 debug('transport not open - deferring close');
185 this.once('open', close);
190 * Writes a packets payload.
192 * @param {Array} data packets
193 * @param {Function} drain callback
197 Polling.prototype.write = function (packets) {
199 this.writable = false;
200 var callbackfn = function () {
201 self.writable = true;
205 parser.encodePayload(packets, this.supportsBinary, function (data) {
206 self.doWrite(data, callbackfn);
211 * Generates uri for connection.
216 Polling.prototype.uri = function () {
217 var query = this.query || {};
218 var schema = this.secure ? 'https' : 'http';
221 // cache busting is forced
222 if (false !== this.timestampRequests) {
223 query[this.timestampParam] = yeast();
226 if (!this.supportsBinary && !query.sid) {
230 query = parseqs.encode(query);
232 // avoid port if default for schema
233 if (this.port && (('https' === schema && Number(this.port) !== 443) ||
234 ('http' === schema && Number(this.port) !== 80))) {
235 port = ':' + this.port;
238 // prepend ? to query
243 var ipv6 = this.hostname.indexOf(':') !== -1;
244 return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;