ami/src/ami.js/reconnect.js

221 lines
5.5 KiB
JavaScript

#include utility.js
var AmiReconnecter = function(parent) {
var handler = new AmiReconnectHandler,
indicator = new AmiReconnectIndicator(parent, handler);
return {
isActive: function() {
return handler.isActive();
},
start: function(idleCallback, successCallback, failCallback) {
if(typeof idleCallback !== 'function')
throw 'idleCallback must be a function';
handler.start(
idleCallback,
function(fails) {
indicator.hide();
if(typeof successCallback === 'function')
successCallback(fails);
},
function(fails) {
if(fails > 0) indicator.showCounter();
if(typeof failCallback === 'function')
failCallback(fails);
}
);
},
session: function(body) {
handler.session(body);
},
clear: function() {
handler.clear();
indicator.hide();
},
};
};
var AmiReconnectHandler = function() {
var fails = 0,
delays = undefined,
timeout = undefined;
var idleCallback = undefined,
successCallback = undefined,
failCallback = undefined;
var started = 0,
delay = 0;
var setDefaultDelays = function() {
delays = [0, 10000, 15000, 30000, 45000, 60000, 120000, 300000];
};
var setCustomDelays = function(customDelays) {
delays = customDelays.slice(0);
delays[0] = 0;
};
setDefaultDelays();
var isActive = function() {
return idleCallback !== undefined;
};
var clearAttemptTimeout = function() {
clearTimeout(timeout);
timeout = undefined;
};
var clear = function() {
clearAttemptTimeout();
fails = 0;
idleCallback = undefined;
successCallback = undefined;
failCallback = undefined;
started = 0;
delay = 0;
};
var manager = {
success: function() {
if(successCallback !== undefined)
successCallback(fails);
clear();
},
fail: function() {
++fails;
if(failCallback !== undefined)
failCallback(fails);
attempt();
},
};
var attemptBody = function() {
clearAttemptTimeout();
idleCallback.call(manager, manager, fails, delay);
};
var attempt = function() {
started = Date.now();
delay = fails < delays.length ? delays[fails] : delays[delays.length - 1];
if(delay < 1) attemptBody();
else timeout = setTimeout(attemptBody, delay);
};
return {
isActive: isActive,
session: function(callback) {
callback.call(manager, manager);
},
start: function(idle, success, fail) {
if(typeof idle !== 'function' || isActive())
return;
clear();
idleCallback = idle;
successCallback = success;
failCallback = fail;
attempt();
},
clear: clear,
getTimeRemaining: function() {
return Math.max(0, (started + delay) - Date.now());
},
};
};
var AmiReconnectIndicator = function(parent, handler) {
var counterTime = $e({
tag: 'span',
attrs: {
id: 'reconnectCounterTime',
},
child: '0.0',
});
var counterBody = $e({
attrs: {
id: 'reconnectCounter',
className: 'hidden',
},
child: ['Reconnecting in ', counterTime, ' seconds.'],
});
var connectEllipsis = $e({
tag: 'span',
attrs: {
id: 'reconnectConnectEllipsis',
},
child: '...',
});
var connectBody = $e({
attrs: {
id: 'reconnectConnect',
className: 'hidden',
},
child: ['Attempting to reconnect', connectEllipsis],
});
var body = $e({
attrs: {
id: 'reconnectIndicator',
className: 'hidden',
},
child: [
{ child: 'WARNING: Connection Problem' },
counterBody,
connectBody,
],
});
parent.appendChild(body);
var counterInterval = undefined;
var clearCounterInterval = function() {
clearInterval(counterInterval);
counterInterval = undefined;
};
var setTime = function(time) {
counterTime.textContent = (parseFloat(time || 0) / 1000).toFixed(1);
};
var show = function() {
body.classList.remove('hidden');
};
var showCounter = function() {
clearCounterInterval();
connectBody.classList.add('hidden');
counterBody.classList.remove('hidden');
show();
counterInterval = setInterval(function() {
var remaining = handler.getTimeRemaining();
if(remaining < 100) showConnect();
else setTime(remaining);
}, 100);
};
var showConnect = function() {
clearCounterInterval();
counterBody.classList.add('hidden');
connectBody.classList.remove('hidden');
show();
};
return {
show: show,
hide: function() {
body.classList.add('hidden');
clearCounterInterval();
},
setTime: setTime,
showCounter: showCounter,
showConnect: showConnect,
};
};