From 0d3ded68a04522bb23dbdc71c1ad04e7f5de0ae2 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 4 Nov 2014 10:51:53 +0100 Subject: [PATCH] use a websocket which automatically reconnects if the connection is lost --- bower.json | 3 +- www/chainpad.js | 2 +- www/messages.js | 1 + www/realtime-wysiwyg.js | 79 ++++++++++++++++++----------------------- 4 files changed, 39 insertions(+), 46 deletions(-) diff --git a/bower.json b/bower.json index c19dc8277..e7f0fc2c4 100644 --- a/bower.json +++ b/bower.json @@ -22,6 +22,7 @@ "tweetnacl": "~0.12.2", "ckeditor": "~4.4.5", "requirejs": "~2.1.15", - "modalBox": "~1.0.2" + "modalBox": "~1.0.2", + "reconnectingWebsocket": "" } } diff --git a/www/chainpad.js b/www/chainpad.js index 9e7909616..82e8102b4 100644 --- a/www/chainpad.js +++ b/www/chainpad.js @@ -649,7 +649,6 @@ var sync = function (realtime) { }; var getMessages = function (realtime) { - if (realtime.registered === true) { return; } realtime.registered = true; /*var to = schedule(realtime, function () { throw new Error("failed to connect to the server"); @@ -1135,6 +1134,7 @@ module.exports.create = function (userName, authToken, channelId, initialState, }), start: enterChainPad(realtime, function () { getMessages(realtime); + if (realtime.syncSchedule) { unschedule(realtime, realtime.syncSchedule); } realtime.syncSchedule = schedule(realtime, function () { sync(realtime); }); }), abort: enterChainPad(realtime, function () { diff --git a/www/messages.js b/www/messages.js index d19124098..1ae8b77e8 100644 --- a/www/messages.js +++ b/www/messages.js @@ -13,6 +13,7 @@ define(function () { out.otherPeople = 'other people'; out.disconnected = 'Disconnected'; out.synchronizing = 'Synchronizing'; + out.reconnecting = 'Reconnecting...'; out.lag = 'Lag'; out.initialState = [ diff --git a/www/realtime-wysiwyg.js b/www/realtime-wysiwyg.js index 16362dd3d..0117fccb9 100644 --- a/www/realtime-wysiwyg.js +++ b/www/realtime-wysiwyg.js @@ -18,12 +18,13 @@ define([ 'html-patcher', 'errorbox', 'messages', + 'bower/reconnectingWebsocket/reconnecting-websocket', 'rangy', 'chainpad', 'otaml', 'bower/jquery/dist/jquery.min', 'bower/tweetnacl/nacl-fast.min' -], function (HTMLPatcher, ErrorBox, Messages) { +], function (HTMLPatcher, ErrorBox, Messages, ReconnectingWebSocket) { window.ErrorBox = ErrorBox; @@ -129,33 +130,29 @@ window.ErrorBox = ErrorBox; var updateUserList = function (myUserName, listElement, userList) { var meIdx = userList.indexOf(myUserName); if (meIdx === -1) { - listElement.text(Messages.synchronizing); + listElement.textContent = Messages.synchronizing; return; } if (userList.length === 1) { - listElement.text(Messages.editingAlone); + listElement.textContent = Messages.editingAlone; } else if (userList.length === 2) { - listElement.text(Messages.editingWithOneOtherPerson); + listElement.textContent = Messages.editingWithOneOtherPerson; } else { - listElement.text(Messages.editingWith + ' ' + (userList.length - 1) + - Messages.otherPeople); + listElement.textContent = Messages.editingWith + ' ' + (userList.length - 1) + + Messages.otherPeople; } }; - var createUserList = function (realtime, myUserName, container) { + var createUserList = function (container) { var id = uid(); $(container).prepend('
'); - var listElement = $('#'+id); - realtime.onUserListChange(function (userList) { - updateUserList(myUserName, listElement, userList); - }); - return listElement; + return $('#'+id)[0]; }; var abort = function (socket, realtime) { realtime.abort(); try { socket._socket.close(); } catch (e) { } - $('.'+USER_LIST_CLS).text("Disconnected"); + $('.'+USER_LIST_CLS).text(Messages.disconnected); $('.'+LAG_ELEM_CLS).text(""); }; @@ -300,18 +297,13 @@ window.ErrorBox = ErrorBox; } else { lagMsg += lagSec; } - lagElement.text(lagMsg); + lagElement.textContent = lagMsg; }; - var createLagElement = function (socket, realtime, container) { + var createLagElement = function (container) { var id = uid(); $(container).append('
'); - var lagElement = $('#'+id); - var intr = setInterval(function () { - checkLag(realtime, lagElement); - }, 3000); - socket.onClose.push(function () { clearTimeout(intr); }); - return lagElement; + return $('#'+id)[0]; }; var createSpinner = function (container) { @@ -376,7 +368,7 @@ window.ErrorBox = ErrorBox; }; var makeWebsocket = function (url) { - var socket = new WebSocket(url); + var socket = new ReconnectingWebSocket(url); var out = { onOpen: [], onClose: [], @@ -460,16 +452,12 @@ window.ErrorBox = ErrorBox; var toolbar = createRealtimeToolbar('#cke_1_toolbox'); - socket.onClose.push(function () { - $(toolbar).remove(); - checkSocket(); - }); - var allMessages = []; var isErrorState = false; var initializing = true; var recoverableErrorCount = 0; var error = function (recoverable, err) { +console.log(new Error().stack); console.log('error: ' + err.stack); if (recoverable && recoverableErrorCount++ < MAX_RECOVERABLE_ERRORS) { return; } var realtime = socket.realtime; @@ -489,15 +477,19 @@ window.ErrorBox = ErrorBox; }; var checkSocket = function () { if (isSocketDisconnected(socket, socket.realtime) && !socket.intentionallyClosing) { - isErrorState = true; - abort(socket, socket.realtime); - ErrorBox.show('disconnected', getDocHTML(doc)); + //isErrorState = true; + //abort(socket, socket.realtime); + //ErrorBox.show('disconnected', getDocHTML(doc)); return true; } return false; }; socket.onOpen.push(function (evt) { + if (!initializing) { + socket.realtime.start(); + return; + } var realtime = socket.realtime = ChainPad.create(userName, @@ -508,11 +500,14 @@ window.ErrorBox = ErrorBox; //createDebugLink(realtime, doc, allMessages, toolbar); - createUserList(realtime, - userName, - toolbar.find('.rtwysiwyg-toolbar-leftside')); - + var userListElement = createUserList(toolbar.find('.rtwysiwyg-toolbar-leftside')); var spinner = createSpinner(toolbar.find('.rtwysiwyg-toolbar-rightside')); + var lagElement = createLagElement(toolbar.find('.rtwysiwyg-toolbar-rightside')); + + setInterval(function () { + if (initializing || isSocketDisconnected(socket, realtime)) { return; } + checkLag(realtime, lagElement); + }, 3000); onEvent = function () { if (isErrorState) { return; } @@ -552,13 +547,11 @@ window.ErrorBox = ErrorBox; }; realtime.onUserListChange(function (userList) { + updateUserList(userName, userListElement, userList); if (!initializing || userList.indexOf(userName) === -1) { return; } // if we spot ourselves being added to the document, we'll switch // 'initializing' off because it means we're fully synced. initializing = false; - createLagElement(socket, - realtime, - toolbar.find('.rtwysiwyg-toolbar-rightside')); incomingPatch(); }); @@ -578,21 +571,19 @@ window.ErrorBox = ErrorBox; try { socket.send(message); } catch (e) { - if (!checkSocket()) { error(true, e.stack); } + error(true, e.stack); } }); realtime.onPatch(incomingPatch); - socket.onError.push(function (err) { - if (isErrorState) { return; } - if (!checkSocket()) { error(true, err); } - }); - bindAllEvents(wysiwygDiv, doc.body, onEvent, false); setInterval(function () { - if (isErrorState || checkSocket()) { return; } + if (isErrorState || checkSocket()) { + userListElement.textContent = Messages.reconnecting; + lagElement.textContent = ''; + } }, 200); realtime.start();