Private
Public Access
1
0

refacto: Keeping entrypoints clean and making files by purpose

This commit is contained in:
gauvainboiche
2026-03-29 13:28:18 +02:00
parent 79cf3ca13e
commit 84af90e81e
13 changed files with 1198 additions and 1167 deletions

128
server/db/gameDb.js Normal file
View File

@@ -0,0 +1,128 @@
import { pool } from "./pools.js";
import { loadConfigFile, getConfig } from "../configLoader.js";
import { computeWorldSeedState } from "../worldSeed.js";
let lastSeedSlot = null;
// ── Schema ────────────────────────────────────────────────────────────────────
export async function initGameSchema() {
await pool.query(`
CREATE TABLE IF NOT EXISTS grid_cells (
id SERIAL PRIMARY KEY,
world_seed TEXT NOT NULL,
x SMALLINT NOT NULL CHECK (x >= 0 AND x < 100),
y SMALLINT NOT NULL CHECK (y >= 0 AND y < 100),
exploitable BOOLEAN NOT NULL,
has_planet BOOLEAN NOT NULL,
planet_json JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (world_seed, x, y)
);
CREATE INDEX IF NOT EXISTS idx_grid_cells_seed ON grid_cells (world_seed);
`);
await pool.query(`
CREATE TABLE IF NOT EXISTS team_cooldowns (
world_seed TEXT NOT NULL,
team TEXT NOT NULL CHECK (team IN ('blue', 'red')),
last_reveal TIMESTAMPTZ,
PRIMARY KEY (world_seed, team)
);
`);
await pool.query(`
ALTER TABLE grid_cells ADD COLUMN IF NOT EXISTS discovered_by TEXT;
UPDATE grid_cells SET discovered_by = 'blue' WHERE discovered_by IS NULL;
ALTER TABLE grid_cells ALTER COLUMN discovered_by SET DEFAULT 'blue';
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'grid_cells_discovered_by_check'
) THEN
ALTER TABLE grid_cells ADD CONSTRAINT grid_cells_discovered_by_check
CHECK (discovered_by IN ('blue', 'red'));
END IF;
END $$;
ALTER TABLE grid_cells ALTER COLUMN discovered_by SET NOT NULL;
`);
}
// ── World-seed epoch ──────────────────────────────────────────────────────────
export async function ensureSeedEpoch() {
loadConfigFile();
const rot = getConfig().databaseWipeoutIntervalSeconds;
const { seedSlot, worldSeed } = computeWorldSeedState(rot);
if (lastSeedSlot === null) {
lastSeedSlot = seedSlot;
return worldSeed;
}
if (seedSlot !== lastSeedSlot) {
await pool.query("TRUNCATE grid_cells RESTART IDENTITY");
await pool.query("DELETE FROM team_cooldowns WHERE world_seed != $1", [worldSeed]);
console.log(`[world] Slot ${lastSeedSlot}${seedSlot}; grid wiped, old cooldowns cleared.`);
lastSeedSlot = seedSlot;
}
return worldSeed;
}
// ── Grid cells ────────────────────────────────────────────────────────────────
export async function getGridCells(worldSeed) {
const { rows } = await pool.query(
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by
FROM grid_cells WHERE world_seed = $1`,
[worldSeed]
);
return rows;
}
export async function insertCell(seed, x, y, exploitable, hasPlanet, planetJson, team) {
const { rows } = await pool.query(
`INSERT INTO grid_cells (world_seed, x, y, exploitable, has_planet, planet_json, discovered_by)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (world_seed, x, y) DO NOTHING
RETURNING x, y, exploitable, has_planet, planet_json, discovered_by`,
[seed, x, y, exploitable, hasPlanet, planetJson, team]
);
return rows[0] ?? null;
}
export async function getExistingCell(seed, x, y) {
const { rows } = await pool.query(
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by
FROM grid_cells WHERE world_seed = $1 AND x = $2 AND y = $3`,
[seed, x, y]
);
return rows[0] ?? null;
}
// ── Team cooldowns ────────────────────────────────────────────────────────────
export async function getTeamCooldown(worldSeed, team) {
const { rows } = await pool.query(
`SELECT last_reveal FROM team_cooldowns WHERE world_seed = $1 AND team = $2`,
[worldSeed, team]
);
return rows[0] ?? null;
}
export async function upsertTeamCooldown(worldSeed, team) {
await pool.query(
`INSERT INTO team_cooldowns (world_seed, team, last_reveal)
VALUES ($1, $2, NOW())
ON CONFLICT (world_seed, team) DO UPDATE SET last_reveal = NOW()`,
[worldSeed, team]
);
}
// ── Scores ────────────────────────────────────────────────────────────────────
export async function getScores(worldSeed) {
const { rows } = await pool.query(
`SELECT discovered_by, COUNT(*) AS cnt
FROM grid_cells WHERE world_seed = $1
GROUP BY discovered_by`,
[worldSeed]
);
return rows;
}

10
server/db/pools.js Normal file
View File

@@ -0,0 +1,10 @@
import pg from "pg";
const DATABASE_URL =
process.env.DATABASE_URL ?? "postgres://game:game@localhost:5432/star_wars_grid";
const USERS_DATABASE_URL =
process.env.USERS_DATABASE_URL ?? "postgres://users:users@localhost:5433/star_wars_users";
export const pool = new pg.Pool({ connectionString: DATABASE_URL });
export const usersPool = new pg.Pool({ connectionString: USERS_DATABASE_URL });

45
server/db/usersDb.js Normal file
View File

@@ -0,0 +1,45 @@
import { usersPool } from "./pools.js";
// ── Schema ────────────────────────────────────────────────────────────────────
export async function initUsersSchema() {
await usersPool.query(`
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
team TEXT NOT NULL CHECK (team IN ('blue', 'red')),
role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('user', 'admin')),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
`);
}
// ── Queries ───────────────────────────────────────────────────────────────────
export async function createUser(username, email, passwordHash, team) {
const { rows } = await usersPool.query(
`INSERT INTO users (username, email, password_hash, team)
VALUES ($1, $2, $3, $4)
RETURNING id, username, email, team, role`,
[username, email, passwordHash, team]
);
return rows[0];
}
export async function getUserByUsername(username) {
const { rows } = await usersPool.query(
`SELECT id, username, email, team, role, password_hash FROM users WHERE username = $1`,
[username]
);
return rows[0] ?? null;
}
export async function getUserById(id) {
const { rows } = await usersPool.query(
`SELECT id, username, email, team, role FROM users WHERE id = $1`,
[id]
);
return rows[0] ?? null;
}