🧑💻 feat: Add telegram api debugging capabilities
This commit is contained in:
parent
2454da15ff
commit
23c5758e0f
9 changed files with 394 additions and 42 deletions
|
|
@ -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<String, Class<TdApi.Function<?>>> 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) {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,10 @@ public class TdApiHelp {
|
|||
});
|
||||
}
|
||||
|
||||
public static Map<String, Class<TdApi.Function<?>>> getFunctions() {
|
||||
return FUNCTIONS;
|
||||
}
|
||||
|
||||
public static TdApi.Function<?> getFunction(String method, Object params) {
|
||||
Class<TdApi.Function<?>> func = FUNCTIONS.get(method);
|
||||
if (func == null) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
300
web/src/components/debug-telegram-method.tsx
Normal file
300
web/src/components/debug-telegram-method.tsx
Normal file
|
|
@ -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<string, any>;
|
||||
}
|
||||
|
||||
export default function DebugTelegramMethod() {
|
||||
const { triggerMethod, isMethodExecuting, lastMethodCode, lastMethodResult } =
|
||||
useTelegramMethod();
|
||||
const [isDeMethodExecuting] = useDebounce(isMethodExecuting, 500, {
|
||||
leading: true,
|
||||
});
|
||||
const [, copyToClipboard] = useCopyToClipboard();
|
||||
const [method, setMethod] = useState<string>("");
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const [parameters, setParameters] = useState<any>({});
|
||||
const [parametersJson, setParametersJson] = useState<string>("");
|
||||
const [error, setError] = useState<string>("");
|
||||
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 (
|
||||
<Card className="mx-auto h-full w-full overflow-y-scroll">
|
||||
<CardHeader>
|
||||
<CardTitle>Telegram API Debug</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
{/* Method Selection */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium">Method</label>
|
||||
{isMethodsLoading && (
|
||||
<div className="flex items-center text-sm text-muted-foreground">
|
||||
<Loader2 className="mr-2 h-3 w-3 animate-spin" />
|
||||
Loading methods...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className="w-full justify-between"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{method ? method : "Select a method..."}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0" modal={true} align="start">
|
||||
<Command shouldFilter={false}>
|
||||
<CommandInput
|
||||
placeholder="Search method..."
|
||||
value={searchQuery}
|
||||
onValueChange={setSearchQuery}
|
||||
/>
|
||||
<CommandList className="relative">
|
||||
{isMethodsLoading && (
|
||||
<CommandLoading>
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-2 -translate-y-2 transform">
|
||||
<Ellipsis className="h-4 w-4 animate-pulse" />
|
||||
</div>
|
||||
</CommandLoading>
|
||||
)}
|
||||
{!isMethodsLoading && filteredMethods.length === 0 && (
|
||||
<CommandEmpty>No methods found.</CommandEmpty>
|
||||
)}
|
||||
{!isMethodExecuting && searchQuery.length === 0 && (
|
||||
<>
|
||||
<CommandGroup>
|
||||
<CommandItem disabled={true}>
|
||||
<CircleAlert className="h-3 w-3" />
|
||||
Only the first 100 methods are shown.
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
</>
|
||||
)}
|
||||
<CommandGroup>
|
||||
{filteredMethods.map((m) => (
|
||||
<CommandItem
|
||||
key={m}
|
||||
value={m}
|
||||
onSelect={handleMethodChange}
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"h-4 w-4",
|
||||
method === m ? "opacity-100" : "opacity-0",
|
||||
)}
|
||||
/>
|
||||
{m}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
{method && (
|
||||
<Link
|
||||
href={methodDocUrl}
|
||||
target="_blank"
|
||||
className="text-xs text-blue-500 underline"
|
||||
>
|
||||
{method} Documentation
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Parameters Editor */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium">Parameters</label>
|
||||
{isParametersLoading && (
|
||||
<div className="flex items-center text-sm text-muted-foreground">
|
||||
<Loader2 className="mr-2 h-3 w-3 animate-spin" />
|
||||
Loading parameters...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Textarea
|
||||
value={parametersJson}
|
||||
onChange={(e) => handleParametersChange(e.target.value)}
|
||||
placeholder="Enter parameters in JSON format"
|
||||
className="h-48 font-mono text-sm"
|
||||
disabled={!method || isLoading}
|
||||
/>
|
||||
{error && <p className="mt-1 text-sm text-red-500">{error}</p>}
|
||||
</div>
|
||||
|
||||
{/* Execute Button */}
|
||||
<Button
|
||||
onClick={handleExecute}
|
||||
disabled={isExecuteDisabled}
|
||||
className="w-full"
|
||||
>
|
||||
{isDeMethodExecuting ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Executing...
|
||||
</>
|
||||
) : (
|
||||
"Execute Method"
|
||||
)}
|
||||
</Button>
|
||||
|
||||
{/* Result Display */}
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium">
|
||||
Result
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{lastMethodCode ? `(${lastMethodCode})` : ""}
|
||||
</span>
|
||||
</label>
|
||||
{isMethodExecuting && (
|
||||
<div className="flex items-center text-sm text-muted-foreground">
|
||||
<Loader2 className="mr-2 h-3 w-3 animate-spin" />
|
||||
Processing...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="group relative">
|
||||
<Textarea
|
||||
value={
|
||||
lastMethodResult
|
||||
? JSON.stringify(lastMethodResult, null, 2)
|
||||
: ""
|
||||
}
|
||||
readOnly
|
||||
placeholder="Method execution result will appear here"
|
||||
className="h-48 font-mono text-sm"
|
||||
/>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
if (!lastMethodResult) return;
|
||||
copyToClipboard(JSON.stringify(lastMethodResult, null, 2));
|
||||
}}
|
||||
className="absolute right-2 top-2 opacity-0 group-hover:opacity-100"
|
||||
>
|
||||
<Copy className="h-2 w-2" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
|
@ -33,30 +33,6 @@ export default function FileProgress({
|
|||
|
||||
return (
|
||||
<div className="flex items-end justify-between gap-2">
|
||||
{/*<div className="hidden min-w-20 md:flex">*/}
|
||||
{/* <div className="group flex items-center gap-1 px-1">*/}
|
||||
{/* <AnimatePresence mode="wait">*/}
|
||||
{/* <motion.div*/}
|
||||
{/* key="content"*/}
|
||||
{/* className="flex items-center gap-1"*/}
|
||||
{/* initial={{ opacity: 1 }}*/}
|
||||
{/* exit={{ opacity: 0 }}*/}
|
||||
{/* >*/}
|
||||
{/* <Zap className="h-3 w-3 group-hover:hidden" />*/}
|
||||
{/* <ClockArrowDown className="hidden h-3 w-3 group-hover:block" />*/}
|
||||
{/* <span className="text-nowrap text-xs">*/}
|
||||
{/* <span className="group-hover:hidden">*/}
|
||||
{/* {`${prettyBytes(downloadSpeed, { bits: true })}/s`}*/}
|
||||
{/* </span>*/}
|
||||
{/* <span className="hidden group-hover:inline">*/}
|
||||
{/* {prettyBytes(file.downloadedSize)}*/}
|
||||
{/* </span>*/}
|
||||
{/* </span>*/}
|
||||
{/* </motion.div>*/}
|
||||
{/* </AnimatePresence>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
<Progress value={progress} className="flex-1 rounded-none md:w-32" />
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import About from "@/components/about";
|
|||
import { ChartColumnIncreasingIcon } from "@/components/ui/chart-column-increasing";
|
||||
import { LayoutPanelTopIcon } from "@/components/ui/layout-panel-top";
|
||||
import FilePhaseStatistics from "@/components/file-phase-statistics";
|
||||
import DebugTelegramMethod from "@/components/debug-telegram-method";
|
||||
|
||||
export const SettingsDialog: React.FC = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
|
@ -50,6 +51,7 @@ export const SettingsDialog: React.FC = () => {
|
|||
<TabsTrigger value="general">General</TabsTrigger>
|
||||
<TabsTrigger value="statistics">Statistics</TabsTrigger>
|
||||
<TabsTrigger value="proxys">Proxys</TabsTrigger>
|
||||
<TabsTrigger value="api">API</TabsTrigger>
|
||||
<TabsTrigger value="about">About</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="general" className="overflow-hidden">
|
||||
|
|
@ -60,10 +62,16 @@ export const SettingsDialog: React.FC = () => {
|
|||
{accountId ? (
|
||||
<Tabs defaultValue="panel">
|
||||
<TabsList className="bg-none!">
|
||||
<TabsTrigger value="panel" className="w-10 h-10 scale-75 data-[state=active]:bg-accent">
|
||||
<TabsTrigger
|
||||
value="panel"
|
||||
className="h-10 w-10 scale-75 data-[state=active]:bg-accent"
|
||||
>
|
||||
<LayoutPanelTopIcon />
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="phase" className="w-10 h-10 scale-75 data-[state=active]:bg-accent">
|
||||
<TabsTrigger
|
||||
value="phase"
|
||||
className="h-10 w-10 scale-75 data-[state=active]:bg-accent"
|
||||
>
|
||||
<ChartColumnIncreasingIcon />
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
|
@ -92,6 +100,9 @@ export const SettingsDialog: React.FC = () => {
|
|||
/>
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="api" className="h-full overflow-hidden">
|
||||
<DebugTelegramMethod />
|
||||
</TabsContent>
|
||||
<TabsContent value="about" className="h-full overflow-hidden">
|
||||
<About />
|
||||
</TabsContent>
|
||||
|
|
|
|||
|
|
@ -13,21 +13,33 @@ const PopoverAnchor = PopoverPrimitive.Anchor;
|
|||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
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",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
));
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {
|
||||
modal?: boolean;
|
||||
}
|
||||
>(
|
||||
(
|
||||
{ className, align = "center", sideOffset = 4, modal = false, ...props },
|
||||
ref,
|
||||
) => {
|
||||
const content = (
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
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",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
return !modal ? (
|
||||
<PopoverPrimitive.Portal>{content}</PopoverPrimitive.Portal>
|
||||
) : (
|
||||
content
|
||||
);
|
||||
},
|
||||
);
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
|
||||
|
|
|
|||
22
web/src/components/ui/textarea.tsx
Normal file
22
web/src/components/ui/textarea.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const Textarea = React.forwardRef<
|
||||
HTMLTextAreaElement,
|
||||
React.ComponentProps<"textarea">
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
Textarea.displayName = "Textarea";
|
||||
|
||||
export { Textarea };
|
||||
|
|
@ -5,8 +5,10 @@ import { useEffect, useMemo, useState } from "react";
|
|||
import { useWebsocket } from "@/hooks/use-websocket";
|
||||
|
||||
export function useTelegramMethod() {
|
||||
const [lastMethodCode, setLastMethodCode] = useState<string>();
|
||||
const [methodCodes, setMethodCodes] = useState<string[]>([]);
|
||||
const [methodCompleteCodes, setMethodCompleteCodes] = useState<string[]>([]);
|
||||
const [lastMethodResult, setLastMethodResult] = useState<unknown>();
|
||||
const { lastJsonMessage } = useWebsocket();
|
||||
|
||||
const { trigger: triggerMethod, isMutating: isMethodMutating } =
|
||||
|
|
@ -15,6 +17,7 @@ export function useTelegramMethod() {
|
|||
telegramApi,
|
||||
{
|
||||
onSuccess: (data) => {
|
||||
setLastMethodCode(data.code);
|
||||
setMethodCodes((prev) => [...prev, data.code]);
|
||||
},
|
||||
},
|
||||
|
|
@ -24,6 +27,7 @@ export function useTelegramMethod() {
|
|||
if (!lastJsonMessage) return;
|
||||
if (lastJsonMessage.code) {
|
||||
setMethodCompleteCodes((prev) => [...prev, lastJsonMessage.code]);
|
||||
setLastMethodResult(lastJsonMessage.data)
|
||||
}
|
||||
}, [lastJsonMessage]);
|
||||
|
||||
|
|
@ -37,5 +41,7 @@ export function useTelegramMethod() {
|
|||
return {
|
||||
triggerMethod,
|
||||
isMethodExecuting,
|
||||
lastMethodCode,
|
||||
lastMethodResult,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue