From 272710b1a8b25729c8aeb55ce35501fb34cc964d Mon Sep 17 00:00:00 2001 From: Naomi Seyfer Date: Mon, 1 Apr 2013 12:08:41 -0700 Subject: [PATCH] Cleaning up duplicated code --- packages/livedata/package.js | 2 +- packages/livedata/stream_client_common.js | 249 ++++++++++++++++++++++ packages/livedata/stream_client_nodejs.js | 146 +------------ packages/livedata/stream_client_sockjs.js | 235 ++++---------------- packages/livedata/urls.js | 70 ------ 5 files changed, 291 insertions(+), 411 deletions(-) create mode 100644 packages/livedata/stream_client_common.js delete mode 100644 packages/livedata/urls.js diff --git a/packages/livedata/package.js b/packages/livedata/package.js index 40fa0fd897..922b2513cb 100644 --- a/packages/livedata/package.js +++ b/packages/livedata/package.js @@ -16,7 +16,7 @@ Package.on_use(function (api) { api.add_files(['sockjs-0.3.4.js', 'stream_client_sockjs.js'], 'client'); api.add_files('stream_client_nodejs.js', 'server'); - api.add_files('urls.js', ['client', 'server']); + api.add_files('stream_client_common.js', ['client', 'server']); api.add_files('stream_server.js', 'server'); // livedata_connection.js uses a Minimongo collection internally to diff --git a/packages/livedata/stream_client_common.js b/packages/livedata/stream_client_common.js new file mode 100644 index 0000000000..3ec7d94ba1 --- /dev/null +++ b/packages/livedata/stream_client_common.js @@ -0,0 +1,249 @@ + +// XXX from Underscore.String (http://epeli.github.com/underscore.string/) +var startsWith = function(str, starts) { + return str.length >= starts.length && + str.substring(0, starts.length) === starts; +}; +var endsWith = function(str, ends) { + return str.length >= ends.length && + str.substring(str.length - ends.length) === ends; +}; + +// @param url {String} URL to Meteor app, eg: +// "/" or "madewith.meteor.com" or "https://foo.meteor.com" +// or "ddp+sockjs://ddp--****-foo.meteor.com/sockjs" +// @returns {String} URL to the endpoint with the specific scheme and subPath, e.g. +// for scheme "http" and subPath "sockjs" +// "http://subdomain.meteor.com/sockjs" or "/sockjs" +// or "https://ddp--1234-foo.meteor.com/sockjs" +var translateUrl = function(url, newSchemeBase, subPath) { + if (! newSchemeBase) { + newSchemeBase = "http"; + } + + var ddpUrlMatch = url.match(/^ddp(i?)\+sockjs:\/\//); + var httpUrlMatch = url.match(/^http(s?):\/\//); + var newScheme; + if (ddpUrlMatch) { + // Remove scheme and split off the host. + var urlAfterDDP = url.substr(ddpUrlMatch[0].length); + newScheme = ddpUrlMatch[1] === "i" ? newSchemeBase : newSchemeBase + "s"; + var slashPos = urlAfterDDP.indexOf('/'); + var host = + slashPos === -1 ? urlAfterDDP : urlAfterDDP.substr(0, slashPos); + var rest = slashPos === -1 ? '' : urlAfterDDP.substr(slashPos); + + // In the host (ONLY!), change '*' characters into random digits. This + // allows different stream connections to connect to different hostnames + // and avoid browser per-hostname connection limits. + host = host.replace(/\*/g, function () { + return Math.floor(Random.fraction()*10); + }); + + return newScheme + '://' + host + rest; + } else if (httpUrlMatch) { + newScheme = !httpUrlMatch[1] ? newSchemeBase : newSchemeBase + "s"; + var urlAfterHttp = url.substr(httpUrlMatch[0].length); + url = newScheme + "://" + urlAfterHttp; + } + + // Prefix FQDNs but not relative URLs + if (url.indexOf("://") === -1 && !startsWith(url, "/")) { + url = newSchemeBase + "://" + url; + } + + if (endsWith(url, "/")) + return url + subPath; + else + return url + "/" + subPath; +}; + +_.extend(Meteor._DdpClientStream.prototype, { + + _initCommon: function () { + var self = this; + //// Constants + + // how long to wait until we declare the connection attempt + // failed. + self.CONNECT_TIMEOUT = 10000; + // how long between hearing heartbeat from the server until we declare + // the connection dead. heartbeats come every 25s (stream_server.js) + // + // NOTE: this is a workaround until sockjs detects heartbeats on the + // client automatically. + // https://github.com/sockjs/sockjs-client/issues/67 + // https://github.com/sockjs/sockjs-node/issues/68 + self.HEARTBEAT_TIMEOUT = 60000; + + // time for initial reconnect attempt. + self.RETRY_BASE_TIMEOUT = 1000; + // exponential factor to increase timeout each attempt. + self.RETRY_EXPONENT = 2.2; + // maximum time between reconnects. + self.RETRY_MAX_TIMEOUT = 1800000; // 30min. + // time to wait for the first 2 retries. this helps page reload + // speed during dev mode restarts, but doesn't hurt prod too + // much (due to CONNECT_TIMEOUT) + self.RETRY_MIN_TIMEOUT = 10; + // how many times to try to reconnect 'instantly' + self.RETRY_MIN_COUNT = 2; + // fuzz factor to randomize reconnect times by. avoid reconnect + // storms. + self.RETRY_FUZZ = 0.5; // +- 25% + + + + self.eventCallbacks = {}; // name -> [callback] + + self._forcedToDisconnect = false; + + //// Reactive status + self.currentStatus = { + status: "connecting", + connected: false, + retryCount: 0, + // XXX Backwards compatibility only. Remove this before 1.0. + retry_count: 0 + }; + + + self.statusListeners = typeof Deps !== 'undefined' && new Deps.Dependency; + self.statusChanged = function () { + if (self.statusListeners) + self.statusListeners.changed(); + }; + + //// Retry logic + self.retryTimer = null; + self.connectionTimer = null; + + }, + + // Trigger a reconnect. + reconnect: function (options) { + var self = this; + + if (self.currentStatus.connected) { + if (options && options._force) { + // force reconnect. + self._lostConnection(); + } // else, noop. + return; + } + + // if we're mid-connection, stop it. + if (self.currentStatus.status === "connecting") { + self._lostConnection(); + } + + if (self.retryTimer) + clearTimeout(self.retryTimer); + self.retryTimer = null; + self.currentStatus.retryCount -= 1; // don't count manual retries + // XXX Backwards compatibility only. Remove this before 1.0. + self.currentStatus.retry_count = self.currentStatus.retryCount; + self._retryNow(); + }, + + // Permanently disconnect a stream. + forceDisconnect: function (optionalErrorMessage) { + var self = this; + self._forcedToDisconnect = true; + self._cleanup(); + if (self.retryTimer) { + clearTimeout(self.retryTimer); + self.retryTimer = null; + } + self.currentStatus = { + status: "failed", + connected: false, + retryCount: 0, + // XXX Backwards compatibility only. Remove this before 1.0. + retryCount: 0 + }; + if (optionalErrorMessage) + self.currentStatus.reason = optionalErrorMessage; + self.statusChanged(); + }, + + + _lostConnection: function () { + var self = this; + + self._cleanup(); + self._retryLater(); // sets status. no need to do it here. + }, + + _retryTimeout: function (count) { + var self = this; + + if (count < self.RETRY_MIN_COUNT) + return self.RETRY_MIN_TIMEOUT; + + var timeout = Math.min( + self.RETRY_MAX_TIMEOUT, + self.RETRY_BASE_TIMEOUT * Math.pow(self.RETRY_EXPONENT, count)); + // fuzz the timeout randomly, to avoid reconnect storms when a + // server goes down. + timeout = timeout * ((Random.fraction() * self.RETRY_FUZZ) + + (1 - self.RETRY_FUZZ/2)); + return timeout; + }, + + _retryLater: function () { + var self = this; + + var timeout = self._retryTimeout(self.currentStatus.retryCount); + if (self.retryTimer) + clearTimeout(self.retryTimer); + self.retryTimer = setTimeout(_.bind(self._retryNow, self), timeout); + + self.currentStatus.status = "waiting"; + self.currentStatus.connected = false; + self.currentStatus.retryTime = (new Date()).getTime() + timeout; + // XXX Backwards compatibility only. Remove this before 1.0. + self.currentStatus.retry_time = self.currentStatus.retryTime; + self.statusChanged(); + }, + + _retryNow: function () { + var self = this; + + if (self._forcedToDisconnect) + return; + + self.currentStatus.retryCount += 1; + // XXX Backwards compatibility only. Remove this before 1.0. + self.currentStatus.retry_count = self.currentStatus.retryCount; + self.currentStatus.status = "connecting"; + self.currentStatus.connected = false; + delete self.currentStatus.retryTime; + // XXX Backwards compatibility only. Remove this before 1.0. + delete self.currentStatus.retry_time; + self.statusChanged(); + + self._launchConnection(); + }, + + + // Get current status. Reactive. + status: function () { + var self = this; + if (self.statusListeners) + self.statusListeners.depend(); + return self.currentStatus; + } +}); + +_.extend(Meteor._DdpClientStream, { + + _toSockjsUrl: function (url) { + return translateUrl(url, "http", "sockjs"); + }, + + _toWebsocketUrl: function (url) { + var ret = translateUrl(url, "ws", "websocket"); + return ret; + } +}); diff --git a/packages/livedata/stream_client_nodejs.js b/packages/livedata/stream_client_nodejs.js index cb9d33693f..ec74ead601 100644 --- a/packages/livedata/stream_client_nodejs.js +++ b/packages/livedata/stream_client_nodejs.js @@ -20,8 +20,6 @@ Meteor._DdpClientStream = function (endpoint) { self.client = new WebSocketClient; self.endpoint = endpoint; self.currentConnection = null; - self.eventCallbacks = {}; // name -> [callback] - self._forcedToDisconnect = false; self.client.on('connect', function (connection) { return self._onConnect(connection); @@ -32,44 +30,9 @@ Meteor._DdpClientStream = function (endpoint) { return self._lostConnection(); }); - //// Constants + self._initCommon(); - // how long to wait until we declare the connection attempt - // failed. - self.CONNECT_TIMEOUT = 10000; - - // time for initial reconnect attempt. - self.RETRY_BASE_TIMEOUT = 1000; - // exponential factor to increase timeout each attempt. - self.RETRY_EXPONENT = 2.2; - // maximum time between reconnects. - self.RETRY_MAX_TIMEOUT = 1800000; // 30min. - // time to wait for the first 2 retries. this helps page reload - // speed during dev mode restarts, but doesn't hurt prod too - // much (due to CONNECT_TIMEOUT) - self.RETRY_MIN_TIMEOUT = 10; - // how many times to try to reconnect 'instantly' - self.RETRY_MIN_COUNT = 2; - // fuzz factor to randomize reconnect times by. avoid reconnect - // storms. - self.RETRY_FUZZ = 0.5; // +- 25% - - //// Reactive status - self.currentStatus = { - status: "connecting", connected: false, retryCount: 0 - }; - - self.statusListeners = typeof Deps !== 'undefined' && new Deps.Dependency; - self.statusChanged = function () { - if (self.statusListeners) - self.statusListeners.changed(); - }; self.expectingWelcome = false; - - //// Retry logic - self.retryTimer = null; - self.connectionTimer = null; - //// Kickoff! self._launchConnection(); }; @@ -97,38 +60,6 @@ _.extend(Meteor._DdpClientStream.prototype, { } }, - // Get current status. Reactive. - status: function () { - var self = this; - if (self.statusListeners) - self.statusListeners.depend(); - return self.currentStatus; - }, - - // Trigger a reconnect. - reconnect: function (options) { - var self = this; - - if (self.currentStatus.connected) { - if (options && options._force) { - // force reconnect. - self._lostConnection(); - } // else, noop. - return; - } - - // if we're mid-connection, stop it. - if (self.currentStatus.status === "connecting") { - self._lostConnection(); - } - - if (self.retryTimer) - clearTimeout(self.retryTimer); - self.retryTimer = null; - self.currentStatus.retryCount -= 1; // don't count manual retries - self._retryNow(); - }, - _onConnect: function (connection) { var self = this; @@ -194,7 +125,7 @@ _.extend(Meteor._DdpClientStream.prototype, { _.each(self.eventCallbacks.reset, function (callback) { callback(); }); }, - _cleanupConnection: function () { + _cleanup: function () { var self = this; self._clearConnectionTimer(); @@ -213,80 +144,9 @@ _.extend(Meteor._DdpClientStream.prototype, { } }, - forceDisconnect: function (optionalErrorMessage) { - var self = this; - self._forcedToDisconnect = true; - self._cleanupConnection(); - if (self.retryTimer) { - clearTimeout(self.retryTimer); - self.retryTimer = null; - } - self.currentStatus = { - status: "failed", - connected: false, - retryCount: 0, - // XXX Backwards compatibility only. Remove this before 1.0. - retry_count: 0 - }; - if (optionalErrorMessage) - self.currentStatus.reason = optionalErrorMessage; - self.statusChanged(); - }, - - _lostConnection: function () { - var self = this; - self._cleanupConnection(); - self._retryLater(); - }, - - _retryTimeout: function (count) { - var self = this; - - if (count < self.RETRY_MIN_COUNT) - return self.RETRY_MIN_TIMEOUT; - - var timeout = Math.min( - self.RETRY_MAX_TIMEOUT, - self.RETRY_BASE_TIMEOUT * Math.pow(self.RETRY_EXPONENT, count)); - // fuzz the timeout randomly, to avoid reconnect storms when a - // server goes down. - timeout = timeout * ((Random.fraction() * self.RETRY_FUZZ) + - (1 - self.RETRY_FUZZ/2)); - return timeout; - }, - - _retryLater: function () { - var self = this; - - var timeout = self._retryTimeout(self.currentStatus.retryCount); - if (self.retryTimer) - clearTimeout(self.retryTimer); - self.retryTimer = setTimeout(_.bind(self._retryNow, self), timeout); - - self.currentStatus.status = "waiting"; - self.currentStatus.connected = false; - self.currentStatus.retryTime = (new Date()).getTime() + timeout; - self.statusChanged(); - }, - - _retryNow: function () { - var self = this; - - if (self._forcedToDisconnect) - return; - - self.currentStatus.retryCount += 1; - self.currentStatus.status = "connecting"; - self.currentStatus.connected = false; - delete self.currentStatus.retryTime; - self.statusChanged(); - - self._launchConnection(); - }, - _launchConnection: function () { var self = this; - self._cleanupConnection(); // cleanup the old socket, if there was one. + self._cleanup(); // cleanup the old socket, if there was one. // launch a connect attempt. we have no way to track it. we either // get an _onConnect event, or we don't. diff --git a/packages/livedata/stream_client_sockjs.js b/packages/livedata/stream_client_sockjs.js index c8678a999d..9c128b6301 100644 --- a/packages/livedata/stream_client_sockjs.js +++ b/packages/livedata/stream_client_sockjs.js @@ -3,63 +3,16 @@ // "ddp+sockjs://foo-**.meteor.com/sockjs" Meteor._DdpClientStream = function (url) { var self = this; - + self._initCommon(); self.rawUrl = url; self.socket = null; - self.event_callbacks = {}; // name -> [callback] + self.sent_update_available = false; - self._forcedToDisconnect = false; - //// Constants - - // how long to wait until we declare the connection attempt - // failed. - self.CONNECT_TIMEOUT = 10000; - // how long between hearing heartbeat from the server until we declare - // the connection dead. heartbeats come every 25s (stream_server.js) - // - // NOTE: this is a workaround until sockjs detects heartbeats on the - // client automatically. - // https://github.com/sockjs/sockjs-client/issues/67 - // https://github.com/sockjs/sockjs-node/issues/68 - self.HEARTBEAT_TIMEOUT = 60000; - - // time for initial reconnect attempt. - self.RETRY_BASE_TIMEOUT = 1000; - // exponential factor to increase timeout each attempt. - self.RETRY_EXPONENT = 2.2; - // maximum time between reconnects. - self.RETRY_MAX_TIMEOUT = 1800000; // 30min. - // time to wait for the first 2 retries. this helps page reload - // speed during dev mode restarts, but doesn't hurt prod too - // much (due to CONNECT_TIMEOUT) - self.RETRY_MIN_TIMEOUT = 10; - // how many times to try to reconnect 'instantly' - self.RETRY_MIN_COUNT = 2; - // fuzz factor to randomize reconnect times by. avoid reconnect - // storms. - self.RETRY_FUZZ = 0.5; // +- 25% - - //// Reactive status - self.current_status = { - status: "connecting", connected: false, retryCount: 0, - // XXX Backwards compatibility only. Remove this before 1.0. - retry_count: 0 - }; - - self.status_listeners = window.Deps && new Deps.Dependency; - self.status_changed = function () { - if (self.status_listeners) - self.status_listeners.changed(); - }; - - //// Retry logic - self.retry_timer = null; - self.connection_timer = null; - self.heartbeat_timer = null; + self.heartbeatTimer = null; //// Kickoff! - self._launch_connection(); + self._launchConnection(); }; _.extend(Meteor._DdpClientStream.prototype, { @@ -70,9 +23,9 @@ _.extend(Meteor._DdpClientStream.prototype, { if (name !== 'message' && name !== 'reset' && name !== 'update_available') throw new Error("unknown event type: " + name); - if (!self.event_callbacks[name]) - self.event_callbacks[name] = []; - self.event_callbacks[name].push(callback); + if (!self.eventCallbacks[name]) + self.eventCallbacks[name] = []; + self.eventCallbacks[name].push(callback); }, // data is a utf8 string. Data sent while not connected is dropped on @@ -80,54 +33,20 @@ _.extend(Meteor._DdpClientStream.prototype, { // messages on 'reset' send: function (data) { var self = this; - if (self.current_status.connected) { + if (self.currentStatus.connected) { self.socket.send(data); } }, - // Get current status. Reactive. - status: function () { - var self = this; - if (self.status_listeners) - self.status_listeners.depend(); - return self.current_status; - }, - - // Trigger a reconnect. - reconnect: function (options) { - var self = this; - - if (self.current_status.connected) { - if (options && options._force) { - // force reconnect. - self._lostConnection(); - } // else, noop. - return; - } - - // if we're mid-connection, stop it. - if (self.current_status.status === "connecting") { - self._lostConnection(); - } - - if (self.retry_timer) - clearTimeout(self.retry_timer); - self.retry_timer = null; - self.current_status.retryCount -= 1; // don't count manual retries - // XXX Backwards compatibility only. Remove this before 1.0. - self.current_status.retry_count = self.current_status.retryCount; - self._retry_now(); - }, - _connected: function (welcome_message) { var self = this; - if (self.connection_timer) { - clearTimeout(self.connection_timer); - self.connection_timer = null; + if (self.connectionTimer) { + clearTimeout(self.connectionTimer); + self.connectionTimer = null; } - if (self.current_status.connected) { + if (self.currentStatus.connected) { // already connected. do nothing. this probably shouldn't happen. return; } @@ -144,27 +63,27 @@ _.extend(Meteor._DdpClientStream.prototype, { __meteor_runtime_config__.serverId !== welcome_data.server_id && !self.sent_update_available) { self.sent_update_available = true; - _.each(self.event_callbacks.update_available, + _.each(self.eventCallbacks.update_available, function (callback) { callback(); }); } } else Meteor._debug("DEBUG: invalid welcome packet", welcome_data); // update status - self.current_status.status = "connected"; - self.current_status.connected = true; - self.current_status.retryCount = 0; + self.currentStatus.status = "connected"; + self.currentStatus.connected = true; + self.currentStatus.retryCount = 0; // XXX Backwards compatibility only. Remove before 1.0. - self.current_status.retry_count = self.current_status.retryCount; - self.status_changed(); + self.currentStatus.retryCount = self.currentStatus.retryCount; + self.statusChanged(); // fire resets. This must come after status change so that clients // can call send from within a reset callback. - _.each(self.event_callbacks.reset, function (callback) { callback(); }); + _.each(self.eventCallbacks.reset, function (callback) { callback(); }); }, - _cleanupSocket: function () { + _cleanup: function () { var self = this; self._clearConnectionAndHeartbeatTimers(); @@ -178,44 +97,16 @@ _.extend(Meteor._DdpClientStream.prototype, { _clearConnectionAndHeartbeatTimers: function () { var self = this; - if (self.connection_timer) { - clearTimeout(self.connection_timer); - self.connection_timer = null; + if (self.connectionTimer) { + clearTimeout(self.connectionTimer); + self.connectionTimer = null; } - if (self.heartbeat_timer) { - clearTimeout(self.heartbeat_timer); - self.heartbeat_timer = null; + if (self.heartbeatTimer) { + clearTimeout(self.heartbeatTimer); + self.heartbeatTimer = null; } }, - // Permanently disconnect a stream. - forceDisconnect: function (optionalErrorMessage) { - var self = this; - self._forcedToDisconnect = true; - self._cleanupSocket(); - if (self.retry_timer) { - clearTimeout(self.retry_timer); - self.retry_timer = null; - } - self.current_status = { - status: "failed", - connected: false, - retryCount: 0, - // XXX Backwards compatibility only. Remove this before 1.0. - retry_count: 0 - }; - if (optionalErrorMessage) - self.current_status.reason = optionalErrorMessage; - self.status_changed(); - }, - - _lostConnection: function () { - var self = this; - - self._cleanupSocket(); - self._retry_later(); // sets status. no need to do it here. - }, - _heartbeat_timeout: function () { var self = this; Meteor._debug("Connection timeout. No heartbeat received."); @@ -228,67 +119,17 @@ _.extend(Meteor._DdpClientStream.prototype, { // already cleared, and we don't need to set it again. if (self._forcedToDisconnect) return; - if (self.heartbeat_timer) - clearTimeout(self.heartbeat_timer); - self.heartbeat_timer = setTimeout( + if (self.heartbeatTimer) + clearTimeout(self.heartbeatTimer); + self.heartbeatTimer = setTimeout( _.bind(self._heartbeat_timeout, self), self.HEARTBEAT_TIMEOUT); }, - _retry_timeout: function (count) { + + _launchConnection: function () { var self = this; - - if (count < self.RETRY_MIN_COUNT) - return self.RETRY_MIN_TIMEOUT; - - var timeout = Math.min( - self.RETRY_MAX_TIMEOUT, - self.RETRY_BASE_TIMEOUT * Math.pow(self.RETRY_EXPONENT, count)); - // fuzz the timeout randomly, to avoid reconnect storms when a - // server goes down. - timeout = timeout * ((Random.fraction() * self.RETRY_FUZZ) + - (1 - self.RETRY_FUZZ/2)); - return timeout; - }, - - _retry_later: function () { - var self = this; - - var timeout = self._retry_timeout(self.current_status.retryCount); - if (self.retry_timer) - clearTimeout(self.retry_timer); - self.retry_timer = setTimeout(_.bind(self._retry_now, self), timeout); - - self.current_status.status = "waiting"; - self.current_status.connected = false; - self.current_status.retryTime = (new Date()).getTime() + timeout; - // XXX Backwards compatibility only. Remove this before 1.0. - self.current_status.retry_time = self.current_status.retryTime; - self.status_changed(); - }, - - _retry_now: function () { - var self = this; - - if (self._forcedToDisconnect) - return; - - self.current_status.retryCount += 1; - // XXX Backwards compatibility only. Remove this before 1.0. - self.current_status.retry_count = self.current_status.retryCount; - self.current_status.status = "connecting"; - self.current_status.connected = false; - delete self.current_status.retryTime; - // XXX Backwards compatibility only. Remove this before 1.0. - delete self.current_status.retry_time; - self.status_changed(); - - self._launch_connection(); - }, - - _launch_connection: function () { - var self = this; - self._cleanupSocket(); // cleanup the old socket, if there was one. + self._cleanup(); // cleanup the old socket, if there was one. // Convert raw URL to SockJS URL each time we open a connection, so that we // can connect to random hostnames and get around browser per-host @@ -307,10 +148,10 @@ _.extend(Meteor._DdpClientStream.prototype, { // first message we get when we're connecting goes to _connected, // which connects us. All subsequent messages (while connected) go to // the callback. - if (self.current_status.status === "connecting") + if (self.currentStatus.status === "connecting") self._connected(data.data); - else if (self.current_status.connected) - _.each(self.event_callbacks.message, function (callback) { + else if (self.currentStatus.connected) + _.each(self.eventCallbacks.message, function (callback) { callback(data.data); }); }; @@ -327,9 +168,9 @@ _.extend(Meteor._DdpClientStream.prototype, { self._heartbeat_received(); }; - if (self.connection_timer) - clearTimeout(self.connection_timer); - self.connection_timer = setTimeout( + if (self.connectionTimer) + clearTimeout(self.connectionTimer); + self.connectionTimer = setTimeout( _.bind(self._lostConnection, self), self.CONNECT_TIMEOUT); } diff --git a/packages/livedata/urls.js b/packages/livedata/urls.js deleted file mode 100644 index a77517bfba..0000000000 --- a/packages/livedata/urls.js +++ /dev/null @@ -1,70 +0,0 @@ - -// XXX from Underscore.String (http://epeli.github.com/underscore.string/) -var startsWith = function(str, starts) { - return str.length >= starts.length && - str.substring(0, starts.length) === starts; -}; -var endsWith = function(str, ends) { - return str.length >= ends.length && - str.substring(str.length - ends.length) === ends; -}; - -// @param url {String} URL to Meteor app, eg: -// "/" or "madewith.meteor.com" or "https://foo.meteor.com" -// or "ddp+sockjs://ddp--****-foo.meteor.com/sockjs" -// @returns {String} URL to the endpoint with the specific scheme and subPath, e.g. -// for scheme "http" and subPath "sockjs" -// "http://subdomain.meteor.com/sockjs" or "/sockjs" -// or "https://ddp--1234-foo.meteor.com/sockjs" -var translateUrl = function(url, newSchemeBase, subPath) { - if (! newSchemeBase) { - newSchemeBase = "http"; - } - - var ddpUrlMatch = url.match(/^ddp(i?)\+sockjs:\/\//); - var httpUrlMatch = url.match(/^http(s?):\/\//); - var newScheme; - if (ddpUrlMatch) { - // Remove scheme and split off the host. - var urlAfterDDP = url.substr(ddpUrlMatch[0].length); - newScheme = ddpUrlMatch[1] === "i" ? newSchemeBase : newSchemeBase + "s"; - var slashPos = urlAfterDDP.indexOf('/'); - var host = - slashPos === -1 ? urlAfterDDP : urlAfterDDP.substr(0, slashPos); - var rest = slashPos === -1 ? '' : urlAfterDDP.substr(slashPos); - - // In the host (ONLY!), change '*' characters into random digits. This - // allows different stream connections to connect to different hostnames - // and avoid browser per-hostname connection limits. - host = host.replace(/\*/g, function () { - return Math.floor(Random.fraction()*10); - }); - - return newScheme + '://' + host + rest; - } else if (httpUrlMatch) { - newScheme = !httpUrlMatch[1] ? newSchemeBase : newSchemeBase + "s"; - var urlAfterHttp = url.substr(httpUrlMatch[0].length); - url = newScheme + "://" + urlAfterHttp; - } - - // Prefix FQDNs but not relative URLs - if (url.indexOf("://") === -1 && !startsWith(url, "/")) { - url = newSchemeBase + "://" + url; - } - - if (endsWith(url, "/")) - return url + subPath; - else - return url + "/" + subPath; -}; - -_.extend(Meteor._DdpClientStream, { - _toSockjsUrl: function (url) { - return translateUrl(url, "http", "sockjs"); - }, - - _toWebsocketUrl: function (url) { - var ret = translateUrl(url, "ws", "websocket"); - return ret; - } -});