feat(widget): add minecraft server status widget (#1801)

This commit is contained in:
Meier Lukas
2024-12-31 09:45:48 +01:00
committed by GitHub
parent b8a155dd08
commit 0ebf4bc55e
13 changed files with 248 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
import type { Duration } from "dayjs/plugin/duration";
import type { WidgetKind } from "@homarr/definitions";
import { createWidgetOptionsChannel } from "@homarr/redis";
import { createCachedRequestHandler } from "./cached-request-handler";
interface Options<TData, TKind extends WidgetKind, TInput extends Record<string, unknown>> {
// Unique key for this request handler
queryKey: string;
requestAsync: (input: TInput) => Promise<TData>;
cacheDuration: Duration;
widgetKind: TKind;
}
export const createCachedWidgetRequestHandler = <
TData,
TKind extends WidgetKind,
TInput extends Record<string, unknown>,
>(
requestHandlerOptions: Options<TData, TKind, TInput>,
) => {
return {
handler: (widgetOptions: TInput) =>
createCachedRequestHandler({
queryKey: requestHandlerOptions.queryKey,
requestAsync: async (input: TInput) => {
return await requestHandlerOptions.requestAsync(input);
},
cacheDuration: requestHandlerOptions.cacheDuration,
createRedisChannel(input, options) {
return createWidgetOptionsChannel<TData>(requestHandlerOptions.widgetKind, options.queryKey, input);
},
}).handler(widgetOptions),
};
};

View File

@@ -0,0 +1,35 @@
import dayjs from "dayjs";
import { z } from "zod";
import { fetchWithTimeout } from "@homarr/common";
import { createCachedWidgetRequestHandler } from "./lib/cached-widget-request-handler";
export const minecraftServerStatusRequestHandler = createCachedWidgetRequestHandler({
queryKey: "minecraftServerStatusApiResult",
widgetKind: "minecraftServerStatus",
async requestAsync(input: { domain: string; isBedrockServer: boolean }) {
const path = `/3/${input.isBedrockServer ? "bedrock/" : ""}${input.domain}`;
const response = await fetchWithTimeout(`https://api.mcsrvstat.us${path}`);
return responseSchema.parse(await response.json());
},
cacheDuration: dayjs.duration(5, "minutes"),
});
const responseSchema = z
.object({
online: z.literal(false),
})
.or(
z.object({
online: z.literal(true),
players: z.object({
online: z.number(),
max: z.number(),
}),
icon: z.string().optional(),
}),
);
export type MinecraftServerStatus = z.infer<typeof responseSchema>;