aboutsummaryrefslogtreecommitdiffstats
path: root/gateway/src/config.js
diff options
context:
space:
mode:
Diffstat (limited to 'gateway/src/config.js')
-rw-r--r--gateway/src/config.js97
1 files changed, 97 insertions, 0 deletions
diff --git a/gateway/src/config.js b/gateway/src/config.js
new file mode 100644
index 0000000..33cad84
--- /dev/null
+++ b/gateway/src/config.js
@@ -0,0 +1,97 @@
+// Loads the same config.toml + .env the Flask dashboard uses (see config.py).
+import { existsSync, readFileSync } from "node:fs";
+import { dirname, resolve } from "node:path";
+import { fileURLToPath } from "node:url";
+import { parse as parseToml } from "smol-toml";
+
+export const ROOT_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
+
+// [section, key, ENV_VAR, type]. Keep in sync with ENV_OVERRIDES in config.py.
+const ENV_OVERRIDES = [
+ ["web", "host", "WEB_HOST", "string"],
+ ["web", "port", "WEB_PORT", "int"],
+ ["web", "dashboard_port", "DASHBOARD_PORT", "int"],
+ ["server", "host", "TS_HOST", "string"],
+ ["server", "webquery_port", "TS_WEBQUERY_PORT", "int"],
+ ["server", "server_id", "TS_SERVER_ID", "string"],
+ ["server", "voice_port", "TS_VOICE_PORT", "int"],
+ ["server", "voice_port", "TS_PORT", "int"], // legacy name from the old .env.template
+ ["server", "ts_domain", "TS_DOMAIN", "string"],
+ ["voice", "enabled", "VOICE_ENABLED", "bool"],
+ ["voice", "trust_proxy", "VOICE_TRUST_PROXY", "bool"],
+];
+
+function envValue(raw, kind) {
+ const value = raw.trim();
+ if (kind === "bool") return ["1", "true", "yes", "on"].includes(value.toLowerCase());
+ if (kind === "int") {
+ if (!/^\d+$/.test(value)) throw new Error("not an integer");
+ return Number(value);
+ }
+ return value;
+}
+
+function toInt(value, fallback, min = 0, max = Number.MAX_SAFE_INTEGER) {
+ const n = Number(value);
+ return Number.isInteger(n) && n >= min && n <= max ? n : fallback;
+}
+
+export function loadConfig(env = process.env) {
+ const envFile = resolve(ROOT_DIR, ".env");
+ // Like python-dotenv's load_dotenv(): existing variables are not overridden.
+ if (env === process.env && existsSync(envFile)) process.loadEnvFile(envFile);
+
+ const configFile = env.TS6_CONFIG_FILE || resolve(ROOT_DIR, "config.toml");
+ let raw = {};
+ if (existsSync(configFile)) raw = parseToml(readFileSync(configFile, "utf8"));
+ else console.warn(`[config] ${configFile} not found, using defaults`);
+
+ const section = (name) => ({ ...(raw[name] ?? {}) });
+ const web = section("web");
+ const server = section("server");
+ const voice = section("voice");
+
+ const sections = { web, server, voice };
+ const applied = new Set();
+ for (const [name, key, envName, kind] of ENV_OVERRIDES) {
+ const value = env[envName];
+ const id = `${name}.${key}`;
+ if (value === undefined || value.trim() === "" || applied.has(id)) continue;
+ try {
+ sections[name][key] = envValue(value, kind);
+ applied.add(id);
+ } catch {
+ console.warn(`[config] ignoring invalid ${envName}=${JSON.stringify(value)}`);
+ }
+ }
+
+ const allowedOrigins = Array.isArray(voice.allowed_origins)
+ ? voice.allowed_origins.filter((o) => typeof o === "string" && o).map((o) => o.replace(/\/+$/, "").toLowerCase())
+ : [];
+
+ return {
+ web: {
+ host: String(web.host ?? "0.0.0.0"),
+ port: toInt(web.port, 5000, 1, 65535),
+ dashboardPort: toInt(web.dashboard_port, 5001, 1, 65535),
+ },
+ server: {
+ host: String(server.host ?? "").trim(),
+ voicePort: toInt(server.voice_port, 9987, 1, 65535),
+ // Secret: only ever read from the environment / .env.
+ password: env.TS_SERVER_PASSWORD ?? "",
+ },
+ voice: {
+ enabled: voice.enabled !== false,
+ maxSessions: toInt(voice.max_sessions, 8, 1, 1000),
+ maxSessionsPerIp: toInt(voice.max_sessions_per_ip, 2, 1, 1000),
+ maxFailedLogins: toInt(voice.max_failed_logins, 5, 1, 1000),
+ lockoutMs: toInt(voice.lockout_minutes, 10, 1, 24 * 60) * 60_000,
+ nicknamePrefix: String(voice.nickname_prefix ?? ""),
+ defaultChannel: String(voice.default_channel ?? ""),
+ identitySecurityLevel: toInt(voice.identity_security_level, 8, 0, 40),
+ trustProxy: voice.trust_proxy === true,
+ allowedOrigins,
+ },
+ };
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage