diff --git a/src/client/Main.ts b/src/client/Main.ts index 31a2a9ab4..5539e4058 100644 --- a/src/client/Main.ts +++ b/src/client/Main.ts @@ -220,6 +220,17 @@ class Client { ((slider.value - slider.min) / (slider.max - slider.min)) * 100; slider.style.setProperty("--progress", `${percent}%`); } + // Establish minimal WebSocket connection to track homepage view + try { + const ws = new WebSocket(`ws://${location.host}/w0`); + + ws.onopen = () => { + console.log("WebSocket opened: sending homepage_ping"); + ws.send(JSON.stringify({ type: "homepage_ping" })); + }; + } catch (e) { + console.warn("Failed to connect to homepage tracking WebSocket", e); + } document .querySelectorAll("#bots-count, #private-lobby-bots-count") diff --git a/src/server/MapPlaylist.ts b/src/server/MapPlaylist.ts index 5418d9be0..03276aaf4 100644 --- a/src/server/MapPlaylist.ts +++ b/src/server/MapPlaylist.ts @@ -2,6 +2,7 @@ import { getServerConfigFromServer } from "../core/configuration/ConfigLoader"; import { Difficulty, GameMapType, GameMode, GameType } from "../core/game/Game"; import { PseudoRandom } from "../core/PseudoRandom"; import { GameConfig } from "../core/Schemas"; +import { getTotalHomepageViewers } from "./homepagetracker"; import { logger } from "./Logger"; const log = logger.child({}); @@ -41,6 +42,10 @@ export class MapPlaylist { public gameConfig(): GameConfig { const { map, mode } = this.getNextMap(); + const viewerCount = getTotalHomepageViewers(); + log.info( + `Picking map: ${map} | Mode: ${mode} | Homepage viewers: ${viewerCount}`, + ); const numPlayerTeams = mode === GameMode.Team ? 2 + Math.floor(Math.random() * 5) : undefined; diff --git a/src/server/Master.ts b/src/server/Master.ts index bcab69fff..26d9ba67b 100644 --- a/src/server/Master.ts +++ b/src/server/Master.ts @@ -8,13 +8,13 @@ import { getServerConfigFromServer } from "../core/configuration/ConfigLoader"; import { GameInfo } from "../core/Schemas"; import { generateID } from "../core/Util"; import { gatekeeper, LimiterType } from "./Gatekeeper"; +import { setHomepageViewers } from "./homepagetracker"; import { logger } from "./Logger"; import { MapPlaylist } from "./MapPlaylist"; const config = getServerConfigFromServer(); const playlist = new MapPlaylist(); const readyWorkers = new Set(); - const app = express(); const server = http.createServer(app); @@ -111,6 +111,9 @@ export async function startMaster() { ); } } + if (message.type === "HOMEPAGE_VIEW_COUNT") { + setHomepageViewers(message.workerId, message.count); + } }); // Handle worker crashes diff --git a/src/server/Worker.ts b/src/server/Worker.ts index 880dca263..170dff2c3 100644 --- a/src/server/Worker.ts +++ b/src/server/Worker.ts @@ -19,6 +19,7 @@ const config = getServerConfigFromServer(); const workerId = parseInt(process.env.WORKER_ID || "0"); const log = logger.child({ comp: `w_${workerId}` }); +const homepageClients = new Set(); // Worker setup export function startWorker() { @@ -265,6 +266,12 @@ export function startWorker() { // Parse and handle client messages const clientMsg = JSON.parse(message.toString()); + if (clientMsg.type === "homepage_ping") { + homepageClients.add(ws); + sendHomepageCount(); + return; + } + if (clientMsg.type == "join") { // Verify this worker should handle this game const expectedWorkerId = config.workerIndex(clientMsg.gameID); @@ -311,6 +318,12 @@ export function startWorker() { }), ); + // Handle homepage presence tracking + ws.on("close", () => { + homepageClients.delete(ws); + sendHomepageCount(); + }); + ws.on("error", (error: Error) => { if ((error as any).code === "WS_ERR_UNEXPECTED_RSV_1") { ws.close(1002); @@ -347,4 +360,15 @@ export function startWorker() { process.on("unhandledRejection", (reason, promise) => { log.error(`unhandled rejection at:`, promise, "reason:", reason); }); + + function sendHomepageCount() { + const count = homepageClients.size; + if (process.send) { + process.send({ + type: "HOMEPAGE_VIEW_COUNT", + count, + workerId, + }); + } + } } diff --git a/src/server/homepagetracker.ts b/src/server/homepagetracker.ts new file mode 100644 index 000000000..99603b595 --- /dev/null +++ b/src/server/homepagetracker.ts @@ -0,0 +1,13 @@ +const homepageViewersByWorker: Map = new Map(); + +export function setHomepageViewers(workerId: number, count: number) { + homepageViewersByWorker.set(workerId, count); +} + +export function getTotalHomepageViewers(): number { + let total = 0; + for (const count of homepageViewersByWorker.values()) { + total += count; + } + return total; +}