From 23c5758e0fecc53d67ea477fef710fd78de4152d Mon Sep 17 00:00:00 2001 From: jarvis2f <137974272+jarvis2f@users.noreply.github.com> Date: Sat, 11 Jan 2025 22:51:15 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20feat:=20Add?= =?UTF-8?q?=20telegram=20api=20debugging=20capabilities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/telegram/files/HttpVerticle.java | 15 +- .../main/java/telegram/files/TdApiHelp.java | 4 + request.http | 8 + web/src/components/debug-telegram-method.tsx | 300 ++++++++++++++++++ web/src/components/file-progress.tsx | 24 -- web/src/components/settings-dialog.tsx | 15 +- web/src/components/ui/popover.tsx | 42 ++- web/src/components/ui/textarea.tsx | 22 ++ web/src/hooks/use-telegram-method.tsx | 6 + 9 files changed, 394 insertions(+), 42 deletions(-) create mode 100644 web/src/components/debug-telegram-method.tsx create mode 100644 web/src/components/ui/textarea.tsx diff --git a/api/src/main/java/telegram/files/HttpVerticle.java b/api/src/main/java/telegram/files/HttpVerticle.java index 3bc35ee..01138da 100644 --- a/api/src/main/java/telegram/files/HttpVerticle.java +++ b/api/src/main/java/telegram/files/HttpVerticle.java @@ -24,6 +24,7 @@ import io.vertx.ext.web.handler.CorsHandler; import io.vertx.ext.web.handler.SessionHandler; import io.vertx.ext.web.sstore.LocalSessionStore; import io.vertx.ext.web.sstore.SessionStore; +import org.drinkless.tdlib.TdApi; import telegram.files.repository.SettingKey; import telegram.files.repository.SettingRecord; import telegram.files.repository.TelegramRecord; @@ -130,6 +131,8 @@ public class HttpVerticle extends AbstractVerticle { router.post("/telegram/create").handler(this::handleTelegramCreate); router.post("/telegram/:telegramId/delete").handler(this::handleTelegramDelete); + router.get("/telegram/api/methods").handler(this::handleTelegramApiMethods); + router.get("/telegram/api/:method/parameters").handler(this::handleTelegramApiMethodParameters); router.post("/telegram/api/:method").handler(this::handleTelegramApi); router.get("/telegrams").handler(this::handleTelegrams); router.get("/telegram/:telegramId/chats").handler(this::handleTelegramChats); @@ -415,7 +418,7 @@ public class HttpVerticle extends AbstractVerticle { String type = ctx.request().getParam("type"); String timeRange = ctx.request().getParam("timeRange"); - (Objects.equals(type, "phase") ? telegramVerticle. getDownloadStatisticsByPhase(Convert.toInt(timeRange, 1)) : + (Objects.equals(type, "phase") ? telegramVerticle.getDownloadStatisticsByPhase(Convert.toInt(timeRange, 1)) : telegramVerticle.getDownloadStatistics()) .onSuccess(ctx::json) .onFailure(ctx::fail); @@ -459,6 +462,16 @@ public class HttpVerticle extends AbstractVerticle { ); } + private void handleTelegramApiMethods(RoutingContext ctx) { + Map>> functions = TdApiHelp.getFunctions(); + ctx.json(JsonObject.of("methods", functions.keySet())); + } + + private void handleTelegramApiMethodParameters(RoutingContext ctx) { + String method = ctx.pathParam("method"); + ctx.json(JsonObject.of("parameters", TdApiHelp.getFunction(method, null))); + } + private void handleTelegramApi(RoutingContext ctx) { String method = ctx.pathParam("method"); if (method == null) { diff --git a/api/src/main/java/telegram/files/TdApiHelp.java b/api/src/main/java/telegram/files/TdApiHelp.java index 84cac3b..95515be 100644 --- a/api/src/main/java/telegram/files/TdApiHelp.java +++ b/api/src/main/java/telegram/files/TdApiHelp.java @@ -71,6 +71,10 @@ public class TdApiHelp { }); } + public static Map>> getFunctions() { + return FUNCTIONS; + } + public static TdApi.Function getFunction(String method, Object params) { Class> func = FUNCTIONS.get(method); if (func == null) { diff --git a/request.http b/request.http index c381fa0..b8d71b1 100644 --- a/request.http +++ b/request.http @@ -80,6 +80,14 @@ Cookie: {{tf}} GET http://{{server}}/telegram/{{telegramId}}/download-statistics?type=phase&timeRange=3 Cookie: {{tf}} +### Telegram api methods +GET http://{{server}}/telegram/api/methods +Cookie: {{tf}} + +### Telegram api method parameters +GET http://{{server}}/telegram/api/GetChats/parameters +Cookie: {{tf}} + ### Telegram GetMe POST http://{{server}}/telegram/api/GetMe Content-Type: application/json diff --git a/web/src/components/debug-telegram-method.tsx b/web/src/components/debug-telegram-method.tsx new file mode 100644 index 0000000..7e5ba31 --- /dev/null +++ b/web/src/components/debug-telegram-method.tsx @@ -0,0 +1,300 @@ +import { useTelegramMethod } from "@/hooks/use-telegram-method"; +import useSWR from "swr"; +import { request } from "@/lib/api"; +import { useMemo, useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, +} from "@/components/ui/command"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { Textarea } from "@/components/ui/textarea"; +import { + Check, + ChevronsUpDown, + CircleAlert, + Copy, + Ellipsis, + Loader2, +} from "lucide-react"; +import { cn } from "@/lib/utils"; +import { CommandLoading } from "cmdk"; +import { useDebounce } from "use-debounce"; +import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard"; +import Link from "next/link"; + +interface TelegramMethodData { + methods: string[]; +} + +interface TelegramMethodParameters { + parameters: Record; +} + +export default function DebugTelegramMethod() { + const { triggerMethod, isMethodExecuting, lastMethodCode, lastMethodResult } = + useTelegramMethod(); + const [isDeMethodExecuting] = useDebounce(isMethodExecuting, 500, { + leading: true, + }); + const [, copyToClipboard] = useCopyToClipboard(); + const [method, setMethod] = useState(""); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const [parameters, setParameters] = useState({}); + const [parametersJson, setParametersJson] = useState(""); + const [error, setError] = useState(""); + const [open, setOpen] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); + + const { data: methodData, isLoading: isMethodsLoading } = useSWR< + TelegramMethodData, + Error + >("/telegram/api/methods", request, { + // 添加缓存以提升性能 + revalidateOnFocus: false, + revalidateOnReconnect: false, + dedupingInterval: 60000, + }); + + // 使用 useMemo 缓存过滤后的方法列表 + const filteredMethods = useMemo(() => { + if (!methodData?.methods || isMethodsLoading) return []; + + return methodData.methods + .filter((m) => m.toLowerCase().includes(searchQuery.toLowerCase())) + .slice(0, 100) + .sort(); + }, [isMethodsLoading, methodData?.methods, searchQuery]); + + const methodDocUrl = useMemo(() => { + if (!method) return ""; + const methodSlug = method.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase(); + return `https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1${methodSlug}.html`; + }, [method]); + + const { isLoading: isParametersLoading } = useSWR< + TelegramMethodParameters, + Error + >(method ? `/telegram/api/${method}/parameters` : null, request, { + revalidateOnFocus: false, + onSuccess: (data) => { + const defaultParams = data.parameters; + setParameters(defaultParams); + setParametersJson(JSON.stringify(defaultParams, null, 2)); + }, + }); + + const handleMethodChange = (value: string) => { + setMethod(value); + setError(""); + setOpen(false); + }; + + const handleParametersChange = (value: string) => { + setParametersJson(value); + try { + setParameters(JSON.parse(value)); + setError(""); + } catch (e) { + setError("Invalid JSON format"); + } + }; + + const handleExecute = async () => { + try { + await triggerMethod({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + data: parameters, + method, + }); + setError(""); + } catch (e) { + setError(e instanceof Error ? e.message : "An error occurred"); + } + }; + + const isLoading = isMethodsLoading || isParametersLoading; + const isExecuteDisabled = !method || !!error || isMethodExecuting; + + return ( + + + Telegram API Debug + + + {/* Method Selection */} +
+
+ + {isMethodsLoading && ( +
+ + Loading methods... +
+ )} +
+ + + + + + + + + {isMethodsLoading && ( + +
+ +
+
+ )} + {!isMethodsLoading && filteredMethods.length === 0 && ( + No methods found. + )} + {!isMethodExecuting && searchQuery.length === 0 && ( + <> + + + + Only the first 100 methods are shown. + + + + + )} + + {filteredMethods.map((m) => ( + + + {m} + + ))} + +
+
+
+
+ {method && ( + + {method} Documentation + + )} +
+ + {/* Parameters Editor */} +
+
+ + {isParametersLoading && ( +
+ + Loading parameters... +
+ )} +
+