Init commit
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import { desc, eq } from "drizzle-orm"
|
||||
import { db } from "../db/index.js"
|
||||
import { servers, serverSnapshots } from "../db/schema.js"
|
||||
import type { SnapshotInsert } from "../db/schema.js"
|
||||
import type { SnapshotRead } from "../types/server.js"
|
||||
import { MikrotikClient } from "./mikrotik.js"
|
||||
|
||||
// ── pollServer ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Connect to a RouterOS device, collect system info, persist a snapshot,
|
||||
* and sync the server's display name from system/identity.
|
||||
*/
|
||||
export async function pollServer(serverId: number): Promise<SnapshotRead> {
|
||||
const server = db
|
||||
.select()
|
||||
.from(servers)
|
||||
.where(eq(servers.id, serverId))
|
||||
.limit(1)
|
||||
.all()[0]
|
||||
|
||||
if (!server) {
|
||||
throw new Error(`Server with id=${serverId} not found`)
|
||||
}
|
||||
|
||||
const now = new Date().toISOString()
|
||||
const client = MikrotikClient.fromServer(server)
|
||||
const t0 = performance.now()
|
||||
|
||||
const partialSnap: Partial<SnapshotInsert> = {
|
||||
serverId,
|
||||
polledAt: now,
|
||||
status: "offline",
|
||||
latencyMs: null,
|
||||
}
|
||||
|
||||
try {
|
||||
// Fire all requests in parallel for speed
|
||||
const [identity, resource, ifaces, addresses] = await Promise.all([
|
||||
client.getIdentity(),
|
||||
client.getResource(),
|
||||
client.getInterfaces(),
|
||||
client.getIpAddresses(),
|
||||
])
|
||||
|
||||
const latencyMs = performance.now() - t0
|
||||
|
||||
// Parse RouterOS string values (RouterOS REST API returns everything as strings)
|
||||
const cpuLoad = parseInt(resource["cpu-load"], 10)
|
||||
const freeMem = parseInt(resource["free-memory"], 10)
|
||||
const totalMem = parseInt(resource["total-memory"], 10)
|
||||
|
||||
Object.assign(partialSnap, {
|
||||
status: "online",
|
||||
latencyMs,
|
||||
identityName: identity.name,
|
||||
rosVersion: resource["version"],
|
||||
boardName: resource["board-name"],
|
||||
uptime: resource["uptime"],
|
||||
cpuLoad: isNaN(cpuLoad) ? null : cpuLoad,
|
||||
freeMemory: isNaN(freeMem) ? null : freeMem,
|
||||
totalMemory: isNaN(totalMem) ? null : totalMem,
|
||||
rawInterfaces: JSON.stringify(ifaces),
|
||||
rawIpAddresses: JSON.stringify(addresses),
|
||||
} satisfies Partial<SnapshotInsert>)
|
||||
|
||||
// Keep server.name in sync with RouterOS identity
|
||||
db.update(servers)
|
||||
.set({ name: identity.name, updatedAt: now })
|
||||
.where(eq(servers.id, serverId))
|
||||
.run()
|
||||
|
||||
} catch (err) {
|
||||
// Log but don't throw — we still persist the offline snapshot
|
||||
console.warn(`[poller] server id=${serverId} unreachable:`, (err as Error).message)
|
||||
}
|
||||
|
||||
const [inserted] = db
|
||||
.insert(serverSnapshots)
|
||||
.values(partialSnap as SnapshotInsert)
|
||||
.returning()
|
||||
.all()
|
||||
|
||||
return toSnapshotRead(inserted)
|
||||
}
|
||||
|
||||
// ── helper ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
export function toSnapshotRead(s: typeof serverSnapshots.$inferSelect): SnapshotRead {
|
||||
return {
|
||||
id: s.id,
|
||||
serverId: s.serverId,
|
||||
polledAt: s.polledAt,
|
||||
status: s.status,
|
||||
latencyMs: s.latencyMs ?? null,
|
||||
rosVersion: s.rosVersion ?? null,
|
||||
boardName: s.boardName ?? null,
|
||||
uptime: s.uptime ?? null,
|
||||
cpuLoad: s.cpuLoad ?? null,
|
||||
freeMemory: s.freeMemory ?? null,
|
||||
totalMemory: s.totalMemory ?? null,
|
||||
identityName: s.identityName ?? null,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user