feat: Introduce queue based live stat refresh (#1059)
This commit is contained in:
parent
6b93f8ed5c
commit
11257a272e
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",
|
"/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);
|
}, 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) {
|
function readURL(input) {
|
||||||
if (input.files && input.files[0]) {
|
if (input.files && input.files[0]) {
|
||||||
const reader = new FileReader();
|
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/keyBindings.js",
|
||||||
"resources/assets/js/itemExport.js",
|
"resources/assets/js/itemExport.js",
|
||||||
"resources/assets/js/itemImport.js",
|
"resources/assets/js/itemImport.js",
|
||||||
|
"resources/assets/js/liveStatRefresh.js",
|
||||||
],
|
],
|
||||||
"public/js/app.js"
|
"public/js/app.js"
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue