refactor: data retrieval function

This commit is contained in:
hamster1963 2024-07-28 23:58:14 +08:00
parent 7cfc5a49cc
commit a16dd290a7
11 changed files with 93 additions and 139 deletions

View File

@ -11,12 +11,11 @@ export default function ServerListClient() {
}); });
if (!data) return null; if (!data) return null;
const sortedResult = data.result.sort((a, b) => a.id - b.id); const sortedResult = data.result.sort((a, b) => a.id - b.id);
const timestamp = Date.now() / 1000;
return ( return (
<section className={"grid grid-cols-1 gap-2 md:grid-cols-2"}> <section className={"grid grid-cols-1 gap-2 md:grid-cols-2"}>
{sortedResult.map((serverInfo) => ( {sortedResult.map((serverInfo) => (
<ServerCard key={serverInfo.id} timestamp={timestamp} serverInfo={serverInfo} /> <ServerCard key={serverInfo.id} serverInfo={serverInfo} />
))} ))}
</section> </section>
); );

View File

@ -38,7 +38,7 @@ function Header() {
// https://github.com/streamich/react-use/blob/master/src/useInterval.ts // https://github.com/streamich/react-use/blob/master/src/useInterval.ts
const useInterval = (callback: Function, delay?: number | null) => { const useInterval = (callback: Function, delay?: number | null) => {
const savedCallback = useRef<Function>(() => { }); const savedCallback = useRef<Function>(() => {});
useEffect(() => { useEffect(() => {
savedCallback.current = callback; savedCallback.current = callback;
@ -61,7 +61,9 @@ function Overview() {
}, []); }, []);
const timeOption = DateTime.TIME_SIMPLE; const timeOption = DateTime.TIME_SIMPLE;
timeOption.hour12 = true; timeOption.hour12 = true;
const [timeString, setTimeString] = useState(DateTime.now().setLocale("en-US").toLocaleString(timeOption)); const [timeString, setTimeString] = useState(
DateTime.now().setLocale("en-US").toLocaleString(timeOption),
);
useInterval(() => { useInterval(() => {
setTimeString(DateTime.now().setLocale("en-US").toLocaleString(timeOption)); setTimeString(DateTime.now().setLocale("en-US").toLocaleString(timeOption));
@ -73,9 +75,7 @@ function Overview() {
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<p className="text-sm font-medium opacity-50">where the time is</p> <p className="text-sm font-medium opacity-50">where the time is</p>
{mouted && ( {mouted && (
<p className="opacity-1 text-sm font-medium"> <p className="opacity-1 text-sm font-medium">{timeString}</p>
{timeString}
</p>
)} )}
</div> </div>
</section> </section>

View File

@ -1,6 +1,7 @@
import ServerList from "@/components/ServerList"; import ServerList from "@/components/ServerList";
import ServerOverview from "@/components/ServerOverview"; import ServerOverview from "@/components/ServerOverview";
import { GetNezhaData } from "@/lib/prefetch"; import { GetNezhaData } from "@/lib/serverFetch";
import { SWRConfig } from "swr"; import { SWRConfig } from "swr";
export default function Home() { export default function Home() {

View File

@ -1,57 +1,10 @@
import { NezhaAPI, ServerApi } from "@/app/types/nezha-api"; import { GetNezhaData } from "@/lib/serverFetch";
import { MakeOptional } from "@/app/types/utils";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
export async function GET(_: Request) { export async function GET(_: Request) {
if (!process.env.NezhaBaseUrl) {
return NextResponse.json(
{ error: "NezhaBaseUrl is not set" },
{ status: 400 },
);
}
// Remove trailing slash
var nezhaBaseUrl = process.env.NezhaBaseUrl;
if (process.env.NezhaBaseUrl[process.env.NezhaBaseUrl.length - 1] === "/") {
nezhaBaseUrl = process.env.NezhaBaseUrl.slice(0, -1);
}
try { try {
const response = await fetch(nezhaBaseUrl + "/api/v1/server/details", { const response = await GetNezhaData();
headers: { return NextResponse.json(response, { status: 200 });
Authorization: process.env.NezhaAuth as string,
},
next: {
revalidate: 0,
},
});
const nezhaData = (await response.json()).result as NezhaAPI[];
const data: ServerApi = {
live_servers: 0,
offline_servers: 0,
total_bandwidth: 0,
result: [],
};
const timestamp = Date.now() / 1000;
data.result = nezhaData.map(
(element: MakeOptional<NezhaAPI, "ipv4" | "ipv6" | "valid_ip">) => {
if (timestamp - element.last_active > 300) {
data.offline_servers += 1;
} else {
data.live_servers += 1;
}
data.total_bandwidth += element.status.NetOutTransfer;
delete element.ipv4;
delete element.ipv6;
delete element.valid_ip;
return element;
},
);
return NextResponse.json(data, { status: 200 });
} catch (error) { } catch (error) {
return NextResponse.json({ error: error }, { status: 200 }); return NextResponse.json({ error: error }, { status: 200 });
} }

View File

@ -12,6 +12,7 @@ export interface NezhaAPI {
name: string; name: string;
tag: string; tag: string;
last_active: number; last_active: number;
online_status: boolean;
ipv4: string; ipv4: string;
ipv6: string; ipv6: string;
valid_ip: string; valid_ip: string;

BIN
bun.lockb

Binary file not shown.

View File

@ -10,18 +10,14 @@ import { formatNezhaInfo } from "@/lib/utils";
import ServerCardPopover from "./ServerCardPopover"; import ServerCardPopover from "./ServerCardPopover";
export default function ServerCard({ export default function ServerCard({
timestamp,
serverInfo, serverInfo,
}: { }: {
timestamp: number;
serverInfo: NezhaAPISafe; serverInfo: NezhaAPISafe;
}) { }) {
const { name, online, cpu, up, down, mem, stg, ...props } = formatNezhaInfo( const { name, online, cpu, up, down, mem, stg, ...props } =
timestamp, formatNezhaInfo(serverInfo);
serverInfo,
);
return online === "online" ? ( return online ? (
<Card <Card
className={ className={
"flex flex-col items-center justify-start gap-3 p-3 md:px-5 lg:flex-row" "flex flex-col items-center justify-start gap-3 p-3 md:px-5 lg:flex-row"

View File

@ -1,13 +1,13 @@
"use client" "use client";
import * as React from "react" import * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover" import * as PopoverPrimitive from "@radix-ui/react-popover";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
const Popover = PopoverPrimitive.Root const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverContent = React.forwardRef< const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>, React.ElementRef<typeof PopoverPrimitive.Content>,
@ -20,12 +20,12 @@ const PopoverContent = React.forwardRef<
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", "z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className className,
)} )}
{...props} {...props}
/> />
</PopoverPrimitive.Portal> </PopoverPrimitive.Portal>
)) ));
PopoverContent.displayName = PopoverPrimitive.Content.displayName PopoverContent.displayName = PopoverPrimitive.Content.displayName;
export { Popover, PopoverTrigger, PopoverContent } export { Popover, PopoverTrigger, PopoverContent };

View File

@ -1,54 +0,0 @@
import { NezhaAPI, ServerApi } from "@/app/types/nezha-api";
import { MakeOptional } from "@/app/types/utils";
import { error } from "console";
export async function GetNezhaData() {
if (!process.env.NezhaBaseUrl) {
error("NezhaBaseUrl is not set");
return;
}
// Remove trailing slash
var nezhaBaseUrl = process.env.NezhaBaseUrl;
if (process.env.NezhaBaseUrl[process.env.NezhaBaseUrl.length - 1] === "/") {
nezhaBaseUrl = process.env.NezhaBaseUrl.slice(0, -1);
}
try {
const response = await fetch(nezhaBaseUrl + "/api/v1/server/details", {
headers: {
Authorization: process.env.NezhaAuth as string,
},
next: {
revalidate: 1,
},
});
const nezhaData = (await response.json()).result as NezhaAPI[];
const data: ServerApi = {
live_servers: 0,
offline_servers: 0,
total_bandwidth: 0,
result: [],
};
const timestamp = Date.now() / 1000;
data.result = nezhaData.map(
(element: MakeOptional<NezhaAPI, "ipv4" | "ipv6" | "valid_ip">) => {
if (timestamp - element.last_active > 300) {
data.offline_servers += 1;
} else {
data.live_servers += 1;
}
data.total_bandwidth += element.status.NetOutTransfer;
delete element.ipv4;
delete element.ipv6;
delete element.valid_ip;
return element;
},
);
return data;
} catch (error) {
return error;
}
}

58
lib/serverFetch.tsx Normal file
View File

@ -0,0 +1,58 @@
"use server";
import { NezhaAPI, ServerApi } from "@/app/types/nezha-api";
import { MakeOptional } from "@/app/types/utils";
import { error } from "console";
export async function GetNezhaData() {
if (!process.env.NezhaBaseUrl) {
error("NezhaBaseUrl is not set");
return;
}
// Remove trailing slash
var nezhaBaseUrl = process.env.NezhaBaseUrl;
if (process.env.NezhaBaseUrl[process.env.NezhaBaseUrl.length - 1] === "/") {
nezhaBaseUrl = process.env.NezhaBaseUrl.slice(0, -1);
}
try {
const response = await fetch(nezhaBaseUrl + "/api/v1/server/details", {
headers: {
Authorization: process.env.NezhaAuth as string,
},
next: {
revalidate: 1,
},
});
const nezhaData = (await response.json()).result as NezhaAPI[];
const data: ServerApi = {
live_servers: 0,
offline_servers: 0,
total_bandwidth: 0,
result: [],
};
const timestamp = Date.now() / 1000;
data.result = nezhaData.map(
(element: MakeOptional<NezhaAPI, "ipv4" | "ipv6" | "valid_ip">) => {
if (timestamp - element.last_active > 300) {
data.offline_servers += 1;
element.online_status = false;
} else {
data.live_servers += 1;
element.online_status = true;
}
data.total_bandwidth += element.status.NetOutTransfer;
delete element.ipv4;
delete element.ipv6;
delete element.valid_ip;
return element;
},
);
return data;
} catch (error) {
return error;
}
}

View File

@ -6,16 +6,16 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs));
} }
export function formatNezhaInfo(timestamp: number, serverInfo: NezhaAPISafe) { export function formatNezhaInfo(serverInfo: NezhaAPISafe) {
return { return {
...serverInfo, ...serverInfo,
cpu: serverInfo.status.CPU, cpu: serverInfo.status.CPU,
up: serverInfo.status.NetOutSpeed / 1024 / 1024, up: serverInfo.status.NetOutSpeed / 1024 / 1024,
down: serverInfo.status.NetInSpeed / 1024 / 1024, down: serverInfo.status.NetInSpeed / 1024 / 1024,
online: timestamp - serverInfo.last_active > 300 ? "offline" : "online", online: serverInfo.online_status,
mem: (serverInfo.status.MemUsed / serverInfo.host.MemTotal) * 100, mem: (serverInfo.status.MemUsed / serverInfo.host.MemTotal) * 100,
stg: (serverInfo.status.DiskUsed / serverInfo.host.DiskTotal) * 100, stg: (serverInfo.status.DiskUsed / serverInfo.host.DiskTotal) * 100,
} };
} }
export function formatBytes(bytes: number, decimals: number = 2) { export function formatBytes(bytes: number, decimals: number = 2) {