Automatically remove unused game-file versions

This commit is contained in:
2026-10-04 23:05:32 -04:00
parent 9c6d7cc347
commit 725d41c112
15 changed files with 336 additions and 22 deletions
@@ -2,6 +2,7 @@ import { json } from '@sveltejs/kit';
import { heartbeat, pendingCreationCancellations } from '$lib/server/hosts/index.js';
import { authenticateAgent, hostApiError, objectBody } from '$lib/server/hosts/http.js';
import { reconcileHostPreparation } from '$lib/server/hosts/preparation.js';
import { reconcileHostLibraryCleanup, cleanupControllerLibraries } from '$lib/server/game-files/index.js';
export async function POST({ request }: { request: Request }) {
const authenticated = authenticateAgent(request);
try {
@@ -13,6 +14,8 @@ export async function POST({ request }: { request: Request }) {
updateHostLibraryCaches(host.id, inventory.libraryCaches, { snapshot: true });
}
reconcileHostPreparation(host.id);
reconcileHostLibraryCleanup(host.id);
await cleanupControllerLibraries();
return json({ host, cancelledCreations: pendingCreationCancellations(host.id), heartbeatSeconds: 15, serverTime: new Date().toISOString() });
} catch (cause) { return hostApiError(cause); }
}
@@ -7,6 +7,7 @@ export function GET({ request, params }: { request: Request; params: { id: strin
authenticateAgent(request);
const version = getLibraryVersion(params.id);
if (!version || version.state !== 'ready') return json({ error: 'Published library not found.' }, { status: 404 });
if (version.filesRemoved || version.filesRemoving) return json({ error: 'These outdated game files have been removed.' }, { status: 410 });
return json({ id: version.id, game: version.game, files: version.files, sizeBytes: version.sizeBytes, manifestSha256: version.manifestSha256 });
} catch (cause) { return gameFileError(cause); }
}
+3 -2
View File
@@ -276,10 +276,11 @@
{#if history.length}
<details class="history">
<summary>Previous uploads ({history.length})</summary>
<p class="muted">Previous files remain available for servers that already use them.</p>
<p class="muted">Old host copies are removed once no instances use them. Controller files are removed after all host copies are gone; upload history is kept.</p>
{#each history as item (item.id)}
<article class="upload-entry">
<h3>Uploaded {uploadDate(item)}</h3>
{#if item.filesRemoved}<p class="muted">Files removed from controller · upload history retained</p>{:else if item.filesRemoving}<p class="muted">Removing unused controller files · upload history retained</p>{/if}
<p>{formatGameBytes(item.sizeBytes)} · {item.fileCount.toLocaleString()} files</p>
{@render uploadDetails(item)}
<details><summary>Host copies</summary>{@render hostCopies(item, false)}</details>
@@ -309,7 +310,7 @@
</tr>
{:else}<tr><td colspan="4">No host copies yet.</td></tr>{/each}
</tbody></table></div>
{#if canManage}<details><summary>Advanced: download or verify these files</summary><p class="muted">Retry a download or prepare a previous upload on a host. The latest files are downloaded automatically.</p><div class="download"><label>Host<select bind:value={targets[item.id]}><option value="">Select host</option>{#each onlineHosts as host}<option value={host.id}>{host.name} · {formatGameBytes(Number(host.inventory.storageAvailable ?? 0))} free</option>{/each}</select></label><Button size="sm" disabled={busy || !targets[item.id]} onclick={() => download(item.id)}>Download / verify</Button></div></details>{/if}
{#if canManage && !item.filesRemoved && !item.filesRemoving}<details><summary>Advanced: download or verify these files</summary><p class="muted">Retry a download or prepare a previous upload on a host. The latest files are downloaded automatically.</p><div class="download"><label>Host<select bind:value={targets[item.id]}><option value="">Select host</option>{#each onlineHosts as host}<option value={host.id}>{host.name} · {formatGameBytes(Number(host.inventory.storageAvailable ?? 0))} free</option>{/each}</select></label><Button size="sm" disabled={busy || !targets[item.id]} onclick={() => download(item.id)}>Download / verify</Button></div></details>{/if}
{/snippet}
<style>