From 326e78df719d06eb03681d3b34bc3992e6da803c Mon Sep 17 00:00:00 2001 From: Simon Woolf Date: Fri, 29 Apr 2016 19:25:31 +0100 Subject: [PATCH] Add options.onPageRefresh = persist | close | none To replace recover: true --- common/lib/transport/connectionmanager.js | 24 ++++---- common/lib/util/defaults.js | 13 +++++ spec/browser/connection.test.js | 68 +++++++++++++++++++++++ 3 files changed, 95 insertions(+), 10 deletions(-) diff --git a/common/lib/transport/connectionmanager.js b/common/lib/transport/connectionmanager.js index 33dedd7abf..9028585089 100644 --- a/common/lib/transport/connectionmanager.js +++ b/common/lib/transport/connectionmanager.js @@ -46,19 +46,19 @@ var ConnectionManager = (function() { params.connection_serial = this.connectionSerial; break; case 'recover': - if(options.recover === true) { + if(options.recover) { + var match = options.recover.match(/^(\w+):(\w+)$/); + if(match) { + params.recover = match[1]; + params.connection_serial = match[2]; + } + } else { var connectionKey = readCookie(connectionKeyCookie), connectionSerial = readCookie(connectionSerialCookie); if(connectionKey !== null && connectionSerial !== null) { params.recover = connectionKey; params.connection_serial = connectionSerial; } - } else { - var match = options.recover.match(/^(\w+):(\w+)$/); - if(match) { - params.recover = match[1]; - params.connection_serial = match[2]; - } } break; default: @@ -125,13 +125,17 @@ var ConnectionManager = (function() { throw new Error(msg); } + var self = this; + /* intercept close event in browser to persist connection id if requested */ - if(createCookie && options.recover === true && window.addEventListener) + if(createCookie && options.onPageRefresh === 'persist' && window.addEventListener) window.addEventListener('beforeunload', this.persistConnection.bind(this)); + if(createCookie && options.onPageRefresh === 'close' && window.addEventListener) + window.addEventListener('beforeunload', function() { self.requestState({state: 'closing'}) }); + /* Listen for online and offline events */ if(typeof window === "object" && window.addEventListener) { - var self = this; window.addEventListener('online', function() { if(self.state == self.states.disconnected || self.state == self.states.suspended) { Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager caught browser ‘online’ event', 'reattempting connection'); @@ -170,7 +174,7 @@ var ConnectionManager = (function() { /* set up the transport params */ /* first attempt the main host; no need to check for general connectivity first. * Inherit any connection state */ - var mode = this.connectionKey ? 'resume' : (this.options.recover ? 'recover' : 'clean'); + var mode = this.connectionKey ? 'resume' : ((this.options.onPageRefresh === 'persist') ? 'recover' : 'clean'); var transportParams = new TransportParams(this.options, null, mode, this.connectionKey, this.connectionSerial); Logger.logAction(Logger.LOG_MINOR, 'ConnectionManager.chooseTransport()', 'Transport recovery mode = ' + mode + (mode == 'clean' ? '' : '; connectionKey = ' + this.connectionKey + '; connectionSerial = ' + this.connectionSerial)); var self = this; diff --git a/common/lib/util/defaults.js b/common/lib/util/defaults.js index 6eb6bba2de..95f7e139c0 100644 --- a/common/lib/util/defaults.js +++ b/common/lib/util/defaults.js @@ -62,6 +62,19 @@ Defaults.normaliseOptions = function(options) { options.queueMessages = options.queueEvents; } + if(options.recover === true) { + Logger.deprecated('{recover: true}', '{onPageRefresh: "persist"}'); + options.recover = undefined; + options.onPageRefresh = 'persist'; + } else if(!('onPageRefresh' in options)) { + options.onPageRefresh = 'none'; + } else if(options.onPageRefresh !== 'none' && + options.onPageRefresh !== 'close' && + options.onPageRefresh !== 'persist') { + Logger.logAction(Logger.LOG_ERROR, 'Defaults.normaliseOptions()', options.onPageRefresh.toString() + ' is an invalid value for options.onPageRefresh. Valid values are: "none", "close", or "persist".'); + options.onPageRefresh = 'none'; + } + if(!('queueMessages' in options)) options.queueMessages = true; diff --git a/spec/browser/connection.test.js b/spec/browser/connection.test.js index 46bed45e91..795c8cfbe6 100644 --- a/spec/browser/connection.test.js +++ b/spec/browser/connection.test.js @@ -123,6 +123,74 @@ define(['ably', 'shared_helper'], function(Ably, helper) { }); }; + /* uses internal realtime knowledge of the format of the connection key to + * check if a connection key is the result of a successful recovery of another */ + function sameConnection(keyA, keyB) { + return keyA.split("-")[0] === keyB.split("-")[0]; + } + + exports.page_refresh_with_onpagerefresh_persist = function(test) { + var realtime = helper.AblyRealtime({ onPageRefresh: 'persist' }), + refreshEvent = new Event('beforeunload', {'bubbles': true}); + + test.expect(2); + monitorConnection(test, realtime); + + realtime.connection.once('connected', function() { + var connectionKey = realtime.connection.key; + document.dispatchEvent(refreshEvent); + test.equal(realtime.connection.state, 'connected', 'check connection state initially unaffected by page refresh'); + simulateDroppedConnection(realtime); + + var newRealtime = helper.AblyRealtime({ onPageRefresh: 'persist' }); + newRealtime.connection.once('connected', function() { + test.ok(sameConnection(connectionKey, newRealtime.connection.key), 'Check new realtime recovered the connection from the cookie'); + closeAndFinish(test, [realtime, newRealtime]); + }); + }); + }; + + exports.page_refresh_with_onpagerefresh_close = function(test) { + var realtime = helper.AblyRealtime({ onPageRefresh: 'close' }), + refreshEvent = new Event('beforeunload', {'bubbles': true}); + + test.expect(2); + monitorConnection(test, realtime); + + realtime.connection.once('connected', function() { + var connectionKey = realtime.connection.key; + document.dispatchEvent(refreshEvent); + test.equal(realtime.connection.state, 'closing', 'check page refresh triggered a close'); + + var newRealtime = helper.AblyRealtime({ onPageRefresh: 'persist' }); + newRealtime.connection.once('connected', function() { + test.ok(!sameConnection(connectionKey, newRealtime.connection.key), 'Check new realtime could not recover old even if it tries'); + closeAndFinish(test, [realtime, newRealtime]); + }); + }); + }; + + exports.page_refresh_with_onpagerefresh_none = function(test) { + var realtime = helper.AblyRealtime({ onPageRefresh: 'none' }), + refreshEvent = new Event('beforeunload', {'bubbles': true}); + + test.expect(2); + monitorConnection(test, realtime); + + realtime.connection.once('connected', function() { + var connectionKey = realtime.connection.key; + document.dispatchEvent(refreshEvent); + test.equal(realtime.connection.state, 'connected', 'check connection state initially unaffected by page refresh'); + simulateDroppedConnection(realtime); + + var newRealtime = helper.AblyRealtime({ onPageRefresh: 'persist' }); + newRealtime.connection.once('connected', function() { + test.ok(!sameConnection(connectionKey, newRealtime.connection.key), 'Check new realtime could not recover old even if it tries'); + closeAndFinish(test, [realtime, newRealtime]); + }); + }); + }; + return module.exports = supportedBrowser() ? helper.withTimeout(exports) : {}; });