Persist Plutonium keys by server ID and add key management
This commit is contained in:
@@ -2,6 +2,7 @@ import { mkdir, chmod, rm, writeFile } from 'node:fs/promises';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { config, destOfKind } from '../config.js';
|
||||
import { db } from '../db/index.js';
|
||||
import { getServerKey, saveServerKey } from './server-keys.js';
|
||||
import { getServer } from './servers.js';
|
||||
import { t5ZombieMapBySlug, type GameMode } from './map-aliases.js';
|
||||
import {
|
||||
@@ -26,6 +27,7 @@ const T5_ZOMBIE_CONFIG_FILE = config.configTargetFile;
|
||||
const T5_ZOMBIE_GAME_ID = 't5sp';
|
||||
|
||||
export type CreateServerFailure =
|
||||
| 'bad-request'
|
||||
| 'unconfigured' // Komodo creds / target server missing
|
||||
| 'unknown-map' // slug isn't in the catalog
|
||||
| 'no-slot' // all lobby slots for this map are taken
|
||||
@@ -45,7 +47,8 @@ export type DestroyServerResult =
|
||||
export interface CreateServerInput {
|
||||
gameMode: GameMode; // 'zombie' — only value supported today
|
||||
mapSlug: string; // 'cosmodrome'
|
||||
plutoKey: string; // required; never persisted
|
||||
plutoKey?: string; // saved for this server ID when supplied
|
||||
lobby?: number; // explicit stable identity; otherwise first available
|
||||
createdBy?: string; // 'ui' by default
|
||||
}
|
||||
|
||||
@@ -132,7 +135,15 @@ function buildSpec(args: {
|
||||
};
|
||||
}
|
||||
|
||||
let creating = false;
|
||||
export async function createServer(input: CreateServerInput): Promise<CreateServerResult> {
|
||||
if (creating) return { ok: false, kind: 'no-slot', message: 'Another server is being created. Please retry shortly.' };
|
||||
creating = true;
|
||||
try { return await createServerUnlocked(input); }
|
||||
finally { creating = false; }
|
||||
}
|
||||
|
||||
async function createServerUnlocked(input: CreateServerInput): Promise<CreateServerResult> {
|
||||
if (input.gameMode !== 'zombie') {
|
||||
return { ok: false, kind: 'unknown-map', message: `unsupported game mode: ${input.gameMode}` };
|
||||
}
|
||||
@@ -149,11 +160,17 @@ export async function createServer(input: CreateServerInput): Promise<CreateServ
|
||||
}
|
||||
|
||||
const baseName = `t5_${input.gameMode}_${mapEntry.slug}`;
|
||||
const lobby = nextLobbyNumber(baseName);
|
||||
if (input.lobby !== undefined && (!Number.isInteger(input.lobby) || input.lobby < 1 || input.lobby > 20)) {
|
||||
return { ok: false, kind: 'bad-request', message: 'Lobby must be an integer from 1 to 20' };
|
||||
}
|
||||
const lobby = input.lobby ?? nextLobbyNumber(baseName);
|
||||
if (lobby === null) {
|
||||
return { ok: false, kind: 'no-slot', message: `all lobby slots (1..20) for ${baseName} are taken` };
|
||||
}
|
||||
const name = `${baseName}_${lobby}`;
|
||||
if (getServer(name)) return { ok: false, kind: 'no-slot', message: `${name} is already deployed` };
|
||||
const plutoKey = input.plutoKey?.trim() || getServerKey(name);
|
||||
if (!plutoKey) return { ok: false, kind: 'bad-request', message: `No saved key for ${name}. Enter a Plutonium server key.` };
|
||||
|
||||
const port = nextAvailablePort();
|
||||
if (port === null) {
|
||||
@@ -164,6 +181,10 @@ export async function createServer(input: CreateServerInput): Promise<CreateServ
|
||||
};
|
||||
}
|
||||
|
||||
// Save before external operations so a failed deployment can also be retried.
|
||||
try { saveServerKey(name, plutoKey); }
|
||||
catch (err) { return { ok: false, kind: 'bad-request', message: (err as Error).message }; }
|
||||
|
||||
const hostDir = `${config.serversRoot}/${name}`;
|
||||
const initialConfig = getPromotedServerConfig('t5', mapEntry.canonical);
|
||||
const mapConfig = getServerMapConfig('t5', mapEntry.canonical)!;
|
||||
@@ -190,7 +211,7 @@ export async function createServer(input: CreateServerInput): Promise<CreateServ
|
||||
}
|
||||
|
||||
// Step 2: Komodo CreateDeployment.
|
||||
const spec = buildSpec({ name, port, hostDir, plutoKey: input.plutoKey });
|
||||
const spec = buildSpec({ name, port, hostDir, plutoKey });
|
||||
const createRes = await komodoCreateDeployment(spec);
|
||||
if (!createRes.ok) {
|
||||
await rm(hostDir, { recursive: true, force: true }).catch(() => {});
|
||||
|
||||
Reference in New Issue
Block a user