feat: 支持免配置调试

This commit is contained in:
手瓜一十雪
2025-12-22 16:27:06 +08:00
parent 2a4ef581d7
commit c495ab5b46
11 changed files with 695 additions and 34 deletions

View File

@@ -19,6 +19,8 @@ export default function HttpDebug () {
const [backgroundImage] = useLocalStorage<string>(key.backgroundImage, '');
const hasBackground = !!backgroundImage;
const [adapterName, setAdapterName] = useState<string>('');
// Auto-collapse sidebar on mobile initial load
useEffect(() => {
if (window.innerWidth < 768) {
@@ -26,6 +28,37 @@ export default function HttpDebug () {
}
}, []);
// Initialize Debug Adapter
useEffect(() => {
let currentAdapterName = '';
const initAdapter = async () => {
try {
const response = await fetch('/api/Debug/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
});
const data = await response.json();
if (data.code === 0) {
currentAdapterName = data.data.adapterName;
setAdapterName(currentAdapterName);
}
} catch (error) {
console.error('Failed to create debug adapter:', error);
}
};
initAdapter();
return () => {
// 不再主动关闭 adapter由后端自动管理活跃状态
};
}, []);
const handleSelectApi = (api: OneBotHttpApiPath) => {
if (!openApis.includes(api)) {
setOpenApis([...openApis, api]);
@@ -149,7 +182,11 @@ export default function HttpDebug () {
api === activeApi ? 'opacity-100 z-10' : 'opacity-0 z-0 pointer-events-none'
)}
>
<OneBotApiDebug path={api} data={oneBotHttpApi[api]} />
<OneBotApiDebug
path={api}
data={oneBotHttpApi[api]}
adapterName={adapterName}
/>
</div>
))}
</div>

View File

@@ -3,9 +3,9 @@ import { Card, CardBody } from '@heroui/card';
import { Input } from '@heroui/input';
import { useLocalStorage } from '@uidotdev/usehooks';
import clsx from 'clsx';
import { useCallback, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import toast from 'react-hot-toast';
import { IoFlash, IoFlashOff } from 'react-icons/io5';
import { IoFlash, IoFlashOff, IoRefresh } from 'react-icons/io5';
import key from '@/const/key';
@@ -33,13 +33,68 @@ export default function WSDebug () {
const { sendMessage, readyState, FilterMessagesType, filteredMessages, clearMessages } =
useWebSocketDebug(socketConfig.url, socketConfig.token, shouldConnect);
// Auto fetch adapter and set URL
useEffect(() => {
// 检查是否应该覆盖 URL
const isDefaultUrl = socketConfig.url === defaultWsUrl || socketConfig.url === '';
const isWebDebugUrl = socketConfig.url && socketConfig.url.includes('/api/Debug/ws');
if (!isDefaultUrl && !isWebDebugUrl) {
setInputUrl(socketConfig.url);
setInputToken(socketConfig.token);
return; // 已经有自定义/有效的配置,跳过自动创建
}
const initAdapter = async () => {
try {
const response = await fetch('/api/Debug/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
}
});
const data = await response.json();
if (data.code === 0) {
//const adapterName = data.data.adapterName;
const token = data.data.token;
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
if (token) {
// URL 中不再包含 TokenToken 单独放入输入框
const wsUrl = `${protocol}//${window.location.host}/api/Debug/ws`;
setSocketConfig({
url: wsUrl,
token: token
});
setInputUrl(wsUrl);
setInputToken(token);
}
}
} catch (error) {
console.error('Failed to create debug adapter:', error);
}
};
initAdapter();
}, []);
const handleConnect = useCallback(() => {
if (!inputUrl.startsWith('ws://') && !inputUrl.startsWith('wss://')) {
// 允许以 / 开头的相对路径(如代理情况),以及标准的 ws/wss
let finalUrl = inputUrl;
if (finalUrl.startsWith('/')) {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
finalUrl = `${protocol}//${window.location.host}${finalUrl}`;
}
if (!finalUrl.startsWith('ws://') && !finalUrl.startsWith('wss://')) {
toast.error('WebSocket URL 不合法');
return;
}
setSocketConfig({
url: inputUrl,
url: finalUrl,
token: inputToken,
});
setShouldConnect(true);
@@ -49,6 +104,12 @@ export default function WSDebug () {
setShouldConnect(false);
}, []);
const handleResetConfig = useCallback(() => {
setSocketConfig({ url: '', token: '' });
// 刷新页面以重新触发初始逻辑
window.location.reload();
}, [setSocketConfig]);
return (
<>
<title>Websocket调试 - NapCat WebUI</title>
@@ -101,16 +162,29 @@ export default function WSDebug () {
input: hasBackground ? 'text-white placeholder:text-white/50' : '',
}}
/>
<Button
onPress={shouldConnect ? handleDisconnect : handleConnect}
size='md'
radius='full'
color={shouldConnect ? 'danger' : 'primary'}
className='font-bold shadow-lg min-w-[100px]'
startContent={shouldConnect ? <IoFlashOff /> : <IoFlash />}
>
{shouldConnect ? '断开' : '连接'}
</Button>
<div className="flex gap-2">
<Button
isIconOnly
size="md"
radius="full"
color="warning"
variant="flat"
onPress={handleResetConfig}
title="重置配置"
>
<IoRefresh className="text-xl" />
</Button>
<Button
onPress={shouldConnect ? handleDisconnect : handleConnect}
size='md'
radius='full'
color={shouldConnect ? 'danger' : 'primary'}
className='font-bold shadow-lg min-w-[100px] flex-1'
startContent={shouldConnect ? <IoFlashOff /> : <IoFlash />}
>
{shouldConnect ? '断开' : '连接'}
</Button>
</div>
</div>
{/* Status Bar */}