diff --git a/UPDATELOG.md b/UPDATELOG.md index 958ea3f8..70f4e527 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -51,7 +51,6 @@ - 添加了Zashboard的一键跳转URL - 使用操作系统默认的窗口管理器 - 切换、升级、重启内核的状态管理 - - 增加了一键随机API端口和密钥/单独刷新按钮(待优化) - 更精细化控制自动日志清理,新增1天选项。 #### 优化了: @@ -78,7 +77,6 @@ - 异步化配置:优化端口查找和配置保存逻辑 - 重构事件通知机制到独立线程,避免前端卡死 - 优化端口设置,每个端口可随机设置端口号 - - 优化了随机端口和密钥机制,防止随机时卡死! - 优化了保存机制,使用平滑函数,防止客户端卡死! - 优化端口设置退出和保存机制! - 强制为 Mihomo 配置补全并覆盖 external-controller-cors 字段,默认不允许跨域和仅本地请求,提升 cors 安全性,升级配置时自动覆盖。 diff --git a/src/components/setting/mods/controller-viewer.tsx b/src/components/setting/mods/controller-viewer.tsx index 777b400b..4724355b 100644 --- a/src/components/setting/mods/controller-viewer.tsx +++ b/src/components/setting/mods/controller-viewer.tsx @@ -1,118 +1,45 @@ import { BaseDialog, DialogRef } from "@/components/base"; import { useClashInfo } from "@/hooks/use-clash"; -import { useVerge } from "@/hooks/use-verge"; -import { patchClashConfig, restartCore } from "@/services/cmds"; +import { patchClashConfig } from "@/services/cmds"; import { showNotice } from "@/services/noticeService"; -import { - ContentCopy, - RefreshRounded, -} from "@mui/icons-material"; +import { ContentCopy } from "@mui/icons-material"; import { Alert, Box, CircularProgress, - FormControlLabel, IconButton, List, ListItem, ListItemText, Snackbar, - Switch, TextField, Tooltip } from "@mui/material"; -import { useLocalStorageState, useLockFn } from "ahooks"; +import { useLockFn } from "ahooks"; import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; import { useTranslation } from "react-i18next"; -// 随机端口和密码生成 -const generateRandomPort = (): number => { - return Math.floor(Math.random() * (65535 - 1024 + 1)) + 1024; -}; - -const generateRandomPassword = (length: number = 32): string => { - const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - let password = ""; - - for (let i = 0; i < length; i++) { - const randomIndex = Math.floor(Math.random() * charset.length); - password += charset.charAt(randomIndex); - } - - return password; -}; - export const ControllerViewer = forwardRef((props, ref) => { const { t } = useTranslation(); const [open, setOpen] = useState(false); - - // 防止数值null - const [autoGenerateState, setAutoGenerate] = useLocalStorageState( - 'autoGenerateConfig', - { defaultValue: false as boolean } - ); - const autoGenerate = autoGenerateState!; - const [copySuccess, setCopySuccess] = useState(null); const [isSaving, setIsSaving] = useState(false); const { clashInfo, patchInfo } = useClashInfo(); - const [controller, setController] = useState(clashInfo?.server || ""); const [secret, setSecret] = useState(clashInfo?.secret || ""); - - // 生成随机配置并重启内核 - const generateAndRestart = useLockFn(async () => { - try { - setIsRestarting(true); - - const port = generateRandomPort(); - const password = generateRandomPassword(); - - const host = controller.split(':')[0] || '127.0.0.1'; - const newController = `${host}:${port}`; - - setController(newController); - setSecret(password); - - // 更新配置 - await patchInfo({ "external-controller": newController, secret: password }); - - // 直接重启内核 - await restartCoreDirectly(); - - // 静默执行,不显示通知 - } catch (err: any) { - showNotice('error', err.message || t("Failed to generate configuration or restart core"), 4000); - } finally { - setIsRestarting(false); - } - }); - - // 仅在对话框打开时生成配置 + // 对话框打开时初始化配置 useImperativeHandle(ref, () => ({ open: async () => { setOpen(true); - - if (autoGenerate) { - await generateAndRestart(); - } else { - setController(clashInfo?.server || ""); - setSecret(clashInfo?.secret || ""); - } + setController(clashInfo?.server || ""); + setSecret(clashInfo?.secret || ""); }, close: () => setOpen(false), })); - // 当自动生成开关状态变化时触发 - useEffect(() => { - if (autoGenerate && open) { - generateAndRestart(); - } - }, [autoGenerate, open]); - - // 保存函数(优化) + // 保存配置 const onSave = useLockFn(async () => { if (!controller.trim()) { showNotice('info', t("Controller address cannot be empty"), 3000); @@ -121,15 +48,8 @@ export const ControllerViewer = forwardRef((props, ref) => { try { setIsSaving(true); - - await patchInfo({ - "external-controller": controller, - secret, - }); - - await restartCore(); - - showNotice('success', t("Configuration saved and core restarted successfully"), 2000); + await patchInfo({ "external-controller": controller, secret }); + showNotice('success', t("Configuration saved successfully"), 2000); setOpen(false); } catch (err: any) { showNotice('error', err.message || t("Failed to save configuration"), 4000); @@ -138,27 +58,6 @@ export const ControllerViewer = forwardRef((props, ref) => { } }); - // 生成随机端口 - const handleGeneratePort = useLockFn(async () => { - if (!autoGenerate) { - const port = generateRandomPort(); - const host = controller.split(':')[0] || '127.0.0.1'; - setController(`${host}:${port}`); - showNotice('success', t("Random port generated"), 1000); - } - return Promise.resolve(); - }); - - // 生成随机 Secret - const handleGenerateSecret = useLockFn(async () => { - if (!autoGenerate) { - const password = generateRandomPassword(); - setSecret(password); - showNotice('success', t("Random secret generated"), 1000); - } - return Promise.resolve(); - }); - // 复制到剪贴板 const handleCopyToClipboard = useLockFn(async (text: string, type: string) => { try { @@ -175,16 +74,14 @@ export const ControllerViewer = forwardRef((props, ref) => { open={open} title={t("External Controller")} contentSx={{ width: 400 }} - okBtn={ - isSaving ? ( - - - {t("Saving...")} - - ) : ( - t("Save") - ) - } + okBtn={isSaving ? ( + + + {t("Saving...")} + + ) : ( + t("Save") + )} cancelBtn={t("Cancel")} onClose={() => setOpen(false)} onCancel={() => setOpen(false)} @@ -192,106 +89,61 @@ export const ControllerViewer = forwardRef((props, ref) => { > - - - - - - - - + setController(e.target.value)} - disabled={autoGenerate || isSaving } + onChange={() => {}} + disabled={true} + inputProps={{ readOnly: true }} /> - {autoGenerate && ( - - handleCopyToClipboard(controller, "controller")} - color="primary" - disabled={isSaving } - > - - - - )} - - - - - - - + handleCopyToClipboard(controller, "controller")} color="primary" - disabled={autoGenerate || isSaving } + disabled={isSaving} > - + - - - setSecret(e.target.value?.replace(/[^\x00-\x7F]/g, "")) - } - disabled={autoGenerate || isSaving } - /> - {autoGenerate && ( - - handleCopyToClipboard(secret, "secret")} - color="primary" - disabled={isSaving } - > - - - - )} - - - setAutoGenerate(!autoGenerate)} + + + {}} + disabled={true} + inputProps={{ readOnly: true }} + /> + + handleCopyToClipboard(secret, "secret")} color="primary" - disabled={isSaving } - /> - } - label={autoGenerate ? t("On") : t("Off")} - labelPlacement="start" - /> + disabled={isSaving} + > + + + + @@ -300,10 +152,7 @@ export const ControllerViewer = forwardRef((props, ref) => { autoHideDuration={2000} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} > - + {copySuccess === "controller" ? t("Controller address copied to clipboard") : t("Secret copied to clipboard")