use a websocket which automatically reconnects if the connection is lost

pull/1/head
Caleb James DeLisle 10 years ago
parent e3a54c11ee
commit 0d3ded68a0

@ -22,6 +22,7 @@
"tweetnacl": "~0.12.2", "tweetnacl": "~0.12.2",
"ckeditor": "~4.4.5", "ckeditor": "~4.4.5",
"requirejs": "~2.1.15", "requirejs": "~2.1.15",
"modalBox": "~1.0.2" "modalBox": "~1.0.2",
"reconnectingWebsocket": ""
} }
} }

@ -649,7 +649,6 @@ var sync = function (realtime) {
}; };
var getMessages = function (realtime) { var getMessages = function (realtime) {
if (realtime.registered === true) { return; }
realtime.registered = true; realtime.registered = true;
/*var to = schedule(realtime, function () { /*var to = schedule(realtime, function () {
throw new Error("failed to connect to the server"); 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 () { start: enterChainPad(realtime, function () {
getMessages(realtime); getMessages(realtime);
if (realtime.syncSchedule) { unschedule(realtime, realtime.syncSchedule); }
realtime.syncSchedule = schedule(realtime, function () { sync(realtime); }); realtime.syncSchedule = schedule(realtime, function () { sync(realtime); });
}), }),
abort: enterChainPad(realtime, function () { abort: enterChainPad(realtime, function () {

@ -13,6 +13,7 @@ define(function () {
out.otherPeople = 'other people'; out.otherPeople = 'other people';
out.disconnected = 'Disconnected'; out.disconnected = 'Disconnected';
out.synchronizing = 'Synchronizing'; out.synchronizing = 'Synchronizing';
out.reconnecting = 'Reconnecting...';
out.lag = 'Lag'; out.lag = 'Lag';
out.initialState = [ out.initialState = [

@ -18,12 +18,13 @@ define([
'html-patcher', 'html-patcher',
'errorbox', 'errorbox',
'messages', 'messages',
'bower/reconnectingWebsocket/reconnecting-websocket',
'rangy', 'rangy',
'chainpad', 'chainpad',
'otaml', 'otaml',
'bower/jquery/dist/jquery.min', 'bower/jquery/dist/jquery.min',
'bower/tweetnacl/nacl-fast.min' 'bower/tweetnacl/nacl-fast.min'
], function (HTMLPatcher, ErrorBox, Messages) { ], function (HTMLPatcher, ErrorBox, Messages, ReconnectingWebSocket) {
window.ErrorBox = ErrorBox; window.ErrorBox = ErrorBox;
@ -129,33 +130,29 @@ window.ErrorBox = ErrorBox;
var updateUserList = function (myUserName, listElement, userList) { var updateUserList = function (myUserName, listElement, userList) {
var meIdx = userList.indexOf(myUserName); var meIdx = userList.indexOf(myUserName);
if (meIdx === -1) { if (meIdx === -1) {
listElement.text(Messages.synchronizing); listElement.textContent = Messages.synchronizing;
return; return;
} }
if (userList.length === 1) { if (userList.length === 1) {
listElement.text(Messages.editingAlone); listElement.textContent = Messages.editingAlone;
} else if (userList.length === 2) { } else if (userList.length === 2) {
listElement.text(Messages.editingWithOneOtherPerson); listElement.textContent = Messages.editingWithOneOtherPerson;
} else { } else {
listElement.text(Messages.editingWith + ' ' + (userList.length - 1) + listElement.textContent = Messages.editingWith + ' ' + (userList.length - 1) +
Messages.otherPeople); Messages.otherPeople;
} }
}; };
var createUserList = function (realtime, myUserName, container) { var createUserList = function (container) {
var id = uid(); var id = uid();
$(container).prepend('<div class="' + USER_LIST_CLS + '" id="'+id+'"></div>'); $(container).prepend('<div class="' + USER_LIST_CLS + '" id="'+id+'"></div>');
var listElement = $('#'+id); return $('#'+id)[0];
realtime.onUserListChange(function (userList) {
updateUserList(myUserName, listElement, userList);
});
return listElement;
}; };
var abort = function (socket, realtime) { var abort = function (socket, realtime) {
realtime.abort(); realtime.abort();
try { socket._socket.close(); } catch (e) { } try { socket._socket.close(); } catch (e) { }
$('.'+USER_LIST_CLS).text("Disconnected"); $('.'+USER_LIST_CLS).text(Messages.disconnected);
$('.'+LAG_ELEM_CLS).text(""); $('.'+LAG_ELEM_CLS).text("");
}; };
@ -300,18 +297,13 @@ window.ErrorBox = ErrorBox;
} else { } else {
lagMsg += lagSec; lagMsg += lagSec;
} }
lagElement.text(lagMsg); lagElement.textContent = lagMsg;
}; };
var createLagElement = function (socket, realtime, container) { var createLagElement = function (container) {
var id = uid(); var id = uid();
$(container).append('<div class="' + LAG_ELEM_CLS + '" id="'+id+'"></div>'); $(container).append('<div class="' + LAG_ELEM_CLS + '" id="'+id+'"></div>');
var lagElement = $('#'+id); return $('#'+id)[0];
var intr = setInterval(function () {
checkLag(realtime, lagElement);
}, 3000);
socket.onClose.push(function () { clearTimeout(intr); });
return lagElement;
}; };
var createSpinner = function (container) { var createSpinner = function (container) {
@ -376,7 +368,7 @@ window.ErrorBox = ErrorBox;
}; };
var makeWebsocket = function (url) { var makeWebsocket = function (url) {
var socket = new WebSocket(url); var socket = new ReconnectingWebSocket(url);
var out = { var out = {
onOpen: [], onOpen: [],
onClose: [], onClose: [],
@ -460,16 +452,12 @@ window.ErrorBox = ErrorBox;
var toolbar = createRealtimeToolbar('#cke_1_toolbox'); var toolbar = createRealtimeToolbar('#cke_1_toolbox');
socket.onClose.push(function () {
$(toolbar).remove();
checkSocket();
});
var allMessages = []; var allMessages = [];
var isErrorState = false; var isErrorState = false;
var initializing = true; var initializing = true;
var recoverableErrorCount = 0; var recoverableErrorCount = 0;
var error = function (recoverable, err) { var error = function (recoverable, err) {
console.log(new Error().stack);
console.log('error: ' + err.stack); console.log('error: ' + err.stack);
if (recoverable && recoverableErrorCount++ < MAX_RECOVERABLE_ERRORS) { return; } if (recoverable && recoverableErrorCount++ < MAX_RECOVERABLE_ERRORS) { return; }
var realtime = socket.realtime; var realtime = socket.realtime;
@ -489,15 +477,19 @@ window.ErrorBox = ErrorBox;
}; };
var checkSocket = function () { var checkSocket = function () {
if (isSocketDisconnected(socket, socket.realtime) && !socket.intentionallyClosing) { if (isSocketDisconnected(socket, socket.realtime) && !socket.intentionallyClosing) {
isErrorState = true; //isErrorState = true;
abort(socket, socket.realtime); //abort(socket, socket.realtime);
ErrorBox.show('disconnected', getDocHTML(doc)); //ErrorBox.show('disconnected', getDocHTML(doc));
return true; return true;
} }
return false; return false;
}; };
socket.onOpen.push(function (evt) { socket.onOpen.push(function (evt) {
if (!initializing) {
socket.realtime.start();
return;
}
var realtime = socket.realtime = var realtime = socket.realtime =
ChainPad.create(userName, ChainPad.create(userName,
@ -508,11 +500,14 @@ window.ErrorBox = ErrorBox;
//createDebugLink(realtime, doc, allMessages, toolbar); //createDebugLink(realtime, doc, allMessages, toolbar);
createUserList(realtime, var userListElement = createUserList(toolbar.find('.rtwysiwyg-toolbar-leftside'));
userName,
toolbar.find('.rtwysiwyg-toolbar-leftside'));
var spinner = createSpinner(toolbar.find('.rtwysiwyg-toolbar-rightside')); 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 () { onEvent = function () {
if (isErrorState) { return; } if (isErrorState) { return; }
@ -552,13 +547,11 @@ window.ErrorBox = ErrorBox;
}; };
realtime.onUserListChange(function (userList) { realtime.onUserListChange(function (userList) {
updateUserList(userName, userListElement, userList);
if (!initializing || userList.indexOf(userName) === -1) { return; } if (!initializing || userList.indexOf(userName) === -1) { return; }
// if we spot ourselves being added to the document, we'll switch // if we spot ourselves being added to the document, we'll switch
// 'initializing' off because it means we're fully synced. // 'initializing' off because it means we're fully synced.
initializing = false; initializing = false;
createLagElement(socket,
realtime,
toolbar.find('.rtwysiwyg-toolbar-rightside'));
incomingPatch(); incomingPatch();
}); });
@ -578,21 +571,19 @@ window.ErrorBox = ErrorBox;
try { try {
socket.send(message); socket.send(message);
} catch (e) { } catch (e) {
if (!checkSocket()) { error(true, e.stack); } error(true, e.stack);
} }
}); });
realtime.onPatch(incomingPatch); realtime.onPatch(incomingPatch);
socket.onError.push(function (err) {
if (isErrorState) { return; }
if (!checkSocket()) { error(true, err); }
});
bindAllEvents(wysiwygDiv, doc.body, onEvent, false); bindAllEvents(wysiwygDiv, doc.body, onEvent, false);
setInterval(function () { setInterval(function () {
if (isErrorState || checkSocket()) { return; } if (isErrorState || checkSocket()) {
userListElement.textContent = Messages.reconnecting;
lagElement.textContent = '';
}
}, 200); }, 200);
realtime.start(); realtime.start();

Loading…
Cancel
Save