feat: Introduce queue based live stat refresh (#1059)
This commit is contained in:
parent
6b93f8ed5c
commit
11257a272e
5 changed files with 103 additions and 84 deletions
2
public/js/app.js
vendored
2
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
2
public/mix-manifest.json
generated
2
public/mix-manifest.json
generated
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"/css/app.css": "/css/app.css?id=910562b0b11f9731ff1cdded5e57f7b5",
|
||||
"/js/app.js": "/js/app.js?id=455ff98b9cf4ee09f73e8521270cea96"
|
||||
"/js/app.js": "/js/app.js?id=86f896ef6c2066036a4e2b946e07750d"
|
||||
}
|
||||
|
|
|
@ -19,88 +19,6 @@ $.when($.ready).then(() => {
|
|||
}, 3500);
|
||||
}
|
||||
|
||||
// from https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
|
||||
// Set the name of the hidden property and the change event for visibility
|
||||
let hidden;
|
||||
let visibilityChange;
|
||||
if (typeof document.hidden !== "undefined") {
|
||||
// Opera 12.10 and Firefox 18 and later support
|
||||
hidden = "hidden";
|
||||
visibilityChange = "visibilitychange";
|
||||
} else if (typeof document.msHidden !== "undefined") {
|
||||
hidden = "msHidden";
|
||||
visibilityChange = "msvisibilitychange";
|
||||
} else if (typeof document.webkitHidden !== "undefined") {
|
||||
hidden = "webkitHidden";
|
||||
visibilityChange = "webkitvisibilitychange";
|
||||
}
|
||||
|
||||
const livestatsRefreshTimeouts = [];
|
||||
const livestatsFuncs = [];
|
||||
const livestatsContainers = $(".livestats-container");
|
||||
function stopLivestatsRefresh() {
|
||||
livestatsRefreshTimeouts.forEach((timeoutId) => {
|
||||
window.clearTimeout(timeoutId);
|
||||
});
|
||||
}
|
||||
function startLivestatsRefresh() {
|
||||
livestatsFuncs.forEach((fun) => {
|
||||
fun();
|
||||
});
|
||||
}
|
||||
|
||||
if (livestatsContainers.length > 0) {
|
||||
if (
|
||||
typeof document.addEventListener === "undefined" ||
|
||||
hidden === undefined
|
||||
) {
|
||||
console.log("This browser does not support visibilityChange");
|
||||
} else {
|
||||
document.addEventListener(
|
||||
visibilityChange,
|
||||
() => {
|
||||
if (document[hidden]) {
|
||||
stopLivestatsRefresh();
|
||||
} else {
|
||||
startLivestatsRefresh();
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
livestatsContainers.each(function (index) {
|
||||
const id = $(this).data("id");
|
||||
const dataonly = $(this).data("dataonly");
|
||||
const increaseby = dataonly === 1 ? 20000 : 1000;
|
||||
const container = $(this);
|
||||
const maxTimer = 30000;
|
||||
let timer = 5000;
|
||||
const fun = function worker() {
|
||||
$.ajax({
|
||||
url: `${base}get_stats/${id}`,
|
||||
dataType: "json",
|
||||
success(data) {
|
||||
container.html(data.html);
|
||||
if (data.status === "active") timer = increaseby;
|
||||
else if (timer < maxTimer) timer += 2000;
|
||||
},
|
||||
complete(jqXHR) {
|
||||
if (jqXHR.status > 299) {
|
||||
// Stop polling when we get errors
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule the next request when the current one's complete
|
||||
livestatsRefreshTimeouts[index] = window.setTimeout(worker, timer);
|
||||
},
|
||||
});
|
||||
};
|
||||
livestatsFuncs[index] = fun;
|
||||
fun();
|
||||
});
|
||||
}
|
||||
|
||||
function readURL(input) {
|
||||
if (input.files && input.files[0]) {
|
||||
const reader = new FileReader();
|
||||
|
|
100
resources/assets/js/liveStatRefresh.js
vendored
Normal file
100
resources/assets/js/liveStatRefresh.js
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
const REFRESH_INTERVAL_SMALL = 5000;
|
||||
const REFRESH_INTERVAL_BIG = 30000;
|
||||
const QUEUE_PROCESSING_INTERVAL = 1000;
|
||||
const CONTAINER_SELECTOR = ".livestats-container";
|
||||
|
||||
/**
|
||||
* @returns {*[]}
|
||||
*/
|
||||
function createQueue() {
|
||||
const queue = [];
|
||||
let suspended = false;
|
||||
|
||||
function processQueue() {
|
||||
if (queue.length === 0 || suspended === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
const next = queue.shift();
|
||||
next();
|
||||
}
|
||||
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
suspended = document.hidden;
|
||||
});
|
||||
|
||||
setInterval(processQueue, QUEUE_PROCESSING_INTERVAL);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {NodeListOf<Element>}
|
||||
*/
|
||||
function getContainers() {
|
||||
return document.querySelectorAll(CONTAINER_SELECTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {boolean} dataOnly
|
||||
* @param {boolean} active
|
||||
* @returns {number}
|
||||
*/
|
||||
function getQueueInterval(dataOnly, active) {
|
||||
if (dataOnly) {
|
||||
return REFRESH_INTERVAL_BIG;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
return REFRESH_INTERVAL_SMALL;
|
||||
}
|
||||
|
||||
return REFRESH_INTERVAL_BIG;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} container
|
||||
* @param {array} queue
|
||||
* @returns {function(): Promise<Response>}
|
||||
*/
|
||||
function createUpdateJob(container, queue) {
|
||||
const id = container.getAttribute("data-id");
|
||||
// Data only attribute seems to indicate that the item should not be updated that often
|
||||
const isDataOnly = container.getAttribute("data-dataonly") === "1";
|
||||
|
||||
return () =>
|
||||
fetch(`get_stats/${id}`)
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
throw new Error(`Network response was not ok: ${response.status}`);
|
||||
})
|
||||
.then((data) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
container.innerHTML = data.html;
|
||||
|
||||
const isActive = data.status === "active";
|
||||
|
||||
if (queue) {
|
||||
setTimeout(() => {
|
||||
queue.push(createUpdateJob(container, queue));
|
||||
}, getQueueInterval(isDataOnly, isActive));
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
const livestatContainers = getContainers();
|
||||
|
||||
if (livestatContainers.length > 0) {
|
||||
const myQueue = createQueue();
|
||||
|
||||
livestatContainers.forEach((container) => {
|
||||
createUpdateJob(container, myQueue)();
|
||||
});
|
||||
}
|
1
webpack.mix.js
vendored
1
webpack.mix.js
vendored
|
@ -20,6 +20,7 @@ mix
|
|||
"resources/assets/js/keyBindings.js",
|
||||
"resources/assets/js/itemExport.js",
|
||||
"resources/assets/js/itemImport.js",
|
||||
"resources/assets/js/liveStatRefresh.js",
|
||||
],
|
||||
"public/js/app.js"
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue