add server settings store

This commit is contained in:
Nystik
2026-06-06 01:16:01 +02:00
parent 3129ed377c
commit 938a698795
4 changed files with 104 additions and 17 deletions

View File

@@ -75,16 +75,6 @@ module.exports = {
vaults = discoverVaults();
return vaults;
},
writeCoalesceMs:
process.env.WRITE_COALESCE_MS !== undefined
? parseInt(process.env.WRITE_COALESCE_MS)
: 5000,
wsOrigins: process.env.WS_ORIGINS
? process.env.WS_ORIGINS.split(",")
.map((s) => s.trim())
.filter(Boolean)
: null,
demoMode: process.env.DEMO_MODE === "true",
demoMaxSessions: parseInt(process.env.DEMO_MAX_SESSIONS) || 20,

View File

@@ -3,6 +3,7 @@ const fs = require("fs");
const path = require("path");
const compression = require("compression");
const config = require("./config");
const settings = require("./settings");
const { getVersion } = require("./version");
const {
setupWebSocket,
@@ -19,7 +20,7 @@ const {
getBundledPluginDirs,
} = require("./plugin-system/manager");
const pluginRoutes = require("./routes/plugins");
writeCoalescer.configure({ writeCoalesceMs: config.writeCoalesceMs });
writeCoalescer.configure({ writeCoalesceMs: settings.get("writeCoalesceMs") });
const { flushAll } = writeCoalescer;
const { setupDemo, wireDemoWebSocket } = require("./demo");
@@ -197,7 +198,7 @@ const server = app.listen(config.port, async () => {
const wss = setupWebSocket(server, {
getVaultPath: config.getVaultPath,
originAllowlist: config.wsOrigins,
originAllowlist: settings.get("wsOrigins"),
});
wireDemoWebSocket(server);

View File

@@ -0,0 +1,91 @@
const fs = require("fs");
const path = require("path");
const config = require("./config");
// Runtime server settings set through UI.
const SETTINGS_FILE = path.join(config.dataRoot, "server-settings.json");
const DEFAULTS = {
contentCacheBytes: 50 * 1024 * 1024,
inputCacheBytes: 200 * 1024 * 1024,
inputCacheTtlMs: 5 * 60 * 1000,
writeCoalesceMs: 5000,
maxBodyBytes: 50 * 1024 * 1024,
// Empty arrays mean "no restriction": any proxy host, any WS origin.
proxyAllowlist: [],
wsOrigins: [],
};
const KEYS = Object.keys(DEFAULTS);
function parseList(raw) {
return raw
.split(",")
.map((s) => s.trim())
.filter(Boolean);
}
function fromEnv() {
const env = {};
if (process.env.WRITE_COALESCE_MS !== undefined) {
const n = parseInt(process.env.WRITE_COALESCE_MS, 10);
if (Number.isFinite(n)) {
env.writeCoalesceMs = n;
}
}
if (process.env.WS_ORIGINS) {
env.wsOrigins = parseList(process.env.WS_ORIGINS);
}
return env;
}
const envOverrides = fromEnv();
function loadFile() {
try {
const parsed = JSON.parse(fs.readFileSync(SETTINGS_FILE, "utf-8"));
// Keep only known keys so a stale or hand-edited file can't inject junk.
const clean = {};
for (const key of KEYS) {
if (parsed[key] !== undefined) {
clean[key] = parsed[key];
}
}
return clean;
} catch {
return {};
}
}
let fileOverrides = loadFile();
function getAll() {
return { ...DEFAULTS, ...envOverrides, ...fileOverrides };
}
function get(key) {
return getAll()[key];
}
// Merge validated changes into the persisted file and return the new effective settings.
function update(partial) {
for (const [key, value] of Object.entries(partial)) {
if (KEYS.includes(key)) {
fileOverrides[key] = value;
}
}
fs.mkdirSync(path.dirname(SETTINGS_FILE), { recursive: true });
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(fileOverrides, null, 2));
return getAll();
}
module.exports = { DEFAULTS, KEYS, getAll, get, update };

View File

@@ -2,6 +2,11 @@ const { WebSocketServer } = require("ws");
const url = require("url");
const watcher = require("./watcher");
// Null / undefined / empty array means no Origin check.
function toOriginSet(list) {
return Array.isArray(list) && list.length > 0 ? new Set(list) : null;
}
function setupWebSocket(server, opts = {}) {
const { getVaultPath, originAllowlist } = opts;
@@ -9,14 +14,14 @@ function setupWebSocket(server, opts = {}) {
throw new Error("setupWebSocket: opts.getVaultPath is required");
}
// Null / undefined / empty array = no Origin check.
const originSet =
Array.isArray(originAllowlist) && originAllowlist.length > 0
? new Set(originAllowlist)
: null;
let originSet = toOriginSet(originAllowlist);
const wss = new WebSocketServer({ server, path: "/ws" });
wss.setOriginAllowlist = function (list) {
originSet = toOriginSet(list);
};
// Global message handlers: type -> handler(msg, ws).
wss.messageHandlers = new Map();