diff --git a/packages/livedata/client_convenience.js b/packages/livedata/client_convenience.js index b6992d1ac7..5838ab1e2d 100644 --- a/packages/livedata/client_convenience.js +++ b/packages/livedata/client_convenience.js @@ -11,8 +11,38 @@ if (Meteor.isClient) { if (__meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL) ddpUrl = __meteor_runtime_config__.DDP_DEFAULT_CONNECTION_URL; } + + var negotiationFailuresKey = "Meteor.DDPVersionNegotiationFailures"; + + var onConnected = function () { + Meteor._localStorage.removeItem(negotiationFailuresKey); + }; + + var exponentialBackoff = function (failures) { + return Math.pow(failures, 1.5) * 1000; + }; + + var onDDPVersionNegotiationFailure = function (serverRequestedVersion) { + if (Package.reload) { + var failures = parseInt(Meteor._localStorage.getItem(negotiationFailuresKey) || "0") + 1; + Meteor._localStorage.setItem(negotiationFailuresKey, "" + failures); + Meteor.setTimeout( + function () { + Package.reload.Reload._reload(); + }, + exponentialBackoff(failures) + ); + } + else { + Meteor._debug("DDP version negotiation failed; server requested version " + serverRequestedVersion); + } + }; + Meteor.connection = - DDP.connect(ddpUrl, true /* restart_on_update */); + DDP.connect(ddpUrl, { + onConnected: onConnected, + onDDPVersionNegotiationFailure: onDDPVersionNegotiationFailure + }); // Proxy the public methods of Meteor.connection so they can // be called directly on Meteor. diff --git a/packages/livedata/livedata_connection.js b/packages/livedata/livedata_connection.js index f71db523bc..fd62c5c5a1 100644 --- a/packages/livedata/livedata_connection.js +++ b/packages/livedata/livedata_connection.js @@ -8,16 +8,17 @@ if (Meteor.isServer) { // or an object as a test hook (see code) // Options: // reloadWithOutstanding: is it OK to reload if there are outstanding methods? +// onDDPNegotiationVersionFailure: callback with the server requested version. var Connection = function (url, options) { var self = this; options = _.extend({ + onConnected: function () {}, + onDDPVersionNegotiationFailure: function (serverRequestedVersion, error) { + Meteor._debug("Failed DDP connection: " + error); + }, // These options are only for testing. reloadWithOutstanding: false, - supportedDDPVersions: SUPPORTED_DDP_VERSIONS, - onConnectionFailure: function (reason) { - Meteor._debug("Failed DDP connection: " + reason); - }, - onConnected: function () {} + supportedDDPVersions: SUPPORTED_DDP_VERSIONS }, options); // If set, called when we reconnect, queuing method calls _before_ the @@ -197,7 +198,7 @@ var Connection = function (url, options) { var error = "Version negotiation failed; server requested version " + msg.version; self._stream.disconnect({_permanent: true, _error: error}); - options.onConnectionFailure(error); + options.onDDPVersionNegotiationFailure(msg.version, error); } } else if (_.include(['added', 'changed', 'removed', 'ready', 'updated'], msg.msg)) @@ -1378,8 +1379,8 @@ LivedataTest.Connection = Connection; // "/", // "ddp+sockjs://ddp--****-foo.meteor.com/sockjs" // -DDP.connect = function (url) { - var ret = new Connection(url); +DDP.connect = function (url, options) { + var ret = new Connection(url, options); allConnections.push(ret); // hack. see below. return ret; }; diff --git a/packages/livedata/package.js b/packages/livedata/package.js index f0f7a7e5b2..d8c01f2cab 100644 --- a/packages/livedata/package.js +++ b/packages/livedata/package.js @@ -25,6 +25,8 @@ Package.on_use(function (api) { // If the facts package is loaded, publish some statistics. api.use('facts', 'server', {weak: true}); + api.use('localstorage', 'client'); + api.export('DDP'); api.export('DDPServer', 'server');