summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Anshul Gupta <ansg191@anshulg.com> 2025-06-07 22:51:16 -0700
committerGravatar Anshul Gupta <ansg191@anshulg.com> 2025-06-07 22:51:16 -0700
commit920ac0949ce5571d3c3c8363314932a830a9e543 (patch)
treeeef8336af1af7b9a880ff1265657d583165c1651
parent3f2ca2e93eeec747713730b71a3befd8e0ff7bb1 (diff)
downloadanshulg-com-920ac0949ce5571d3c3c8363314932a830a9e543.tar.gz
anshulg-com-920ac0949ce5571d3c3c8363314932a830a9e543.tar.zst
anshulg-com-920ac0949ce5571d3c3c8363314932a830a9e543.zip
Extract kuma dependency from `Uptime` component
Diffstat (limited to '')
-rw-r--r--src/components/server/Uptime.astro129
-rw-r--r--src/pages/index.astro4
-rw-r--r--src/utils/status/index.ts43
-rw-r--r--src/utils/status/kuma.ts62
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;