This commit is contained in:
Denozordec
2026-05-03 11:16:07 +07:00
parent ce00c4c671
commit bdb9b72fac
66 changed files with 9553 additions and 1547 deletions
+105
View File
@@ -81,6 +81,8 @@ CREATE TABLE IF NOT EXISTS uptime_settings (
id INTEGER PRIMARY KEY,
enabled INTEGER NOT NULL DEFAULT 1,
interval_sec INTEGER NOT NULL DEFAULT 15,
probe_interval_sec INTEGER NOT NULL DEFAULT 15,
speed_interval_sec INTEGER NOT NULL DEFAULT 60,
retention_days INTEGER NOT NULL DEFAULT 14,
last_collected_at TEXT,
last_duration_ms INTEGER,
@@ -97,6 +99,7 @@ CREATE TABLE IF NOT EXISTS uptime_probes (
target TEXT NOT NULL,
probe_filter TEXT NOT NULL DEFAULT '—',
enabled INTEGER NOT NULL DEFAULT 1,
show_on_dashboard INTEGER NOT NULL DEFAULT 0,
sort_order INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
@@ -134,6 +137,66 @@ CREATE TABLE IF NOT EXISTS uptime_resource_samples (
);
CREATE INDEX IF NOT EXISTS idx_uptime_resource_samples_server_time
ON uptime_resource_samples(server_id, sampled_at);
CREATE TABLE IF NOT EXISTS uptime_speed_probes (
id TEXT PRIMARY KEY,
src_server_id INTEGER NOT NULL,
dst_server_id INTEGER NOT NULL,
src_interface TEXT NOT NULL DEFAULT '',
dst_interface TEXT NOT NULL DEFAULT '',
protocol TEXT NOT NULL DEFAULT 'tcp',
direction TEXT NOT NULL DEFAULT 'both',
duration_sec INTEGER NOT NULL DEFAULT 10,
enabled INTEGER NOT NULL DEFAULT 1,
last_run_at TEXT,
last_tx_avg_mbps REAL,
last_rx_avg_mbps REAL,
last_status TEXT,
last_error TEXT,
sort_order INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (src_server_id) REFERENCES servers(id) ON DELETE CASCADE,
FOREIGN KEY (dst_server_id) REFERENCES servers(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_uptime_speed_probes_src_sort
ON uptime_speed_probes(src_server_id, sort_order);
CREATE TABLE IF NOT EXISTS uptime_speed_test_runs (
id TEXT PRIMARY KEY,
probe_id TEXT,
src_server_id INTEGER NOT NULL,
dst_server_id INTEGER NOT NULL,
src_interface TEXT NOT NULL DEFAULT '',
dst_interface TEXT NOT NULL DEFAULT '',
src_address TEXT,
dst_address TEXT,
src_interface_address TEXT,
dst_interface_address TEXT,
protocol TEXT NOT NULL DEFAULT 'tcp',
direction TEXT NOT NULL DEFAULT 'both',
duration_sec INTEGER NOT NULL DEFAULT 10,
tx_avg_mbps REAL,
rx_avg_mbps REAL,
ping_rtt_ms INTEGER,
ping_loss_pct INTEGER,
ping_error TEXT,
status TEXT NOT NULL DEFAULT 'done',
error TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (src_server_id) REFERENCES servers(id) ON DELETE CASCADE,
FOREIGN KEY (dst_server_id) REFERENCES servers(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_uptime_speed_test_runs_created_at
ON uptime_speed_test_runs(created_at);
CREATE TABLE IF NOT EXISTS evobgp_settings (
id INTEGER PRIMARY KEY,
base_url TEXT NOT NULL DEFAULT '',
api_key TEXT NOT NULL DEFAULT '',
enabled INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
`)
// Lightweight schema evolution for existing databases without migrations
@@ -148,6 +211,42 @@ const hasSrcInterfaceColumn = uptimeProbeCols.some((c) => c.name === "src_interf
if (!hasSrcInterfaceColumn) {
sqlite.exec(`ALTER TABLE uptime_probes ADD COLUMN src_interface TEXT NOT NULL DEFAULT ''`)
}
const hasShowOnDashboardColumn = uptimeProbeCols.some((c) => c.name === "show_on_dashboard")
if (!hasShowOnDashboardColumn) {
sqlite.exec(`ALTER TABLE uptime_probes ADD COLUMN show_on_dashboard INTEGER NOT NULL DEFAULT 0`)
}
const uptimeSettingsCols = sqlite.prepare(`PRAGMA table_info('uptime_settings')`).all() as Array<{ name?: string }>
const hasProbeIntervalColumn = uptimeSettingsCols.some((c) => c.name === "probe_interval_sec")
if (!hasProbeIntervalColumn) {
sqlite.exec(`ALTER TABLE uptime_settings ADD COLUMN probe_interval_sec INTEGER NOT NULL DEFAULT 15`)
}
const hasSpeedIntervalColumn = uptimeSettingsCols.some((c) => c.name === "speed_interval_sec")
if (!hasSpeedIntervalColumn) {
sqlite.exec(`ALTER TABLE uptime_settings ADD COLUMN speed_interval_sec INTEGER NOT NULL DEFAULT 60`)
}
const uptimeSpeedProbeCols = sqlite.prepare(`PRAGMA table_info('uptime_speed_probes')`).all() as Array<{ name?: string }>
const ensureSpeedProbeCol = (name: string, ddl: string) => {
if (!uptimeSpeedProbeCols.some((c) => c.name === name)) sqlite.exec(ddl)
}
ensureSpeedProbeCol("last_run_at", `ALTER TABLE uptime_speed_probes ADD COLUMN last_run_at TEXT`)
ensureSpeedProbeCol("last_tx_avg_mbps", `ALTER TABLE uptime_speed_probes ADD COLUMN last_tx_avg_mbps REAL`)
ensureSpeedProbeCol("last_rx_avg_mbps", `ALTER TABLE uptime_speed_probes ADD COLUMN last_rx_avg_mbps REAL`)
ensureSpeedProbeCol("last_status", `ALTER TABLE uptime_speed_probes ADD COLUMN last_status TEXT`)
ensureSpeedProbeCol("last_error", `ALTER TABLE uptime_speed_probes ADD COLUMN last_error TEXT`)
ensureSpeedProbeCol("last_ping_rtt_ms", `ALTER TABLE uptime_speed_probes ADD COLUMN last_ping_rtt_ms INTEGER`)
ensureSpeedProbeCol("last_ping_loss_pct", `ALTER TABLE uptime_speed_probes ADD COLUMN last_ping_loss_pct INTEGER`)
ensureSpeedProbeCol("last_ping_at", `ALTER TABLE uptime_speed_probes ADD COLUMN last_ping_at TEXT`)
ensureSpeedProbeCol("last_ping_error", `ALTER TABLE uptime_speed_probes ADD COLUMN last_ping_error TEXT`)
const serverCols = sqlite.prepare(`PRAGMA table_info('servers')`).all() as Array<{ name?: string }>
if (!serverCols.some((c) => c.name === "lan_subnet")) {
sqlite.exec(`ALTER TABLE servers ADD COLUMN lan_subnet TEXT NOT NULL DEFAULT ''`)
}
if (!serverCols.some((c) => c.name === "wan_uplinks")) {
sqlite.exec(`ALTER TABLE servers ADD COLUMN wan_uplinks TEXT NOT NULL DEFAULT '[]'`)
}
sqlite.exec(`
INSERT INTO traffic_settings (id, enabled, interval_sec, retention_days)
@@ -161,4 +260,10 @@ SELECT 1, 1, 15, 14
WHERE NOT EXISTS (SELECT 1 FROM uptime_settings WHERE id = 1);
`)
sqlite.exec(`
INSERT INTO evobgp_settings (id, base_url, api_key, enabled)
SELECT 1, '', '', 0
WHERE NOT EXISTS (SELECT 1 FROM evobgp_settings WHERE id = 1);
`)
export const db = drizzle(sqlite, { schema })
+74
View File
@@ -27,6 +27,11 @@ export const servers = sqliteTable("servers", {
comment: text("comment").notNull().default(""),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
/** Подсеть LAN (home-router), текст из формы */
lanSubnet: text("lan_subnet").notNull().default(""),
/** JSON-массив WAN-аплинков [{ id, name, isp, iface, ip, maxDl, maxUl }, …] */
wanUplinks: text("wan_uplinks").notNull().default("[]"),
createdAt: text("created_at").notNull().default(sql`(datetime('now'))`),
updatedAt: text("updated_at").notNull().default(sql`(datetime('now'))`),
})
@@ -133,6 +138,8 @@ export const uptimeSettings = sqliteTable("uptime_settings", {
id: integer("id").primaryKey(),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
intervalSec: integer("interval_sec").notNull().default(15),
probeIntervalSec: integer("probe_interval_sec").notNull().default(15),
speedIntervalSec: integer("speed_interval_sec").notNull().default(60),
retentionDays: integer("retention_days").notNull().default(14),
lastCollectedAt: text("last_collected_at"),
lastDurationMs: integer("last_duration_ms"),
@@ -151,6 +158,8 @@ export const uptimeProbes = sqliteTable("uptime_probes", {
target: text("target").notNull(),
probeFilter: text("probe_filter").notNull().default("—"),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
/** Выводить пробу в блоке «Активные пробы» на дашборде */
showOnDashboard: integer("show_on_dashboard", { mode: "boolean" }).notNull().default(false),
sortOrder: integer("sort_order").notNull().default(0),
createdAt: text("created_at").notNull().default(sql`(datetime('now'))`),
updatedAt: text("updated_at").notNull().default(sql`(datetime('now'))`),
@@ -184,6 +193,68 @@ export const uptimeResourceSamples = sqliteTable("uptime_resource_samples", {
rosVersion: text("ros_version").notNull().default(""),
})
export const uptimeSpeedProbes = sqliteTable("uptime_speed_probes", {
id: text("id").primaryKey(),
srcServerId: integer("src_server_id")
.notNull()
.references(() => servers.id, { onDelete: "cascade" }),
dstServerId: integer("dst_server_id")
.notNull()
.references(() => servers.id, { onDelete: "cascade" }),
srcInterface: text("src_interface").notNull().default(""),
dstInterface: text("dst_interface").notNull().default(""),
protocol: text("protocol", { enum: ["tcp", "udp"] }).notNull().default("tcp"),
direction: text("direction", { enum: ["transmit", "receive", "both"] }).notNull().default("both"),
durationSec: integer("duration_sec").notNull().default(10),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
lastRunAt: text("last_run_at"),
lastTxAvgMbps: real("last_tx_avg_mbps"),
lastRxAvgMbps: real("last_rx_avg_mbps"),
lastStatus: text("last_status", { enum: ["done", "error"] }),
lastError: text("last_error"),
lastPingRttMs: integer("last_ping_rtt_ms"),
lastPingLossPct: integer("last_ping_loss_pct"),
lastPingAt: text("last_ping_at"),
lastPingError: text("last_ping_error"),
sortOrder: integer("sort_order").notNull().default(0),
createdAt: text("created_at").notNull().default(sql`(datetime('now'))`),
updatedAt: text("updated_at").notNull().default(sql`(datetime('now'))`),
})
// ── EvoBGP integration (URL + API key на сервере) ─────────────────────────────
export const evobgpSettings = sqliteTable("evobgp_settings", {
id: integer("id").primaryKey(),
baseUrl: text("base_url").notNull().default(""),
apiKey: text("api_key").notNull().default(""),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(false),
updatedAt: text("updated_at").notNull().default(sql`(datetime('now'))`),
})
export const uptimeSpeedTestRuns = sqliteTable("uptime_speed_test_runs", {
id: text("id").primaryKey(),
probeId: text("probe_id"),
srcServerId: integer("src_server_id").notNull().references(() => servers.id, { onDelete: "cascade" }),
dstServerId: integer("dst_server_id").notNull().references(() => servers.id, { onDelete: "cascade" }),
srcInterface: text("src_interface").notNull().default(""),
dstInterface: text("dst_interface").notNull().default(""),
srcAddress: text("src_address"),
dstAddress: text("dst_address"),
srcInterfaceAddress:text("src_interface_address"),
dstInterfaceAddress:text("dst_interface_address"),
protocol: text("protocol", { enum: ["tcp", "udp"] }).notNull().default("tcp"),
direction: text("direction", { enum: ["transmit", "receive", "both"] }).notNull().default("both"),
durationSec: integer("duration_sec").notNull().default(10),
txAvgMbps: real("tx_avg_mbps"),
rxAvgMbps: real("rx_avg_mbps"),
pingRttMs: integer("ping_rtt_ms"),
pingLossPct: integer("ping_loss_pct"),
pingError: text("ping_error"),
status: text("status", { enum: ["done", "error"] }).notNull().default("done"),
error: text("error"),
createdAt: text("created_at").notNull().default(sql`(datetime('now'))`),
})
// ── inferred types ─────────────────────────────────────────────────────────────
export type Server = typeof servers.$inferSelect
@@ -198,3 +269,6 @@ export type UptimeSettingsRow = typeof uptimeSettings.$inferSelect
export type UptimeProbeRow = typeof uptimeProbes.$inferSelect
export type UptimeProbeSampleRow = typeof uptimeProbeSamples.$inferSelect
export type UptimeResourceSampleRow = typeof uptimeResourceSamples.$inferSelect
export type UptimeSpeedProbeRow = typeof uptimeSpeedProbes.$inferSelect
export type UptimeSpeedTestRunRow = typeof uptimeSpeedTestRuns.$inferSelect
export type EvobgpSettingsRow = typeof evobgpSettings.$inferSelect