Automatically place servers using learned resource capacity
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
let maps = $derived(catalogs[game]);
|
||||
let selectedBlueprint = $derived(blueprints.find(b => b.id === blueprintId));
|
||||
let preview = $state<LaunchPreview | null>(null);
|
||||
let hostSelection = $state<NativeDeploymentSelection>({ hostId: '', libraryIds: {}, image: '' });
|
||||
let hostSelection = $state<NativeDeploymentSelection>({ libraryIds: {}, image: '' });
|
||||
let hostReady = $state(false);
|
||||
let plutoKey = $state('');
|
||||
let busy = $state(false);
|
||||
@@ -55,7 +55,7 @@
|
||||
blueprintId = initialBlueprintId;
|
||||
game = initialGame;
|
||||
mapSlug = initialMapSlug;
|
||||
hostSelection = { hostId: '', libraryIds: {}, image: '' }; hostReady = false;
|
||||
hostSelection = { libraryIds: {}, image: '' }; hostReady = false;
|
||||
try {
|
||||
const [mapRes, blueprintRes] = await Promise.all([fetch('/api/maps'), fetch('/api/blueprints')]);
|
||||
if (!mapRes.ok || !blueprintRes.ok) throw new Error('Could not load maps and collections. Try again.');
|
||||
@@ -76,7 +76,7 @@
|
||||
}
|
||||
|
||||
function selectionChanged() {
|
||||
if (preview) selectionNotice = 'The host or game files changed. Review the launch again with the latest files.';
|
||||
if (preview) selectionNotice = 'The launch settings or game files changed. Review the launch again with the latest files.';
|
||||
preview = null; plutoKey = ''; keyNotice = '';
|
||||
}
|
||||
|
||||
@@ -85,14 +85,14 @@
|
||||
if (!sourceDeploymentId && selectedBlueprint) {
|
||||
open = false; collectionOpen = true; return;
|
||||
}
|
||||
if (!hostReady) { error = 'Choose a host and wait for its latest game files and runtime to finish automatic setup.'; return; }
|
||||
if (!hostReady) { error = 'Wait for a host to finish preparing the latest game files and runtime.'; return; }
|
||||
const current = session;
|
||||
const previousName = preview?.name;
|
||||
busy = true; error = ''; savedName = ''; keyNotice = ''; selectionNotice = '';
|
||||
try {
|
||||
const res = await fetch('/api/provisioning/preview', { method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...(sourceDeploymentId ? { deploymentId: sourceDeploymentId } : { game, mapSlug }),
|
||||
hostId: hostSelection.hostId, libraryId: hostSelection.libraryIds[game], image: hostSelection.image,
|
||||
libraryId: hostSelection.libraryIds[game], image: hostSelection.image,
|
||||
bindAddress: hostSelection.bindAddress || undefined, publicAddress: hostSelection.publicAddress || undefined, publicPort: hostSelection.publicPort }) });
|
||||
const body = await res.json();
|
||||
if (!res.ok) throw new Error(body.error ?? 'Could not prepare launch preview.');
|
||||
@@ -154,13 +154,13 @@
|
||||
<ul>{#each preview.checks as check}<li class:blocked={check.state === 'blocked'}><span class="check" aria-label={check.state}>{check.state === 'pass' ? '✓' : check.state === 'blocked' ? '!' : 'i'}</span><div><strong>{check.label}</strong><p>{check.detail}</p></div></li>{/each}</ul>
|
||||
</section>
|
||||
<form onsubmit={event => { event.preventDefault(); void launch(); }}>
|
||||
<div class="identity"><span class="eyebrow">Your new server</span><strong>{preview.name ?? 'Waiting for an available lobby'}</strong><p>{preview.port ? `Port ${preview.port} · ` : ''}Fresh identity, with its own server key.</p></div>
|
||||
<div class="identity"><span class="eyebrow">Your new server</span><strong>{preview.name ?? 'Waiting for an available lobby'}</strong><p>Fresh identity, with its own server key.</p></div>
|
||||
{#if preview.hasSavedKey}<p class="key-ready"><span aria-hidden="true">✓</span> Saved key ready</p>
|
||||
{:else}<label>Plutonium server key<input type="password" bind:value={plutoKey} disabled={busy || saving || !preview.name} maxlength="512" autocomplete="off" placeholder="Paste the key for this server ID" /></label>{/if}
|
||||
<p class="muted">{preview.hasSavedKey ? 'The saved key for this server ID will be reused automatically. Electric Cherry does not check whether Plutonium accepts it. Update it in Keys.' : 'Add the key here. It is saved for this exact server ID when you launch, including if provisioning fails.'} <a href={`/server-keys?server=${encodeURIComponent(preview.name ?? '')}`} target="_blank" rel="noopener">Manage saved keys in a new tab</a>; your launch stays open here.</p>
|
||||
<div class="launch-actions"><Button variant="ghost" disabled={busy || saving} onclick={() => { preview = null; plutoKey = ''; error = ''; }}>Back</Button><Button type="submit" variant="primary" loading={busy} disabled={busy || saving || expired || !hostReady || !preview.ready || (!preview.hasSavedKey && !plutoKey.trim())}>Launch server</Button></div>
|
||||
{#if !preview.hasSavedKey && !plutoKey.trim()}<p class="muted">Enter this server’s key to enable launch.</p>{/if}
|
||||
<p class="caption">Preview valid until {$timeFormat.minuteTime(preview.expiresAt)}. Lobby and port availability are checked again at launch.</p>
|
||||
<p class="caption">Preview valid until {$timeFormat.minuteTime(preview.expiresAt)}. Capacity is checked again at launch. The host and port are assigned automatically.</p>
|
||||
</form>
|
||||
<details class="save"><summary>Make this a reusable collection</summary><p class="muted">Save this game and map with a target of one lobby. Future launches use the latest promoted setup and create only missing lobbies.</p>
|
||||
{#if savedName}<p class="success" role="status">“{savedName}” is ready in your collection library.</p>{:else}
|
||||
@@ -168,7 +168,7 @@
|
||||
{/if}
|
||||
</details>
|
||||
{:else if sourceDeploymentId}
|
||||
<p class="muted">Choose a host for the latest promoted {game.toUpperCase()} setup, with a fresh lobby and port.</p><Button disabled={busy || !hostReady} onclick={review}>Review launch</Button>
|
||||
<p class="muted">Launch the latest promoted {game.toUpperCase()} setup, with a fresh lobby and port.</p><Button disabled={busy || !hostReady} onclick={review}>Review launch</Button>
|
||||
{:else}
|
||||
<form onsubmit={event => { event.preventDefault(); void review(); }}>
|
||||
<label>Start with<select bind:value={blueprintId} disabled={busy}><option value="">Current promoted setup</option>{#each blueprints as blueprint}<option value={blueprint.id}>{blueprint.name} · {blueprint.totalServers} server{blueprint.totalServers === 1 ? '' : 's'}</option>{/each}</select></label>
|
||||
|
||||
Reference in New Issue
Block a user