You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
4.4 KiB
200 lines
4.4 KiB
6 years ago
|
(function () {
|
||
|
|
||
|
var socket, attempts, attemptTimer, pingTimer;
|
||
|
|
||
|
window.send = function (msg) {
|
||
|
// need deferral or reporting on these lost messages...
|
||
|
if (connSM.state != 'synced' && connSM.state != 'syncing')
|
||
|
return;
|
||
|
if (socket.readyState != SockJS.OPEN) {
|
||
|
if (console)
|
||
|
console.warn("Attempting to send while socket closed");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
msg = JSON.stringify(msg);
|
||
|
if (DEBUG)
|
||
|
console.log('<', msg);
|
||
|
socket.send(msg);
|
||
|
};
|
||
|
|
||
|
var pong = '[[0,' + PING + ']]';
|
||
|
|
||
|
function on_message(e) {
|
||
|
if (e == pong)
|
||
|
return;
|
||
|
if (DEBUG)
|
||
|
console.log('>', e.data);
|
||
|
var msgs = JSON.parse(e.data);
|
||
|
|
||
|
with_dom(function () {
|
||
|
|
||
|
for (var i = 0; i < msgs.length; i++) {
|
||
|
var msg = msgs[i];
|
||
|
var op = msg.shift();
|
||
|
var type = msg.shift();
|
||
|
if (is_pubsub(type) && op in syncs)
|
||
|
syncs[op]++;
|
||
|
dispatcher[type](msg, op);
|
||
|
}
|
||
|
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function sync_status(msg, hover) {
|
||
|
$('#sync').text(msg).attr('class', hover ? 'error' : '');
|
||
|
}
|
||
|
|
||
|
connSM.act('load + start -> conn', function () {
|
||
|
sync_status('Connecting...', false);
|
||
|
attempts = 0;
|
||
|
connect();
|
||
|
});
|
||
|
|
||
|
function connect() {
|
||
|
if (socket) {
|
||
|
socket.onclose = null;
|
||
|
socket.onmessage = null;
|
||
|
}
|
||
|
if (window.location.protocol == 'file:') {
|
||
|
console.log("Page downloaded locally; refusing to sync.");
|
||
|
return;
|
||
|
}
|
||
|
socket = window.new_socket(attempts);
|
||
|
socket.onopen = connSM.feeder('open');
|
||
|
socket.onclose = connSM.feeder('close');
|
||
|
socket.onmessage = on_message;
|
||
|
if (DEBUG)
|
||
|
window.socket = socket;
|
||
|
}
|
||
|
|
||
|
window.new_socket = function (attempt) {
|
||
|
var protocols = ['xdr-streaming', 'xhr-streaming', 'iframe-eventsource', 'iframe-htmlfile', 'xdr-polling', 'xhr-polling', 'iframe-xhr-polling', 'jsonp-polling'];
|
||
|
if (config.USE_WEBSOCKETS)
|
||
|
protocols.unshift('websocket');
|
||
|
var url = SOCKET_PATH;
|
||
|
if (typeof ctoken != 'undefined') {
|
||
|
url += '?' + $.param({ctoken: ctoken});
|
||
|
}
|
||
|
return new SockJS(url, null, {
|
||
|
transports: protocols,
|
||
|
});
|
||
|
};
|
||
|
|
||
|
connSM.act('conn, reconn + open -> syncing', function () {
|
||
|
sync_status('Syncing...', false);
|
||
|
CONN_ID = random_id();
|
||
|
send([SYNCHRONIZE, CONN_ID, BOARD, syncs, BUMP, document.cookie]);
|
||
|
if (pingTimer)
|
||
|
clearInterval(pingTimer);
|
||
|
pingTimer = setInterval(ping, 25000);
|
||
|
});
|
||
|
|
||
|
connSM.act('syncing + sync -> synced', function () {
|
||
|
sync_status('Synced.', false);
|
||
|
attemptTimer = setTimeout(function () {
|
||
|
attemptTimer = 0;
|
||
|
reset_attempts();
|
||
|
}, 10000);
|
||
|
});
|
||
|
|
||
|
function reset_attempts() {
|
||
|
if (attemptTimer) {
|
||
|
clearTimeout(attemptTimer);
|
||
|
attemptTimer = 0;
|
||
|
}
|
||
|
attempts = 0;
|
||
|
}
|
||
|
|
||
|
connSM.act('* + close -> dropped', function (e) {
|
||
|
if (socket) {
|
||
|
socket.onclose = null;
|
||
|
socket.onmessage = null;
|
||
|
}
|
||
|
if (DEBUG)
|
||
|
console.error('E:', e);
|
||
|
if (attemptTimer) {
|
||
|
clearTimeout(attemptTimer);
|
||
|
attemptTimer = 0;
|
||
|
}
|
||
|
if (pingTimer) {
|
||
|
clearInterval(pingTimer);
|
||
|
pingTimer = 0;
|
||
|
}
|
||
|
sync_status('Dropped.', true);
|
||
|
|
||
|
attempts++;
|
||
|
var n = Math.min(Math.floor(attempts/2), 12);
|
||
|
var wait = 500 * Math.pow(1.5, n);
|
||
|
// wait maxes out at ~1min
|
||
|
setTimeout(connSM.feeder('retry'), wait);
|
||
|
});
|
||
|
|
||
|
connSM.act('dropped + retry -> reconn', function () {
|
||
|
connect();
|
||
|
/* Don't show this immediately so we don't thrash on network loss */
|
||
|
setTimeout(function () {
|
||
|
if (connSM.state == 'reconn')
|
||
|
sync_status('Reconnecting...', true);
|
||
|
}, 100);
|
||
|
});
|
||
|
|
||
|
connSM.act('* + invalid, desynced + close -> desynced', function (msg) {
|
||
|
msg = (msg && msg[0]) ? 'Out of sync: ' + msg[0] : 'Out of sync.';
|
||
|
sync_status(msg, true);
|
||
|
if (attemptTimer) {
|
||
|
clearTimeout(attemptTimer);
|
||
|
attemptTimer = 0;
|
||
|
}
|
||
|
socket.onclose = null;
|
||
|
socket.onmessage = null;
|
||
|
socket.close();
|
||
|
socket = null;
|
||
|
if (DEBUG)
|
||
|
window.socket = null;
|
||
|
});
|
||
|
|
||
|
function window_focused() {
|
||
|
var s = connSM.state;
|
||
|
if (s == 'desynced')
|
||
|
return;
|
||
|
// might have just been suspended;
|
||
|
// try to get our SM up to date if possible
|
||
|
if (s == 'synced' || s == 'syncing' || s == 'conn') {
|
||
|
var rs = socket.readyState;
|
||
|
if (rs != SockJS.OPEN && rs != SockJS.CONNECTING) {
|
||
|
connSM.feed('close');
|
||
|
return;
|
||
|
}
|
||
|
else if (navigator.onLine === false) {
|
||
|
connSM.feed('close');
|
||
|
return;
|
||
|
}
|
||
|
ping();
|
||
|
}
|
||
|
connSM.feed('retry');
|
||
|
}
|
||
|
|
||
|
function ping() {
|
||
|
if (socket.readyState == SockJS.OPEN)
|
||
|
socket.send('['+PING+']');
|
||
|
else if (pingTimer) {
|
||
|
clearInterval(pingTimer);
|
||
|
pingTimer = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
(function () {
|
||
|
_.defer(connSM.feeder('start'));
|
||
|
$(window).focus(function () {
|
||
|
setTimeout(window_focused, 20);
|
||
|
});
|
||
|
window.addEventListener('online', function () {
|
||
|
reset_attempts();
|
||
|
connSM.feed('retry');
|
||
|
});
|
||
|
window.addEventListener('offline', connSM.feeder('close'));
|
||
|
})();
|
||
|
|
||
|
})();
|