diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index a39bfc42842713069b8e05585a55542d2d76f6c5..4d30c8563703db3434868fc570f87a9b489d66c1 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -174,6 +174,13 @@ pub fn get_clash_info(core: State<'_, Core>) -> CmdResult<ClashInfo> { Ok(clash.info.clone()) } +/// get the running clash config string +#[tauri::command] +pub fn get_running_config(core: State<'_, Core>) -> CmdResult<Option<String>> { + let clash = core.clash.lock(); + Ok(clash.running_config.clone()) +} + /// update the clash core config /// after putting the change to the clash core /// then we should save the latest config diff --git a/src-tauri/src/core/clash.rs b/src-tauri/src/core/clash.rs index 5d88aaf5d850fd24e125921b1e8ab89945d3591a..92c078dede450dc4f875ead57a2c3700a97d23e3 100644 --- a/src-tauri/src/core/clash.rs +++ b/src-tauri/src/core/clash.rs @@ -87,6 +87,9 @@ pub struct Clash { /// some info pub info: ClashInfo, + + /// save the running config + pub running_config: Option<String>, } impl Clash { @@ -94,7 +97,11 @@ impl Clash { let config = Clash::read_config(); let info = ClashInfo::from(&config); - Clash { config, info } + Clash { + config, + info, + running_config: None, + } } /// get clash config @@ -111,6 +118,14 @@ impl Clash { ) } + /// save running config + pub fn set_running_config(&mut self, config: &Mapping) { + self.running_config = match serde_yaml::to_string(config) { + Ok(config_str) => Some(config_str), + Err(_) => None, + }; + } + /// patch update the clash config /// if the port is changed then return true pub fn patch_config(&mut self, patch: Mapping) -> Result<(bool, bool)> { diff --git a/src-tauri/src/core/mod.rs b/src-tauri/src/core/mod.rs index 893e26184539c83452d82a82070a734f01cce562..2d8da943c877d4f8b240f71faea070f1a7fd4380 100644 --- a/src-tauri/src/core/mod.rs +++ b/src-tauri/src/core/mod.rs @@ -347,12 +347,10 @@ impl Core { Clash::strict_filter(data) }; - let (mut config, info) = { - let clash = self.clash.lock(); - let config = clash.config.clone(); - let info = clash.info.clone(); - (config, info) - }; + let mut clash = self.clash.lock(); + + let mut config = clash.config.clone(); + let info = clash.info.clone(); for (key, value) in data.into_iter() { config.insert(key, value); @@ -369,6 +367,9 @@ impl Core { Notice::from(window.clone()) }; + clash.set_running_config(&config); + drop(clash); + let service = self.service.lock(); service.set_config(info, config, notice) } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 4010509ff7a95051eee7ae9436c42f6cc4a392be..28eeff3bf54348f231dbd1cc97ce718fb1dd0652 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -114,6 +114,7 @@ fn main() -> std::io::Result<()> { cmds::get_clash_info, cmds::patch_clash_config, cmds::change_clash_core, + cmds::get_running_config, // verge cmds::get_verge_config, cmds::patch_verge_config, diff --git a/src/components/setting/config-viewer.tsx b/src/components/setting/config-viewer.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4a5a6724b534d59da0ef89808e69392b41f43cf0 --- /dev/null +++ b/src/components/setting/config-viewer.tsx @@ -0,0 +1,75 @@ +import { useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useRecoilValue } from "recoil"; +import { + Button, + Chip, + Dialog, + DialogActions, + DialogContent, + DialogTitle, +} from "@mui/material"; +import { InfoRounded } from "@mui/icons-material"; +import { atomThemeMode } from "../../services/states"; +import { getRunningConfig } from "../../services/cmds"; + +import "monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js"; +import "monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js"; +import "monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js"; +import { editor } from "monaco-editor/esm/vs/editor/editor.api"; + +const ConfigViewer = () => { + const { t } = useTranslation(); + const [open, setOpen] = useState(false); + + const editorRef = useRef<any>(); + const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null); + const themeMode = useRecoilValue(atomThemeMode); + + useEffect(() => { + if (!open) return; + + getRunningConfig().then((data) => { + const dom = editorRef.current; + + if (!dom) return; + if (instanceRef.current) instanceRef.current.dispose(); + + instanceRef.current = editor.create(editorRef.current, { + value: data ?? "# Error\n", + language: "yaml", + theme: themeMode === "light" ? "vs" : "vs-dark", + minimap: { enabled: false }, + readOnly: true, + }); + }); + + return () => { + if (instanceRef.current) { + instanceRef.current.dispose(); + instanceRef.current = null; + } + }; + }, [open]); + + return ( + <> + <Dialog open={open} onClose={() => setOpen(false)}> + <DialogTitle> + {t("Running Config")} <Chip label="ReadOnly" size="small" /> + </DialogTitle> + + <DialogContent sx={{ width: 520, pb: 1 }}> + <div style={{ width: "100%", height: "420px" }} ref={editorRef} /> + </DialogContent> + + <DialogActions> + <Button onClick={() => setOpen(false)}>{t("Back")}</Button> + </DialogActions> + </Dialog> + + <InfoRounded fontSize="small" onClick={() => setOpen(true)} /> + </> + ); +}; +export default ConfigViewer; diff --git a/src/components/setting/setting-system.tsx b/src/components/setting/setting-system.tsx index bd3b9933c821758907612e4bff37fe27615d7029..36ffaced711fbec12b60bbb6742ee602750ac339 100644 --- a/src/components/setting/setting-system.tsx +++ b/src/components/setting/setting-system.tsx @@ -18,6 +18,7 @@ import { SettingList, SettingItem } from "./setting"; import { CmdType } from "../../services/types"; import GuardState from "./guard-state"; import ServiceMode from "./service-mode"; +import ConfigViewer from "./config-viewer"; import SysproxyTooltip from "./sysproxy-tooltip"; import getSystem from "../../utils/get-system"; @@ -58,7 +59,14 @@ const SettingSystem = ({ onError }: Props) => { return ( <SettingList title={t("System Setting")}> <SettingItem> - <ListItemText primary={t("Tun Mode")} /> + <ListItemText + primary={ + <Box sx={{ display: "flex", alignItems: "center" }}> + <span style={{ marginRight: 4 }}>{t("Tun Mode")}</span> + <ConfigViewer /> + </Box> + } + /> <GuardState value={enable_tun_mode ?? false} valueProps="checked" diff --git a/src/services/cmds.ts b/src/services/cmds.ts index fd7f99ad6ed2b6da63d773175cedc3cc4f8983ef..08b69870fb66bb9904f379b0cdd4fa40018977ef 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -70,6 +70,10 @@ export async function getClashInfo() { return invoke<CmdType.ClashInfo | null>("get_clash_info"); } +export async function getRunningConfig() { + return invoke<string | null>("get_running_config"); +} + export async function patchClashConfig(payload: Partial<ApiType.ConfigData>) { return invoke<void>("patch_clash_config", { payload }); }