mirror of
https://github.com/YuzuZensai/Termix.git
synced 2026-09-14 02:59:06 +00:00
190 lines
5.5 KiB
TypeScript
190 lines
5.5 KiB
TypeScript
import type { Express, RequestHandler } from "express";
|
|||
|
|
import { getDb } from "../database/db/index.js";
|
||
|
|
import { statsLogger } from "../utils/logger.js";
|
||
|
|
|
||
|
|
type ServerStatsSettingsConfig = {
|
||
|
|
statusCheckInterval: number;
|
||
|
|
metricsInterval: number;
|
||
|
|
};
|
||
|
|
|
||
|
|
type ServerStatsSettingsRoutesDeps = {
|
||
|
|
requireAdmin: RequestHandler;
|
||
|
|
defaultStatsConfig: ServerStatsSettingsConfig;
|
||
|
|
refreshAllPolling: () => Promise<void>;
|
||
|
|
};
|
||
|
|
|
||
|
|
export function registerServerStatsSettingsRoutes(
|
||
|
|
app: Express,
|
||
|
|
{
|
||
|
|
requireAdmin,
|
||
|
|
defaultStatsConfig: DEFAULT_STATS_CONFIG,
|
||
|
|
refreshAllPolling,
|
||
|
|
}: ServerStatsSettingsRoutesDeps,
|
||
|
|
): void {
|
||
|
|
/**
|
||
|
|
* @openapi
|
||
|
|
* /global-settings:
|
||
|
|
* get:
|
||
|
|
* summary: Get global monitoring defaults
|
||
|
|
* tags:
|
||
|
|
* - Stats
|
||
|
|
* responses:
|
||
|
|
* 200:
|
||
|
|
* description: Global monitoring settings.
|
||
|
|
* 403:
|
||
|
|
* description: Requires admin privileges.
|
||
|
|
*/
|
||
|
|
app.get("/global-settings", requireAdmin, async (_req, res) => {
|
||
|
|
try {
|
||
|
|
const db = getDb();
|
||
|
|
|
||
|
|
try {
|
||
|
|
db.$client.prepare("SELECT 1 FROM settings LIMIT 1").get();
|
||
|
|
} catch (tableError) {
|
||
|
|
statsLogger.warn("Settings table does not exist, using defaults", {
|
||
|
|
operation: "global_settings_table_check",
|
||
|
|
error:
|
||
|
|
tableError instanceof Error
|
||
|
|
? tableError.message
|
||
|
|
: String(tableError),
|
||
|
|
});
|
||
|
|
return res.json({
|
||
|
|
statusCheckInterval: DEFAULT_STATS_CONFIG.statusCheckInterval,
|
||
|
|
metricsInterval: DEFAULT_STATS_CONFIG.metricsInterval,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const statusRow = db.$client
|
||
|
|
.prepare(
|
||
|
|
"SELECT value FROM settings WHERE key = 'global_status_check_interval'",
|
||
|
|
)
|
||
|
|
.get() as { value: string } | undefined;
|
||
|
|
const metricsRow = db.$client
|
||
|
|
.prepare(
|
||
|
|
"SELECT value FROM settings WHERE key = 'global_metrics_interval'",
|
||
|
|
)
|
||
|
|
.get() as { value: string } | undefined;
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
statusCheckInterval: statusRow
|
||
|
|
? parseInt(statusRow.value, 10)
|
||
|
|
: DEFAULT_STATS_CONFIG.statusCheckInterval,
|
||
|
|
metricsInterval: metricsRow
|
||
|
|
? parseInt(metricsRow.value, 10)
|
||
|
|
: DEFAULT_STATS_CONFIG.metricsInterval,
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
statsLogger.error("Failed to fetch global settings", {
|
||
|
|
operation: "global_settings_fetch_error",
|
||
|
|
error: error instanceof Error ? error.message : String(error),
|
||
|
|
});
|
||
|
|
res.status(500).json({ error: "Failed to fetch global settings" });
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @openapi
|
||
|
|
* /global-settings:
|
||
|
|
* post:
|
||
|
|
* summary: Update global monitoring defaults
|
||
|
|
* tags:
|
||
|
|
* - Stats
|
||
|
|
* requestBody:
|
||
|
|
* required: true
|
||
|
|
* content:
|
||
|
|
* application/json:
|
||
|
|
* schema:
|
||
|
|
* type: object
|
||
|
|
* properties:
|
||
|
|
* statusCheckInterval:
|
||
|
|
* type: integer
|
||
|
|
* metricsInterval:
|
||
|
|
* type: integer
|
||
|
|
* responses:
|
||
|
|
* 200:
|
||
|
|
* description: Settings saved.
|
||
|
|
* 400:
|
||
|
|
* description: Invalid parameters.
|
||
|
|
* 403:
|
||
|
|
* description: Requires admin privileges.
|
||
|
|
*/
|
||
|
|
app.post("/global-settings", requireAdmin, async (req, res) => {
|
||
|
|
const { statusCheckInterval, metricsInterval } = req.body;
|
||
|
|
|
||
|
|
if (
|
||
|
|
statusCheckInterval !== undefined &&
|
||
|
|
(typeof statusCheckInterval !== "number" ||
|
||
|
|
statusCheckInterval < 5 ||
|
||
|
|
statusCheckInterval > 3600)
|
||
|
|
) {
|
||
|
|
return res.status(400).json({
|
||
|
|
error: "statusCheckInterval must be between 5 and 3600 seconds",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
if (
|
||
|
|
metricsInterval !== undefined &&
|
||
|
|
(typeof metricsInterval !== "number" ||
|
||
|
|
metricsInterval < 5 ||
|
||
|
|
metricsInterval > 3600)
|
||
|
|
) {
|
||
|
|
return res
|
||
|
|
.status(400)
|
||
|
|
.json({ error: "metricsInterval must be between 5 and 3600 seconds" });
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const db = getDb();
|
||
|
|
|
||
|
|
try {
|
||
|
|
db.$client.prepare("SELECT 1 FROM settings LIMIT 1").get();
|
||
|
|
} catch (tableError) {
|
||
|
|
statsLogger.error(
|
||
|
|
"Settings table does not exist, cannot save settings",
|
||
|
|
{
|
||
|
|
operation: "global_settings_table_check",
|
||
|
|
error:
|
||
|
|
tableError instanceof Error
|
||
|
|
? tableError.message
|
||
|
|
: String(tableError),
|
||
|
|
},
|
||
|
|
);
|
||
|
|
return res.status(500).json({
|
||
|
|
error:
|
||
|
|
"Database settings table is missing. Please check database initialization.",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (statusCheckInterval !== undefined) {
|
||
|
|
db.$client
|
||
|
|
.prepare(
|
||
|
|
"INSERT OR REPLACE INTO settings (key, value) VALUES ('global_status_check_interval', ?)",
|
||
|
|
)
|
||
|
|
.run(String(statusCheckInterval));
|
||
|
|
}
|
||
|
|
if (metricsInterval !== undefined) {
|
||
|
|
db.$client
|
||
|
|
.prepare(
|
||
|
|
"INSERT OR REPLACE INTO settings (key, value) VALUES ('global_metrics_interval', ?)",
|
||
|
|
)
|
||
|
|
.run(String(metricsInterval));
|
||
|
|
}
|
||
|
|
|
||
|
|
await refreshAllPolling();
|
||
|
|
|
||
|
|
res.json({
|
||
|
|
success: true,
|
||
|
|
message: "Settings updated and polling refreshed",
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
statsLogger.error("Failed to save global settings", {
|
||
|
|
operation: "global_settings_save_error",
|
||
|
|
error: error instanceof Error ? error.message : String(error),
|
||
|
|
});
|
||
|
|
res.status(500).json({
|
||
|
|
error: "Failed to save global settings",
|
||
|
|
details: error instanceof Error ? error.message : String(error),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|