Auto-trigger locked-files restoration exactly at the 60s deadline
Previously the restore check only ran lazily on a player's next message, so files could stay wrongly-removed for an arbitrary amount of time after the window expired. The frontend now schedules a setTimeout (using the server-provided deadline, mirroring the terminal lock's reveal timer) that pings the backend right at the deadline so the check runs promptly regardless of player activity. Restored via data-files-removal-deadline on page load too, so a refresh mid-window doesn't lose the timer.
This commit is contained in:
@@ -177,6 +177,42 @@ function applyLock(lockData, apiEchoUrl, messageContainer) {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
let filesRemovalTimer = null;
|
||||
let scheduledFilesRemovalDeadline = null;
|
||||
|
||||
async function pingFilesRemovalDeadline(apiEchoUrl) {
|
||||
if (!apiEchoUrl) return;
|
||||
try {
|
||||
// A no-op message is enough to make the server evaluate the deadline server-side;
|
||||
// the actual restore notice (if any) arrives for everyone via the Mercure broadcast.
|
||||
await fetchJson(apiEchoUrl, {
|
||||
method: 'POST',
|
||||
body: { message: '', ts: new Date().toISOString() },
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('[Game1] Failed to ping files-removal deadline:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleFilesRemovalCheck(deadline, apiEchoUrl) {
|
||||
if (!deadline || scheduledFilesRemovalDeadline === deadline) {
|
||||
return; // nothing to (re)schedule
|
||||
}
|
||||
scheduledFilesRemovalDeadline = deadline;
|
||||
|
||||
if (filesRemovalTimer) {
|
||||
clearTimeout(filesRemovalTimer);
|
||||
filesRemovalTimer = null;
|
||||
}
|
||||
|
||||
const delay = Math.max(0, deadline * 1000 - Date.now());
|
||||
filesRemovalTimer = setTimeout(() => {
|
||||
filesRemovalTimer = null;
|
||||
scheduledFilesRemovalDeadline = null;
|
||||
pingFilesRemovalDeadline(apiEchoUrl);
|
||||
}, delay);
|
||||
}
|
||||
|
||||
async function fetchJson(url, options = {}) {
|
||||
const opts = { ...options };
|
||||
const headers = new Headers(opts.headers || {});
|
||||
@@ -236,6 +272,12 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
const lockLockedAt = cfgEl.dataset.lockLockedAt;
|
||||
const lockRevealAt = cfgEl.dataset.lockRevealAt;
|
||||
const lockUnlockAt = cfgEl.dataset.lockUnlockAt;
|
||||
const filesRemovalDeadline = cfgEl.dataset.filesRemovalDeadline;
|
||||
|
||||
// Resume the auto-restore timer after a page refresh, if a window is already running
|
||||
if (filesRemovalDeadline) {
|
||||
scheduleFilesRemovalCheck(parseInt(filesRemovalDeadline, 10), apiEchoUrl);
|
||||
}
|
||||
|
||||
if (mercurePublicUrl && topic) {
|
||||
subscribeToMercure(mercurePublicUrl, topic, screen);
|
||||
@@ -391,6 +433,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
} else if (response.result.locked === false) {
|
||||
clearLock();
|
||||
}
|
||||
|
||||
if (response.result.filesRemovalDeadline) {
|
||||
scheduleFilesRemovalCheck(response.result.filesRemovalDeadline, apiEchoUrl);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[API][game1] Failed to send message:', err);
|
||||
|
||||
Reference in New Issue
Block a user