mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:50:42 +00:00
config
This commit is contained in:
Vendored
+1
-1
@@ -22,7 +22,7 @@
|
||||
"${workspaceFolder}/src/server/Server.ts"
|
||||
],
|
||||
"env": {
|
||||
"GAME_ENV": "dev"
|
||||
"GAME_ENV": "Dev"
|
||||
},
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"html.validate.scripts": false
|
||||
}
|
||||
@@ -56,6 +56,11 @@
|
||||
/>
|
||||
<meta property="og:type" content="game" />
|
||||
|
||||
<!-- Server Configuration -->
|
||||
<script>
|
||||
window.SERVER_CONFIG = <%- serverConfig %>;
|
||||
</script>
|
||||
|
||||
<!-- CrazyGames SDK -->
|
||||
<script
|
||||
src="https://sdk.crazygames.com/crazygames-sdk-v3.js"
|
||||
|
||||
-19
@@ -113,25 +113,6 @@ server {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# /api/env endpoint - Cache for 1 hour
|
||||
location = /api/env {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# Cache configuration
|
||||
proxy_cache API_CACHE;
|
||||
proxy_cache_valid 200 1h; # Cache successful responses for 1 hour
|
||||
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
|
||||
proxy_cache_lock on;
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
|
||||
# Standard proxy headers
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# /commit.txt endpoint - Cache for 5 seconds
|
||||
location = /commit.txt {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
|
||||
+4
-4
@@ -5,10 +5,10 @@
|
||||
"build-prod": "concurrently --kill-others-on-fail \"tsc --noEmit\" \"vite build\"",
|
||||
"start:client": "vite",
|
||||
"start:server": "tsx src/server/Server.ts",
|
||||
"start:server-dev": "cross-env GAME_ENV=dev tsx src/server/Server.ts",
|
||||
"dev": "cross-env GAME_ENV=dev concurrently \"npm run start:client\" \"npm run start:server-dev\"",
|
||||
"dev:staging": "cross-env GAME_ENV=dev API_DOMAIN=api.openfront.dev concurrently \"npm run start:client\" \"npm run start:server-dev\"",
|
||||
"dev:prod": "cross-env GAME_ENV=dev API_DOMAIN=api.openfront.io concurrently \"npm run start:client\" \"npm run start:server-dev\"",
|
||||
"start:server-dev": "cross-env GAME_ENV=Dev tsx src/server/Server.ts",
|
||||
"dev": "cross-env GAME_ENV=Dev concurrently \"npm run start:client\" \"npm run start:server-dev\"",
|
||||
"dev:staging": "cross-env GAME_ENV=Dev API_DOMAIN=api.openfront.dev concurrently \"npm run start:client\" \"npm run start:server-dev\"",
|
||||
"dev:prod": "cross-env GAME_ENV=Dev API_DOMAIN=api.openfront.io concurrently \"npm run start:client\" \"npm run start:server-dev\"",
|
||||
"docs:map-generator": "cd map-generator && go doc -cmd -u -all",
|
||||
"tunnel": "npm run build-prod && npm run start:server",
|
||||
"test": "vitest run",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Env } from "src/core/configuration/Env";
|
||||
import { translateText } from "../client/Utils";
|
||||
import { EventBus } from "../core/EventBus";
|
||||
import {
|
||||
@@ -182,8 +183,9 @@ async function createClientGame(
|
||||
if (lobbyConfig.gameStartInfo === undefined) {
|
||||
throw new Error("missing gameStartInfo");
|
||||
}
|
||||
const config = await getConfig(
|
||||
const config = getConfig(
|
||||
lobbyConfig.gameStartInfo.config,
|
||||
Env.GAME_ENV,
|
||||
userSettings,
|
||||
lobbyConfig.gameRecord !== undefined,
|
||||
);
|
||||
@@ -200,6 +202,7 @@ async function createClientGame(
|
||||
}
|
||||
const worker = new WorkerClient(
|
||||
lobbyConfig.gameStartInfo,
|
||||
Env.GAME_ENV,
|
||||
lobbyConfig.clientID,
|
||||
);
|
||||
await worker.initialize();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { copyToClipboard, translateText } from "../client/Utils";
|
||||
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import {
|
||||
Difficulty,
|
||||
Duos,
|
||||
@@ -1156,7 +1156,7 @@ export class HostLobbyModal extends BaseModal {
|
||||
console.log(
|
||||
`Starting private game with map: ${GameMapType[this.selectedMap as keyof typeof GameMapType]} ${this.useRandomMap ? " (Randomly selected)" : ""}`,
|
||||
);
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
const response = await fetch(
|
||||
`${window.location.origin}/${config.workerPath(this.lobbyId)}/api/start_game/${this.lobbyId}`,
|
||||
{
|
||||
@@ -1178,7 +1178,7 @@ export class HostLobbyModal extends BaseModal {
|
||||
}
|
||||
|
||||
private async pollPlayers() {
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
fetch(`/${config.workerPath(this.lobbyId)}/api/game/${this.lobbyId}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
@@ -1231,7 +1231,7 @@ export class HostLobbyModal extends BaseModal {
|
||||
}
|
||||
|
||||
async function createLobby(creatorClientID: string): Promise<GameInfo> {
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
try {
|
||||
const id = generateID();
|
||||
const response = await fetch(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { html, TemplateResult } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators.js";
|
||||
import { Env } from "src/core/configuration/Env";
|
||||
import { copyToClipboard, translateText } from "../client/Utils";
|
||||
import {
|
||||
ClientInfo,
|
||||
@@ -8,7 +9,7 @@ import {
|
||||
GameRecordSchema,
|
||||
} from "../core/Schemas";
|
||||
import { generateID } from "../core/Util";
|
||||
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import { GameMode } from "../core/game/Game";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import { getApiBase } from "./Api";
|
||||
@@ -511,7 +512,7 @@ export class JoinPrivateLobbyModal extends BaseModal {
|
||||
}
|
||||
|
||||
private async checkActiveLobby(lobbyId: string): Promise<boolean> {
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
const url = `/${config.workerPath(lobbyId)}/api/game/${lobbyId}/exists`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
@@ -548,22 +549,12 @@ export class JoinPrivateLobbyModal extends BaseModal {
|
||||
private async checkArchivedGame(
|
||||
lobbyId: string,
|
||||
): Promise<"success" | "not_found" | "version_mismatch" | "error"> {
|
||||
const archivePromise = fetch(`${getApiBase()}/game/${lobbyId}`, {
|
||||
const archiveResponse = await fetch(`${getApiBase()}/game/${lobbyId}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const gitCommitPromise = fetch(`/commit.txt`, {
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
cache: "no-cache",
|
||||
});
|
||||
|
||||
const [archiveResponse, gitCommitResponse] = await Promise.all([
|
||||
archivePromise,
|
||||
gitCommitPromise,
|
||||
]);
|
||||
|
||||
if (archiveResponse.status === 404) {
|
||||
return "not_found";
|
||||
@@ -578,16 +569,7 @@ export class JoinPrivateLobbyModal extends BaseModal {
|
||||
return "version_mismatch";
|
||||
}
|
||||
|
||||
let myGitCommit = "";
|
||||
if (gitCommitResponse.status === 404) {
|
||||
// commit.txt is not found when running locally
|
||||
myGitCommit = "DEV";
|
||||
} else if (gitCommitResponse.status === 200) {
|
||||
myGitCommit = (await gitCommitResponse.text()).trim();
|
||||
} else {
|
||||
console.error("Error getting git commit:", gitCommitResponse.status);
|
||||
return "error";
|
||||
}
|
||||
const myGitCommit = Env.GIT_COMMIT;
|
||||
|
||||
// Allow DEV to join games created with a different version for debugging.
|
||||
if (myGitCommit !== "DEV" && parsed.data.gitCommit !== myGitCommit) {
|
||||
@@ -616,7 +598,7 @@ export class JoinPrivateLobbyModal extends BaseModal {
|
||||
private async pollPlayers() {
|
||||
const lobbyId = this.currentLobbyId;
|
||||
if (!lobbyId) return;
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
|
||||
fetch(`/${config.workerPath(lobbyId)}/api/game/${lobbyId}`, {
|
||||
method: "GET",
|
||||
|
||||
+4
-4
@@ -3,7 +3,7 @@ import { UserMeResponse } from "../core/ApiSchemas";
|
||||
import { EventBus } from "../core/EventBus";
|
||||
import { GameRecord, GameStartInfo, ID } from "../core/Schemas";
|
||||
import { GameEnv } from "../core/configuration/Config";
|
||||
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import { GameType } from "../core/game/Game";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import "./AccountModal";
|
||||
@@ -735,7 +735,7 @@ class Client {
|
||||
this.gameStop();
|
||||
document.body.classList.remove("in-game");
|
||||
}
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
|
||||
const pattern = this.userSettings.getSelectedPatternName(
|
||||
await fetchCosmetics(),
|
||||
@@ -895,7 +895,7 @@ class Client {
|
||||
private async getTurnstileToken(
|
||||
lobby: JoinLobbyEvent,
|
||||
): Promise<string | null> {
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
if (
|
||||
config.env() === GameEnv.Dev ||
|
||||
lobby.gameStartInfo?.config.gameType === GameType.Singleplayer
|
||||
@@ -955,7 +955,7 @@ async function getTurnstileToken(): Promise<{
|
||||
throw new Error("Failed to load Turnstile script");
|
||||
}
|
||||
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
const widgetId = window.turnstile.render("#turnstile-container", {
|
||||
sitekey: config.turnstileSiteKey(),
|
||||
size: "normal",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators.js";
|
||||
import { UserMeResponse } from "../core/ApiSchemas";
|
||||
import { getServerConfigFromClient } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import { generateID } from "../core/Util";
|
||||
import { getUserMe } from "./Api";
|
||||
import { getPlayToken } from "./Auth";
|
||||
@@ -143,7 +143,7 @@ export class MatchmakingModal extends BaseModal {
|
||||
}
|
||||
|
||||
private async connect() {
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
|
||||
this.socket = new WebSocket(`${config.jwtIssuer()}/matchmaking/join`);
|
||||
this.socket.onopen = async () => {
|
||||
@@ -222,7 +222,7 @@ export class MatchmakingModal extends BaseModal {
|
||||
if (this.gameID === null) {
|
||||
return;
|
||||
}
|
||||
const config = await getServerConfigFromClient();
|
||||
const config = getServerConfig();
|
||||
const url = `/${config.workerPath(this.gameID)}/api/game/${this.gameID}/exists`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
|
||||
@@ -31,7 +31,7 @@ export class MultiTabModal extends LitElement implements Layer {
|
||||
if (
|
||||
this.game.inSpawnPhase() ||
|
||||
this.game.config().gameConfig().gameType === GameType.Singleplayer ||
|
||||
this.game.config().serverConfig().env() === GameEnv.Dev
|
||||
this.game.config().env() === GameEnv.Dev
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { placeName } from "../client/graphics/NameBoxCalculator";
|
||||
import { GameEnv } from "./configuration/Config";
|
||||
import { getConfig } from "./configuration/ConfigLoader";
|
||||
import { Executor } from "./execution/ExecutionManager";
|
||||
import { WinCheckExecution } from "./execution/WinCheckExecution";
|
||||
@@ -34,11 +35,12 @@ import { censorNameWithClanTag } from "./validations/username";
|
||||
|
||||
export async function createGameRunner(
|
||||
gameStart: GameStartInfo,
|
||||
env: GameEnv,
|
||||
clientID: ClientID,
|
||||
mapLoader: GameMapLoader,
|
||||
callBack: (gu: GameUpdateViewData | ErrorUpdate) => void,
|
||||
): Promise<GameRunner> {
|
||||
const config = await getConfig(gameStart.config, null);
|
||||
const config = getConfig(gameStart.config, env, null, false);
|
||||
const gameMap = await loadGameMap(
|
||||
gameStart.config.gameMap,
|
||||
gameStart.config.gameMapSize,
|
||||
|
||||
@@ -22,7 +22,7 @@ import { NukeType } from "../StatsSchemas";
|
||||
|
||||
export enum GameEnv {
|
||||
Dev,
|
||||
Preprod,
|
||||
Staging,
|
||||
Prod,
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ export interface NukeMagnitude {
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
env(): GameEnv;
|
||||
spawnImmunityDuration(): Tick;
|
||||
serverConfig(): ServerConfig;
|
||||
gameConfig(): GameConfig;
|
||||
theme(): Theme;
|
||||
percentageTilesOwnedToWin(): number;
|
||||
|
||||
@@ -7,56 +7,34 @@ import { Env } from "./Env";
|
||||
import { preprodConfig } from "./PreprodConfig";
|
||||
import { prodConfig } from "./ProdConfig";
|
||||
|
||||
export let cachedSC: ServerConfig | null = null;
|
||||
|
||||
export async function getConfig(
|
||||
export function getConfig(
|
||||
gameConfig: GameConfig,
|
||||
gameEnv: GameEnv,
|
||||
userSettings: UserSettings | null,
|
||||
isReplay: boolean = false,
|
||||
): Promise<Config> {
|
||||
const sc = await getServerConfigFromClient();
|
||||
switch (sc.env()) {
|
||||
): Config {
|
||||
switch (gameEnv) {
|
||||
case GameEnv.Dev:
|
||||
return new DevConfig(sc, gameConfig, userSettings, isReplay);
|
||||
case GameEnv.Preprod:
|
||||
return new DevConfig(gameConfig, gameEnv, userSettings, isReplay);
|
||||
case GameEnv.Staging:
|
||||
case GameEnv.Prod:
|
||||
console.log("using prod config");
|
||||
return new DefaultConfig(sc, gameConfig, userSettings, isReplay);
|
||||
return new DefaultConfig(gameConfig, gameEnv, userSettings, isReplay);
|
||||
default:
|
||||
throw Error(`unsupported server configuration: ${Env.GAME_ENV}`);
|
||||
}
|
||||
}
|
||||
export async function getServerConfigFromClient(): Promise<ServerConfig> {
|
||||
if (cachedSC) {
|
||||
return cachedSC;
|
||||
}
|
||||
const response = await fetch("/api/env");
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch server config: ${response.status} ${response.statusText}`,
|
||||
);
|
||||
}
|
||||
const config = await response.json();
|
||||
// Log the retrieved configuration
|
||||
console.log("Server config loaded:", config);
|
||||
|
||||
cachedSC = getServerConfig(config.game_env);
|
||||
return cachedSC;
|
||||
}
|
||||
export function getServerConfigFromServer(): ServerConfig {
|
||||
export function getServerConfig(): ServerConfig {
|
||||
const gameEnv = Env.GAME_ENV;
|
||||
return getServerConfig(gameEnv);
|
||||
}
|
||||
export function getServerConfig(gameEnv: string) {
|
||||
switch (gameEnv) {
|
||||
case "dev":
|
||||
case GameEnv.Dev:
|
||||
console.log("using dev server config");
|
||||
return new DevServerConfig();
|
||||
case "staging":
|
||||
case GameEnv.Staging:
|
||||
console.log("using preprod server config");
|
||||
return preprodConfig;
|
||||
case "prod":
|
||||
case GameEnv.Prod:
|
||||
console.log("using prod server config");
|
||||
return prodConfig;
|
||||
default:
|
||||
|
||||
@@ -244,12 +244,16 @@ export class DefaultConfig implements Config {
|
||||
private pastelTheme: PastelTheme = new PastelTheme();
|
||||
private pastelThemeDark: PastelThemeDark = new PastelThemeDark();
|
||||
constructor(
|
||||
private _serverConfig: ServerConfig,
|
||||
private _gameConfig: GameConfig,
|
||||
private _gameEnv: GameEnv,
|
||||
private _userSettings: UserSettings | null,
|
||||
private _isReplay: boolean,
|
||||
) {}
|
||||
|
||||
env(): GameEnv {
|
||||
return this._gameEnv;
|
||||
}
|
||||
|
||||
stripePublishableKey(): string {
|
||||
return Env.STRIPE_PUBLISHABLE_KEY ?? "";
|
||||
}
|
||||
@@ -275,10 +279,6 @@ export class DefaultConfig implements Config {
|
||||
return this._gameConfig;
|
||||
}
|
||||
|
||||
serverConfig(): ServerConfig {
|
||||
return this._serverConfig;
|
||||
}
|
||||
|
||||
userSettings(): UserSettings {
|
||||
if (this._userSettings === null) {
|
||||
throw new Error("userSettings is null");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UserSettings } from "../game/UserSettings";
|
||||
import { GameConfig } from "../Schemas";
|
||||
import { GameEnv, ServerConfig } from "./Config";
|
||||
import { GameEnv } from "./Config";
|
||||
import { DefaultConfig, DefaultServerConfig } from "./DefaultConfig";
|
||||
|
||||
export class DevServerConfig extends DefaultServerConfig {
|
||||
@@ -49,11 +49,11 @@ export class DevServerConfig extends DefaultServerConfig {
|
||||
|
||||
export class DevConfig extends DefaultConfig {
|
||||
constructor(
|
||||
sc: ServerConfig,
|
||||
gc: GameConfig,
|
||||
gameEnv: GameEnv,
|
||||
us: UserSettings | null,
|
||||
isReplay: boolean,
|
||||
) {
|
||||
super(sc, gc, us, isReplay);
|
||||
super(gc, gameEnv, us, isReplay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
* - In Node.js (Server), it uses `process.env`.
|
||||
*/
|
||||
|
||||
import { GameEnv } from "./Config";
|
||||
|
||||
export interface ServerConfigVars {
|
||||
gameEnv: string;
|
||||
numWorkers: number;
|
||||
gitCommit: string;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface ImportMetaEnv {
|
||||
[key: string]: string | boolean | undefined;
|
||||
@@ -11,6 +19,9 @@ declare global {
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
interface Window {
|
||||
SERVER_CONFIG?: ServerConfigVars;
|
||||
}
|
||||
}
|
||||
|
||||
function getEnv(key: string, viteKey?: string): string | undefined {
|
||||
@@ -44,8 +55,32 @@ function getEnv(key: string, viteKey?: string): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Helper function to get GameEnv value case-insensitively
|
||||
function getGameEnvValue(envString: string | undefined): GameEnv {
|
||||
if (!envString) {
|
||||
throw new Error("GAME_ENV is not defined");
|
||||
}
|
||||
|
||||
const normalizedEnv = envString.toLowerCase();
|
||||
const enumKey = Object.keys(GameEnv).find(
|
||||
(key) => key.toLowerCase() === normalizedEnv,
|
||||
);
|
||||
|
||||
return enumKey ? GameEnv[enumKey as keyof typeof GameEnv] : GameEnv.Dev;
|
||||
}
|
||||
|
||||
export const Env = {
|
||||
get GAME_ENV(): string {
|
||||
get GAME_ENV(): GameEnv {
|
||||
// Check window.SERVER_CONFIG first (injected at build time)
|
||||
try {
|
||||
if (typeof window !== "undefined" && window.SERVER_CONFIG) {
|
||||
console.log("using server config from window");
|
||||
return getGameEnvValue(window.SERVER_CONFIG.gameEnv);
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors accessing window
|
||||
}
|
||||
|
||||
// Check MODE for Vite, GAME_ENV for Node
|
||||
try {
|
||||
if (
|
||||
@@ -53,13 +88,14 @@ export const Env = {
|
||||
import.meta.env &&
|
||||
import.meta.env.MODE
|
||||
) {
|
||||
return import.meta.env.MODE;
|
||||
console.log("using server config from import.meta.env");
|
||||
return getGameEnvValue(import.meta.env.MODE);
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors accessing import.meta
|
||||
}
|
||||
|
||||
return getEnv("GAME_ENV") ?? "dev";
|
||||
console.log("using server config from environment variable");
|
||||
return getGameEnvValue(getEnv("GAME_ENV"));
|
||||
},
|
||||
|
||||
get TURNSTILE_SECRET_KEY() {
|
||||
@@ -80,7 +116,14 @@ export const Env = {
|
||||
get OTEL_AUTH_HEADER() {
|
||||
return getEnv("OTEL_AUTH_HEADER");
|
||||
},
|
||||
get GIT_COMMIT() {
|
||||
get GIT_COMMIT(): string | undefined {
|
||||
try {
|
||||
if (typeof window !== "undefined" && window.SERVER_CONFIG) {
|
||||
return window.SERVER_CONFIG.gitCommit;
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors accessing window
|
||||
}
|
||||
return getEnv("GIT_COMMIT");
|
||||
},
|
||||
get API_KEY() {
|
||||
@@ -89,4 +132,16 @@ export const Env = {
|
||||
get ADMIN_TOKEN() {
|
||||
return getEnv("ADMIN_TOKEN");
|
||||
},
|
||||
get NUM_WORKERS() {
|
||||
// Check window.SERVER_CONFIG first (injected at build time)
|
||||
try {
|
||||
if (typeof window !== "undefined" && window.SERVER_CONFIG) {
|
||||
return String(window.SERVER_CONFIG.numWorkers);
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors accessing window
|
||||
}
|
||||
|
||||
return getEnv("NUM_WORKERS");
|
||||
},
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DefaultServerConfig } from "./DefaultConfig";
|
||||
|
||||
export const preprodConfig = new (class extends DefaultServerConfig {
|
||||
env(): GameEnv {
|
||||
return GameEnv.Preprod;
|
||||
return GameEnv.Staging;
|
||||
}
|
||||
numWorkers(): number {
|
||||
return 2;
|
||||
|
||||
@@ -43,6 +43,7 @@ ctx.addEventListener("message", async (e: MessageEvent<MainThreadMessage>) => {
|
||||
try {
|
||||
gameRunner = createGameRunner(
|
||||
message.gameStartInfo,
|
||||
message.env,
|
||||
message.clientID,
|
||||
mapLoader,
|
||||
gameUpdate,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { GameEnv } from "../configuration/Config";
|
||||
import {
|
||||
Cell,
|
||||
PlayerActions,
|
||||
@@ -21,6 +22,7 @@ export class WorkerClient {
|
||||
|
||||
constructor(
|
||||
private gameStartInfo: GameStartInfo,
|
||||
private env: GameEnv,
|
||||
private clientID: ClientID,
|
||||
) {
|
||||
this.worker = new Worker(new URL("./Worker.worker.ts", import.meta.url), {
|
||||
@@ -71,6 +73,7 @@ export class WorkerClient {
|
||||
type: "init",
|
||||
id: messageId,
|
||||
gameStartInfo: this.gameStartInfo,
|
||||
env: this.env,
|
||||
clientID: this.clientID,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { GameEnv } from "../configuration/Config";
|
||||
import {
|
||||
PlayerActions,
|
||||
PlayerBorderTiles,
|
||||
@@ -39,6 +40,7 @@ export interface HeartbeatMessage extends BaseWorkerMessage {
|
||||
export interface InitMessage extends BaseWorkerMessage {
|
||||
type: "init";
|
||||
gameStartInfo: GameStartInfo;
|
||||
env: GameEnv;
|
||||
clientID: ClientID;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import z from "zod";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import {
|
||||
GameID,
|
||||
GameRecord,
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import { replacer } from "../core/Util";
|
||||
import { logger } from "./Logger";
|
||||
|
||||
const config = getServerConfigFromServer();
|
||||
const config = getServerConfig();
|
||||
|
||||
const log = logger.child({ component: "Archive" });
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@ import {
|
||||
import { OpenTelemetryTransportV3 } from "@opentelemetry/winston-transport";
|
||||
import * as dotenv from "dotenv";
|
||||
import winston from "winston";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import { getOtelResource } from "./OtelResource";
|
||||
dotenv.config();
|
||||
|
||||
const config = getServerConfigFromServer();
|
||||
const config = getServerConfig();
|
||||
|
||||
const resource = getOtelResource();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import {
|
||||
Difficulty,
|
||||
Duos,
|
||||
@@ -17,7 +17,7 @@ import { logger } from "./Logger";
|
||||
|
||||
const log = logger.child({});
|
||||
|
||||
const config = getServerConfigFromServer();
|
||||
const config = getServerConfig();
|
||||
|
||||
// How many times each map should appear in the playlist.
|
||||
// Note: The Partial should eventually be removed for better type safety.
|
||||
|
||||
+2
-10
@@ -6,13 +6,13 @@ import http from "http";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { WebSocket, WebSocketServer } from "ws";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import { GameInfo } from "../core/Schemas";
|
||||
import { generateID } from "../core/Util";
|
||||
import { logger } from "./Logger";
|
||||
import { MapPlaylist } from "./MapPlaylist";
|
||||
|
||||
const config = getServerConfigFromServer();
|
||||
const config = getServerConfig();
|
||||
const playlist = new MapPlaylist();
|
||||
const readyWorkers = new Set();
|
||||
|
||||
@@ -203,14 +203,6 @@ export async function startMaster() {
|
||||
});
|
||||
}
|
||||
|
||||
app.get("/api/env", async (req, res) => {
|
||||
const envConfig = {
|
||||
game_env: process.env.GAME_ENV,
|
||||
};
|
||||
if (!envConfig.game_env) return res.sendStatus(500);
|
||||
res.json(envConfig);
|
||||
});
|
||||
|
||||
// Add lobbies endpoint to list public games for this worker
|
||||
app.get("/api/public_lobbies", async (req, res) => {
|
||||
res.json(publicLobbiesData);
|
||||
|
||||
@@ -3,9 +3,9 @@ import {
|
||||
ATTR_SERVICE_NAME,
|
||||
ATTR_SERVICE_VERSION,
|
||||
} from "@opentelemetry/semantic-conventions";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
|
||||
const config = getServerConfigFromServer();
|
||||
const config = getServerConfig();
|
||||
|
||||
export function getOtelResource() {
|
||||
return resourceFromAttributes({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import cluster from "cluster";
|
||||
import * as dotenv from "dotenv";
|
||||
import { getServerConfig } from "src/core/configuration/ConfigLoader";
|
||||
import { startMaster } from "./Master";
|
||||
import { startWorker } from "./Worker";
|
||||
|
||||
@@ -8,6 +9,7 @@ dotenv.config();
|
||||
|
||||
// Main entry point of the application
|
||||
async function main() {
|
||||
getServerConfig();
|
||||
// Check if this is the primary (master) process
|
||||
if (cluster.isPrimary) {
|
||||
console.log("Starting master process...");
|
||||
|
||||
@@ -7,7 +7,7 @@ import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { WebSocket, WebSocketServer } from "ws";
|
||||
import { z } from "zod";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import { GameMapSize, GameType } from "../core/game/Game";
|
||||
import {
|
||||
ClientMessageSchema,
|
||||
@@ -30,7 +30,7 @@ import { PrivilegeRefresher } from "./PrivilegeRefresher";
|
||||
import { verifyTurnstileToken } from "./Turnstile";
|
||||
import { initWorkerMetrics } from "./WorkerMetrics";
|
||||
|
||||
const config = getServerConfigFromServer();
|
||||
const config = getServerConfig();
|
||||
|
||||
const workerId = parseInt(process.env.WORKER_ID ?? "0");
|
||||
const log = logger.child({ comp: `w_${workerId}` });
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
PeriodicExportingMetricReader,
|
||||
} from "@opentelemetry/sdk-metrics";
|
||||
import * as dotenv from "dotenv";
|
||||
import { getServerConfigFromServer } from "../core/configuration/ConfigLoader";
|
||||
import { getServerConfig } from "../core/configuration/ConfigLoader";
|
||||
import { GameManager } from "./GameManager";
|
||||
import { getOtelResource, getPromLabels } from "./OtelResource";
|
||||
|
||||
@@ -12,7 +12,7 @@ dotenv.config();
|
||||
|
||||
export function initWorkerMetrics(gameManager: GameManager): void {
|
||||
// Get server configuration
|
||||
const config = getServerConfigFromServer();
|
||||
const config = getServerConfig();
|
||||
|
||||
// Create resource with worker information
|
||||
const resource = getOtelResource();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Minimal test maps for pathfinding unit tests
|
||||
|
||||
import { GameEnv } from "src/core/configuration/Config";
|
||||
import {
|
||||
Difficulty,
|
||||
Game,
|
||||
@@ -12,7 +13,6 @@ import { createGame as createGameImpl } from "../../../src/core/game/GameImpl";
|
||||
import { GameMapImpl } from "../../../src/core/game/GameMap";
|
||||
import { UserSettings } from "../../../src/core/game/UserSettings";
|
||||
import { TestConfig } from "../../util/TestConfig";
|
||||
import { TestServerConfig } from "../../util/TestServerConfig";
|
||||
|
||||
export const W = "W"; // Water
|
||||
export const L = "L"; // Land
|
||||
@@ -130,7 +130,6 @@ export function createGame(data: TestMapData): Game {
|
||||
miniNumLand,
|
||||
);
|
||||
|
||||
const serverConfig = new TestServerConfig();
|
||||
const gameConfig = {
|
||||
gameMap: GameMapType.Asia,
|
||||
gameMapSize: GameMapSize.Normal,
|
||||
@@ -148,8 +147,8 @@ export function createGame(data: TestMapData): Game {
|
||||
randomSpawn: false,
|
||||
};
|
||||
const config = new TestConfig(
|
||||
serverConfig,
|
||||
gameConfig,
|
||||
GameEnv.Dev,
|
||||
new UserSettings(),
|
||||
false,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "fs";
|
||||
import path, { dirname } from "path";
|
||||
import { GameEnv } from "src/core/configuration/Config";
|
||||
import { fileURLToPath } from "url";
|
||||
import {
|
||||
Difficulty,
|
||||
@@ -248,7 +249,6 @@ export async function setupFromPath(
|
||||
|
||||
// Configure the game
|
||||
const config = new TestConfig(
|
||||
new (await import("../util/TestServerConfig")).TestServerConfig(),
|
||||
{
|
||||
gameMap: GameMapType.Asia,
|
||||
gameMapSize: GameMapSize.Normal,
|
||||
@@ -265,6 +265,7 @@ export async function setupFromPath(
|
||||
randomSpawn: false,
|
||||
...gameConfig,
|
||||
},
|
||||
GameEnv.Dev,
|
||||
new UserSettings(),
|
||||
false,
|
||||
);
|
||||
|
||||
+2
-3
@@ -1,5 +1,6 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { GameEnv } from "src/core/configuration/Config";
|
||||
import {
|
||||
Difficulty,
|
||||
Game,
|
||||
@@ -18,7 +19,6 @@ import {
|
||||
import { UserSettings } from "../../src/core/game/UserSettings";
|
||||
import { GameConfig } from "../../src/core/Schemas";
|
||||
import { TestConfig } from "./TestConfig";
|
||||
import { TestServerConfig } from "./TestServerConfig";
|
||||
|
||||
export async function setup(
|
||||
mapName: string,
|
||||
@@ -54,7 +54,6 @@ export async function setup(
|
||||
const miniGameMap = await genTerrainFromBin(manifest.map4x, miniMapBinBuffer);
|
||||
|
||||
// Configure the game
|
||||
const serverConfig = new TestServerConfig();
|
||||
const gameConfig: GameConfig = {
|
||||
gameMap: GameMapType.Asia,
|
||||
gameMapSize: GameMapSize.Normal,
|
||||
@@ -72,8 +71,8 @@ export async function setup(
|
||||
..._gameConfig,
|
||||
};
|
||||
const config = new ConfigClass(
|
||||
serverConfig,
|
||||
gameConfig,
|
||||
GameEnv.Dev,
|
||||
new UserSettings(),
|
||||
false,
|
||||
);
|
||||
|
||||
+5
-14
@@ -56,7 +56,11 @@ export default defineConfig(({ mode }) => {
|
||||
template: "index.html",
|
||||
inject: {
|
||||
data: {
|
||||
// In case we need to inject variables into HTML
|
||||
serverConfig: JSON.stringify({
|
||||
gameEnv: isProduction ? env.GAME_ENV : "Dev",
|
||||
numWorkers: isProduction ? parseInt(env.NUM_WORKERS, 10) : 2,
|
||||
gitCommit: isProduction ? env.GIT_COMMIT : "DEV",
|
||||
}),
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -71,19 +75,6 @@ export default defineConfig(({ mode }) => {
|
||||
tailwindcss(),
|
||||
],
|
||||
|
||||
define: {
|
||||
"process.env.WEBSOCKET_URL": JSON.stringify(
|
||||
isProduction ? "" : "localhost:3000",
|
||||
),
|
||||
"process.env.GAME_ENV": JSON.stringify(isProduction ? "prod" : "dev"),
|
||||
"process.env.GIT_COMMIT": JSON.stringify(gitCommit),
|
||||
"process.env.STRIPE_PUBLISHABLE_KEY": JSON.stringify(
|
||||
env.STRIPE_PUBLISHABLE_KEY,
|
||||
),
|
||||
"process.env.API_DOMAIN": JSON.stringify(env.API_DOMAIN),
|
||||
// Add other process.env variables if needed, OR migrate code to import.meta.env
|
||||
},
|
||||
|
||||
build: {
|
||||
outDir: "static", // Webpack outputs to 'static', assuming we want to keep this.
|
||||
emptyOutDir: true,
|
||||
|
||||
Reference in New Issue
Block a user