61 lines
2.2 KiB
JavaScript
61 lines
2.2 KiB
JavaScript
(() => {
|
|
function playbackSession({request, onState, onExpired, onError, interval = 20000, timeout = 8000, retry = 5000}) {
|
|
let session = '', timer = null, pending = null, ended = false;
|
|
function stop() {
|
|
session = '';
|
|
ended = false;
|
|
clearTimeout(timer);
|
|
timer = null;
|
|
const previous = pending;
|
|
pending = null;
|
|
previous?.controller.abort();
|
|
}
|
|
function schedule(delay) {
|
|
clearTimeout(timer);
|
|
if (session && !ended) timer = setTimeout(() => ping(), delay);
|
|
}
|
|
function ping(fresh = false) {
|
|
if (!session || ended) return Promise.resolve(null);
|
|
if (pending && !fresh) return pending.promise;
|
|
if (pending) {
|
|
const previous = pending;
|
|
pending = null;
|
|
previous.controller.abort();
|
|
}
|
|
clearTimeout(timer);
|
|
const call = {session, controller: new AbortController()};
|
|
pending = call;
|
|
call.promise = (async () => {
|
|
let deadline, delay = interval;
|
|
try {
|
|
const expiry = new Promise((_, reject) => {
|
|
deadline = setTimeout(() => {call.controller.abort(); reject(new Error('播放保活请求超时'));}, timeout);
|
|
});
|
|
const state = await Promise.race([Promise.resolve().then(() => request(call.session, call.controller.signal)), expiry]);
|
|
if (pending !== call || session !== call.session) return null;
|
|
onState(state);
|
|
return state;
|
|
} catch (error) {
|
|
if (pending !== call || session !== call.session) return null;
|
|
if (error.status === 410) {
|
|
ended = true;
|
|
onExpired(error);
|
|
} else if (error.status === 401 || error.status === 403) {
|
|
ended = true;
|
|
onError(error);
|
|
} else delay = retry;
|
|
return null;
|
|
} finally {
|
|
clearTimeout(deadline);
|
|
if (pending === call) {pending = null; schedule(delay);}
|
|
}
|
|
})();
|
|
return call.promise;
|
|
}
|
|
function start(id) {stop(); session = id; schedule(interval);}
|
|
return {start, stop, ping};
|
|
}
|
|
if (typeof module === 'object' && module.exports) module.exports = playbackSession;
|
|
else window.JukuPlaybackSession = playbackSession;
|
|
})();
|