mami/src/mami.js/conman.js
flash cf71bab92d Rewrote connection handling.
This has been in the works for over a month and might break things because it's a very radical change.
If it causes you to be unable to join chat, report it on the forum or try joining using the legacy chat on https://sockchat.flashii.net.
2024-04-17 15:42:50 +00:00

134 lines
3.6 KiB
JavaScript

#include awaitable.js
#include utility.js
const MamiConnectionManager = function(client, settings, urls, eventTarget) {
const validateClient = value => {
if(typeof value !== 'object' || value === null)
throw 'client must be a non-null object';
};
validateClient(client);
if(typeof settings !== 'object' || settings === null)
throw 'settings must be a non-null object';
if(!Array.isArray(urls))
throw 'urls must be an array';
if(typeof eventTarget !== 'object' || eventTarget === null)
throw 'eventTarget must be a non-null object';
const delays = [
0,
2000, 2000, 2000, 2000, 2000,
5000, 5000, 5000, 5000, 5000,
10000, 10000, 10000, 10000, 10000,
15000, 30000, 45000, 60000, 120000,
300000
];
let timeout;
let attempts, started, delay, url;
let startResolve;
const resetTimeout = () => {
if(timeout !== undefined) {
clearTimeout(timeout);
timeout = undefined;
}
};
const clear = () => {
resetTimeout();
attempts = started = delay = 0;
url = undefined;
};
$as(urls);
const attempt = () => {
started = Date.now();
url = urls[attempts % urls.length];
if(url.startsWith('//'))
url = location.protocol.replace('http', 'ws') + url;
const attemptNo = attempts + 1;
timeout = setTimeout(() => {
resetTimeout();
(async () => {
if(settings.get('onlyConnectWhenVisible'))
await MamiWaitVisible();
eventTarget.dispatch('attempt', {
url: url,
started: started,
attempt: attemptNo,
});
try {
const result = await client.connect(url);
if(typeof result === 'boolean' && !result)
throw {};
eventTarget.dispatch('success', {
url: url,
started: started,
attempt: attemptNo,
});
startResolve();
startResolve = undefined;
} catch(ex) {
++attempts;
delay = attempts < delays.length ? delays[attempts] : delays[delays.length - 1];
eventTarget.dispatch('fail', {
url: url,
started: started,
attempt: attempts,
delay: delay,
error: ex,
});
attempt();
}
})();
}, delay);
};
const isActive = () => timeout !== undefined || startResolve !== undefined;
return {
get isActive() { return isActive(); },
get client() { return client; },
set client(value) {
validateClient(value);
client = value;
},
start: () => {
return new Promise(resolve => {
if(isActive())
throw 'already attempting to connect';
startResolve = resolve;
clear();
attempt();
});
},
force: () => {
if(!isActive())
return;
resetTimeout();
delay = 0;
attempt();
},
clear: clear,
watch: eventTarget.watch,
unwatch: eventTarget.unwatch,
};
};