UNPKG

faye

Version:

Simple pub/sub messaging for the web

187 lines (144 loc) 5.19 kB
'use strict'; var Class = require('../util/class'), URI = require('../util/uri'), cookies = require('../util/cookies'), assign = require('../util/assign'), Logging = require('../mixins/logging'), Publisher = require('../mixins/publisher'), Transport = require('../transport'), Scheduler = require('./scheduler'); var Dispatcher = Class({ className: 'Dispatcher', MAX_REQUEST_SIZE: 2048, DEFAULT_RETRY: 5, UP: 1, DOWN: 2, initialize: function(client, endpoint, options) { this._client = client; this.endpoint = URI.parse(endpoint); this._alternates = options.endpoints || {}; this.cookies = cookies.CookieJar && new cookies.CookieJar(); this._disabled = []; this._envelopes = {}; this.headers = {}; this.retry = options.retry || this.DEFAULT_RETRY; this._scheduler = options.scheduler || Scheduler; this._state = 0; this.transports = {}; this.wsExtensions = []; this.proxy = options.proxy || {}; if (typeof this._proxy === 'string') this._proxy = { origin: this._proxy }; var exts = options.websocketExtensions; if (exts) { exts = [].concat(exts); for (var i = 0, n = exts.length; i < n; i++) this.addWebsocketExtension(exts[i]); } this.tls = options.tls || {}; this.tls.ca = this.tls.ca || options.ca; for (var type in this._alternates) this._alternates[type] = URI.parse(this._alternates[type]); this.maxRequestSize = this.MAX_REQUEST_SIZE; }, endpointFor: function(connectionType) { return this._alternates[connectionType] || this.endpoint; }, addWebsocketExtension: function(extension) { this.wsExtensions.push(extension); }, disable: function(feature) { this._disabled.push(feature); Transport.disable(feature); }, setHeader: function(name, value) { this.headers[name] = value; }, close: function() { var transport = this._transport; delete this._transport; if (transport) transport.close(); }, getConnectionTypes: function() { return Transport.getConnectionTypes(); }, selectTransport: function(transportTypes) { Transport.get(this, transportTypes, this._disabled, function(transport) { this.debug('Selected ? transport for ?', transport.connectionType, transport.endpoint.href); if (transport === this._transport) return; if (this._transport) this._transport.close(); this._transport = transport; this.connectionType = transport.connectionType; }, this); }, sendMessage: function(message, timeout, options) { options = options || {}; var id = message.id, attempts = options.attempts, deadline = options.deadline && new Date().getTime() + (options.deadline * 1000), envelope = this._envelopes[id], scheduler; if (!envelope) { scheduler = new this._scheduler(message, { timeout: timeout, interval: this.retry, attempts: attempts, deadline: deadline }); envelope = this._envelopes[id] = { message: message, scheduler: scheduler }; } this._sendEnvelope(envelope); }, _sendEnvelope: function(envelope) { if (!this._transport) return; if (envelope.request || envelope.timer) return; var message = envelope.message, scheduler = envelope.scheduler, self = this; if (!scheduler.isDeliverable()) { scheduler.abort(); delete this._envelopes[message.id]; return; } envelope.timer = global.setTimeout(function() { self.handleError(message); }, scheduler.getTimeout() * 1000); scheduler.send(); envelope.request = this._transport.sendMessage(message); }, handleResponse: function(reply) { var envelope = this._envelopes[reply.id]; if (reply.successful !== undefined && envelope) { envelope.scheduler.succeed(); delete this._envelopes[reply.id]; global.clearTimeout(envelope.timer); } this.trigger('message', reply); if (this._state === this.UP) return; this._state = this.UP; this._client.trigger('transport:up'); }, handleError: function(message, immediate) { var envelope = this._envelopes[message.id], request = envelope && envelope.request, self = this; if (!request) return; request.then(function(req) { if (req && req.abort) req.abort(); }); var scheduler = envelope.scheduler; scheduler.fail(); global.clearTimeout(envelope.timer); envelope.request = envelope.timer = null; if (immediate) { this._sendEnvelope(envelope); } else { envelope.timer = global.setTimeout(function() { envelope.timer = null; self._sendEnvelope(envelope); }, scheduler.getInterval() * 1000); } if (this._state === this.DOWN) return; this._state = this.DOWN; this._client.trigger('transport:down'); } }); Dispatcher.create = function(client, endpoint, options) { return new Dispatcher(client, endpoint, options); }; assign(Dispatcher.prototype, Publisher); assign(Dispatcher.prototype, Logging); module.exports = Dispatcher;