Files
lapp/static/item_update_queue.js
T

118 lines
3.0 KiB
JavaScript

(function () {
const STORAGE_KEY = "lapp.pendingItemUpdates";
function readQueue() {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]");
} catch (error) {
return [];
}
}
function writeQueue(queue) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(queue));
}
function queueRequest(request) {
const queue = readQueue();
const queuedRequest = {
url: request.url,
method: request.method || "GET",
coalesceKey: request.coalesceKey || null,
clientUpdatedAt: request.clientUpdatedAt || Date.now()
};
if (queuedRequest.coalesceKey) {
const existingIndex = queue.findIndex(function (item) {
return item.coalesceKey === queuedRequest.coalesceKey;
});
if (existingIndex >= 0) {
queue[existingIndex] = queuedRequest;
} else {
queue.push(queuedRequest);
}
} else {
queue.push(queuedRequest);
}
writeQueue(queue);
}
async function sendRequest(request) {
const url = new URL(request.url, window.location.origin);
if (request.clientUpdatedAt) {
url.searchParams.set("client_updated_at", request.clientUpdatedAt);
}
const response = await fetch(url.toString(), {
method: request.method || "GET",
cache: "no-store",
credentials: "same-origin"
});
if (response.redirected && new URL(response.url).pathname === "/login") {
const error = new Error("Login required");
error.retryable = true;
throw error;
}
if (!response.ok) {
const error = new Error("Request failed: " + response.status);
error.retryable = response.status >= 500 || response.status === 408 || response.status === 429;
throw error;
}
return response;
}
async function queueableItemRequest(url, options) {
const request = Object.assign({}, options || {}, {
url: url,
clientUpdatedAt: Date.now()
});
try {
await sendRequest(request);
flushItemUpdateQueue();
return true;
} catch (error) {
if (error.retryable !== false) {
queueRequest(request);
}
return false;
}
}
async function flushItemUpdateQueue() {
if (flushItemUpdateQueue.running) {
return;
}
flushItemUpdateQueue.running = true;
const queue = readQueue();
const remaining = [];
for (const request of queue) {
try {
await sendRequest(request);
} catch (error) {
if (error.retryable !== false) {
remaining.push(request);
}
}
}
writeQueue(remaining);
flushItemUpdateQueue.running = false;
}
window.lappQueueItemRequest = queueableItemRequest;
window.lappFlushItemUpdateQueue = flushItemUpdateQueue;
window.addEventListener("online", flushItemUpdateQueue);
document.addEventListener("visibilitychange", function () {
if (!document.hidden) {
flushItemUpdateQueue();
}
});
document.addEventListener("DOMContentLoaded", flushItemUpdateQueue);
})();