diff options
Diffstat (limited to '')
-rw-r--r-- | src/components/server/Uptime.astro | 129 | ||||
-rw-r--r-- | src/pages/index.astro | 4 | ||||
-rw-r--r-- | src/utils/status/index.ts | 43 | ||||
-rw-r--r-- | src/utils/status/kuma.ts | 62 |
4 files changed, 141 insertions, 97 deletions
diff --git a/src/components/server/Uptime.astro b/src/components/server/Uptime.astro index a189c29..3949482 100644 --- a/src/components/server/Uptime.astro +++ b/src/components/server/Uptime.astro @@ -3,78 +3,23 @@ * Server Island component to grab uptime from Uptime Kuma. */ -import { KUMA_URL, KUMA_API_KEY } from "astro:env/server"; +import { ServiceStatus } from "../../utils/status"; +import kuma_status from "../../utils/status/kuma"; interface Props { name: string; + src: "kuma"; } -const { name } = Astro.props; +const { name, src } = Astro.props; -let show = true; - -// Ensure ENV variables are set -if (!KUMA_URL || !KUMA_API_KEY) { - console.warn( - "Uptime Kuma URL or API Key is not set. Skipping Uptime component.", - ); - show = false; +let status = ServiceStatus.UNKNOWN; +switch (src) { + case "kuma": + status = await kuma_status(name); } -// Fetch the metrics from Uptime Kuma -const response = await fetch(`${KUMA_URL}/metrics`, { - headers: { - Authorization: `Basic ${Buffer.from(`:${KUMA_API_KEY}`).toString("base64")}`, - }, -}); - -if (!response.ok) { - console.warn( - `Failed to fetch metrics from Uptime Kuma: ${response.status} ${response.statusText}`, - ); - show = false; -} - -// Parse the metrics to find the status of the monitor with the given name -const metrics = await response.text(); -const status = metrics - .split("\n") - .filter((line) => line.startsWith("monitor_status")) - .map((l) => { - return { - status: l.substring(l.length - 1), - name: l - .substring("monitor_status{".length, l.length - 3) - .split(",") - .map((kv) => kv.split("=", 2)) - .filter((kv) => kv[0] === "monitor_name") - .map((kv) => kv[1].replace(/"/g, ""))[0], - }; - }) - .filter((m) => m.name === name) - .map((m) => m.status)[0]; - -if (status == null) { - console.warn(`Monitor with name "${name}" not found in Uptime Kuma metrics.`); - show = false; -} - -// Map the status to a color -const colorMap = { - "0": "bg-red-500", - "1": "bg-green-500", - "2": "bg-yellow-500", - "3": "bg-orange-500", -} as Record<string, string>; -const color = colorMap[status] || "bg-gray-500"; - -// Map the status to a human-readable string -const statusMap = { - "0": "Down", - "1": "Up", - "2": "Pending", - "3": "Under Maintenance", -} as Record<string, string>; -const statusText = statusMap[status] || "unknown"; +const color = ServiceStatus.toColorClass(status); +const statusText = ServiceStatus.toHumanReadable(status); // Set caching headers for 5 min and allow stale content for 1 minute Astro.response.headers.set( @@ -83,33 +28,27 @@ Astro.response.headers.set( ); --- -{ - show && ( - <> - <span class="absolute -top-1.5 -right-1 w-2.5 h-2.5"> - <span - aria-hidden="true" - class:list={[ - "absolute", - "inset-0", - "rounded-full", - "opacity-75", - "motion-safe:animate-ping", - color, - ]} - /> - <span - class:list={[ - "relative", - "block", - "w-2.5", - "h-2.5", - "rounded-full", - color, - ]} - /> - </span> - <span class="sr-only">Service Status: {statusText}</span> - </> - ) -} +<> + <span class="absolute -top-1.5 -right-1 w-2.5 h-2.5"> + <span + aria-hidden="true" + class:list={[ + "absolute", + "inset-0", + "rounded-full", + "opacity-75", + "motion-safe:animate-ping", + color, + ]}></span> + <span + class:list={[ + "relative", + "block", + "w-2.5", + "h-2.5", + "rounded-full", + color, + ]}></span> + </span> + <span class="sr-only">Service Status: {statusText}</span> +</> diff --git a/src/pages/index.astro b/src/pages/index.astro index a5fcd2d..68ae6c9 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -120,7 +120,7 @@ const projectsWidth = 13; <h2 class="font-extrabold text-xl">SEE ALSO</h2> <ManItem key="Git Server" keyLink="https://git.anshulg.com" keylen={10}> <span slot="key-extra"> - <Uptime name="CGit Server" server:defer> + <Uptime name="CGit Server" src="kuma" server:defer> <UptimeFallback slot="fallback" /> </Uptime> </span> @@ -137,7 +137,7 @@ const projectsWidth = 13; </ManItem> <ManItem key="Apt Repo" keyLink="https://apt.anshulg.com" keylen={10}> <span slot="key-extra"> - <Uptime name="Debian Apt Server" server:defer> + <Uptime name="Debian Apt Server" src="kuma" server:defer> <UptimeFallback slot="fallback" /> </Uptime> </span> diff --git a/src/utils/status/index.ts b/src/utils/status/index.ts new file mode 100644 index 0000000..b4343b2 --- /dev/null +++ b/src/utils/status/index.ts @@ -0,0 +1,43 @@ +export enum ServiceStatus { + UNKNOWN, + DOWN, + UP, + PENDING, + MAINTENANCE, +} + +export namespace ServiceStatus { + export function toColorClass(status: ServiceStatus): string { + switch (status) { + case ServiceStatus.UNKNOWN: + return "bg-gray-500"; + case ServiceStatus.DOWN: + return "bg-red-500"; + case ServiceStatus.UP: + return "bg-green-500"; + case ServiceStatus.PENDING: + return "bg-yellow-500"; + case ServiceStatus.MAINTENANCE: + return "bg-orange-500"; + default: + return "bg-gray-500"; + } + } + + export function toHumanReadable(status: ServiceStatus): string { + switch (status) { + case ServiceStatus.UNKNOWN: + return "Unknown"; + case ServiceStatus.DOWN: + return "Down"; + case ServiceStatus.UP: + return "Up"; + case ServiceStatus.PENDING: + return "Pending"; + case ServiceStatus.MAINTENANCE: + return "Under Maintenance"; + default: + return "Unknown"; + } + } +} diff --git a/src/utils/status/kuma.ts b/src/utils/status/kuma.ts new file mode 100644 index 0000000..0bdf814 --- /dev/null +++ b/src/utils/status/kuma.ts @@ -0,0 +1,62 @@ +import { KUMA_API_KEY, KUMA_URL } from "astro:env/server"; +import { ServiceStatus } from "./index.ts"; + +const STATUS_MAP: Record<string, ServiceStatus> = { + "0": ServiceStatus.DOWN, + "1": ServiceStatus.UP, + "2": ServiceStatus.PENDING, + "3": ServiceStatus.MAINTENANCE, +}; + +async function kuma_status(name: string): Promise<ServiceStatus> { + if (!KUMA_URL || !KUMA_API_KEY) { + console.warn( + "Uptime Kuma URL or API Key is not set. Skipping Uptime component.", + ); + return ServiceStatus.UNKNOWN; + } + + // Fetch the metrics from Uptime Kuma + const response = await fetch(`${KUMA_URL}/metrics`, { + headers: { + Authorization: `Basic ${Buffer.from(`:${KUMA_API_KEY}`).toString("base64")}`, + }, + }); + + if (!response.ok) { + console.error( + `Failed to fetch metrics from Uptime Kuma: ${response.statusText}`, + ); + return ServiceStatus.UNKNOWN; + } + + // Parse the metrics to find the status of the monitor with the given name + const metrics = await response.text(); + const statusStr = metrics + .split("\n") + .filter((line) => line.startsWith("monitor_status")) + .map((l) => { + return { + status: l.substring(l.length - 1), + name: l + .substring("monitor_status{".length, l.length - 3) + .split(",") + .map((kv) => kv.split("=", 2)) + .filter((kv) => kv[0] === "monitor_name") + .map((kv) => kv[1]?.replace(/"/g, ""))[0], + }; + }) + .filter((m) => m.name === name) + .map((m) => m.status)[0]; + + if (statusStr == null) { + console.warn( + `Monitor with name "${name}" not found in Uptime Kuma metrics.`, + ); + return ServiceStatus.UNKNOWN; + } + + return STATUS_MAP[statusStr] ?? ServiceStatus.UNKNOWN; +} + +export default kuma_status; |