fix: 修复proxy_service和account_service中不当的顶层import
- proxy_service.py: 将requests和WhitelistManager改为函数内延迟import, 避免启动时加载不需要的依赖;移除未使用的get_exit_ip_via_proxy导入 - account_service.py: 移除未使用的func、joinedload、AuditLog、 user_has_permission顶层导入
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
export interface RealtimeLog {
|
||||
level: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface ConnectOptions {
|
||||
clear?: boolean;
|
||||
onClose?: () => void;
|
||||
onError?: () => void;
|
||||
onResult?: () => void;
|
||||
}
|
||||
|
||||
function toWebSocketUrl(pathOrUrl: string): string {
|
||||
if (pathOrUrl.startsWith('ws://') || pathOrUrl.startsWith('wss://')) {
|
||||
return pathOrUrl;
|
||||
}
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const path = pathOrUrl.startsWith('/') ? pathOrUrl : `/${pathOrUrl}`;
|
||||
return `${protocol}://${window.location.host}${path}`;
|
||||
}
|
||||
|
||||
export function useWebSocketLogs() {
|
||||
const [logs, setLogs] = useState<RealtimeLog[]>([]);
|
||||
const [connected, setConnected] = useState(false);
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const callbacksRef = useRef<ConnectOptions>({});
|
||||
const suppressCloseRef = useRef(false);
|
||||
|
||||
const clearLogs = useCallback(() => {
|
||||
setLogs([]);
|
||||
}, []);
|
||||
|
||||
const close = useCallback((notify = false) => {
|
||||
if (!wsRef.current) {
|
||||
setConnected(false);
|
||||
return;
|
||||
}
|
||||
suppressCloseRef.current = !notify;
|
||||
wsRef.current.close();
|
||||
wsRef.current = null;
|
||||
setConnected(false);
|
||||
}, []);
|
||||
|
||||
const connect = useCallback((pathOrUrl: string, options: ConnectOptions = {}) => {
|
||||
close(false);
|
||||
suppressCloseRef.current = false;
|
||||
callbacksRef.current = options;
|
||||
if (options.clear ?? true) {
|
||||
setLogs([]);
|
||||
}
|
||||
|
||||
const ws = new WebSocket(toWebSocketUrl(pathOrUrl));
|
||||
wsRef.current = ws;
|
||||
setConnected(true);
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const msg = JSON.parse(event.data) as RealtimeLog;
|
||||
if (msg.level === 'heartbeat') return;
|
||||
if (msg.level === 'result') {
|
||||
callbacksRef.current.onResult?.();
|
||||
return;
|
||||
}
|
||||
setLogs((prev) => [...prev, msg]);
|
||||
} catch {
|
||||
setLogs((prev) => [...prev, { level: 'info', message: String(event.data) }]);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
const isCurrent = wsRef.current === ws;
|
||||
const shouldNotify = isCurrent && !suppressCloseRef.current;
|
||||
if (isCurrent) {
|
||||
wsRef.current = null;
|
||||
setConnected(false);
|
||||
suppressCloseRef.current = false;
|
||||
}
|
||||
if (shouldNotify) {
|
||||
callbacksRef.current.onClose?.();
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = () => {
|
||||
setConnected(false);
|
||||
callbacksRef.current.onError?.();
|
||||
};
|
||||
}, [close]);
|
||||
|
||||
useEffect(() => () => {
|
||||
close(false);
|
||||
}, [close]);
|
||||
|
||||
return {
|
||||
logs,
|
||||
connected,
|
||||
clearLogs,
|
||||
connect,
|
||||
close,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user