Files
Termix/src/backend/ssh/host-metrics-settings-routes.ts
T

280 lines
8.3 KiB
TypeScript
Raw Normal View History

2026-06-04 15:16:53 -04:00
import type { Express, RequestHandler } from "express";
import { getDb } from "../database/db/index.js";
import { statsLogger } from "../utils/logger.js";
+2
2026-06-16 15:59:53 -05:00
type HostMetricsSettingsConfig = {
2026-06-04 15:16:53 -04:00
statusCheckInterval: number;
metricsInterval: number;
};
+2
2026-06-16 15:59:53 -05:00
type HostMetricsSettingsRoutesDeps = {
2026-06-04 15:16:53 -04:00
requireAdmin: RequestHandler;
+2
2026-06-16 15:59:53 -05:00
defaultStatsConfig: HostMetricsSettingsConfig;
2026-06-04 15:16:53 -04:00
refreshAllPolling: () => Promise<void>;
};
+2
2026-06-16 15:59:53 -05:00
export function registerHostMetricsSettingsRoutes(
2026-06-04 15:16:53 -04:00
app: Express,
{
requireAdmin,
defaultStatsConfig: DEFAULT_STATS_CONFIG,
refreshAllPolling,
+2
2026-06-16 15:59:53 -05:00
}: HostMetricsSettingsRoutesDeps,
2026-06-04 15:16:53 -04:00
): void {
/**
* @openapi
* /global-settings:
* get:
* summary: Get global monitoring defaults
* tags:
+2
2026-06-16 15:59:53 -05:00
* - Host Metrics
2026-06-04 15:16:53 -04:00
* 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:
+2
2026-06-16 15:59:53 -05:00
* - Host Metrics
2026-06-04 15:16:53 -04:00
* 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),
});
}
});
2026-06-29 13:28:26 -05:00
/**
* @openapi
* /global-settings/history:
* get:
* summary: Get metrics history retention setting
* tags:
* - Host Metrics
* responses:
* 200:
* description: Retention setting in days.
* 403:
* description: Requires admin privileges.
*/
app.get("/global-settings/history", requireAdmin, (_req, res) => {
try {
const db = getDb();
const row = db.$client
.prepare(
"SELECT value FROM settings WHERE key = 'metrics_history_retention_days'",
)
.get() as { value: string } | undefined;
const days = row ? parseInt(row.value, 10) : 7;
res.json({ metricsHistoryRetentionDays: isNaN(days) ? 7 : days });
} catch (error) {
statsLogger.error("Failed to fetch history retention setting", {
operation: "history_retention_fetch_error",
error: error instanceof Error ? error.message : String(error),
});
res
.status(500)
.json({ error: "Failed to fetch history retention setting" });
}
});
/**
* @openapi
* /global-settings/history:
* post:
* summary: Update metrics history retention setting
* tags:
* - Host Metrics
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* metricsHistoryRetentionDays:
* type: integer
* minimum: 1
* maximum: 90
* responses:
* 200:
* description: Setting saved.
* 400:
* description: Invalid value.
* 403:
* description: Requires admin privileges.
*/
app.post("/global-settings/history", requireAdmin, (req, res) => {
const { metricsHistoryRetentionDays } = req.body;
if (
typeof metricsHistoryRetentionDays !== "number" ||
metricsHistoryRetentionDays < 1 ||
metricsHistoryRetentionDays > 90
) {
return res.status(400).json({
error: "metricsHistoryRetentionDays must be between 1 and 90",
});
}
try {
const db = getDb();
db.$client
.prepare(
"INSERT OR REPLACE INTO settings (key, value) VALUES ('metrics_history_retention_days', ?)",
)
.run(String(Math.floor(metricsHistoryRetentionDays)));
res.json({ success: true });
} catch (error) {
statsLogger.error("Failed to save history retention setting", {
operation: "history_retention_save_error",
error: error instanceof Error ? error.message : String(error),
});
res
.status(500)
.json({ error: "Failed to save history retention setting" });
}
});
2026-06-04 15:16:53 -04:00
}