mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-16 11:42:21 +08:00
Compare commits
5 Commits
8342f985e5
...
1667856894
Author | SHA1 | Date | |
---|---|---|---|
|
1667856894 | ||
|
c5c76ab539 | ||
|
eb060d2e43 | ||
|
b5556613cf | ||
|
ad1a057edb |
|
@ -49,7 +49,8 @@
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"react-transition-group": "^4.4.5",
|
"react-transition-group": "^4.4.5",
|
||||||
"react-virtuoso": "^4.7.11",
|
"react-virtuoso": "^4.7.11",
|
||||||
"swr": "^1.3.0",
|
"sockette": "^2.0.6",
|
||||||
|
"swr": "^2.2.5",
|
||||||
"tar": "^6.2.1",
|
"tar": "^6.2.1",
|
||||||
"types-pac": "^1.0.2"
|
"types-pac": "^1.0.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -100,9 +100,12 @@ importers:
|
||||||
react-virtuoso:
|
react-virtuoso:
|
||||||
specifier: ^4.7.11
|
specifier: ^4.7.11
|
||||||
version: 4.7.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 4.7.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
sockette:
|
||||||
|
specifier: ^2.0.6
|
||||||
|
version: 2.0.6
|
||||||
swr:
|
swr:
|
||||||
specifier: ^1.3.0
|
specifier: ^2.2.5
|
||||||
version: 1.3.0(react@18.3.1)
|
version: 2.2.5(react@18.3.1)
|
||||||
tar:
|
tar:
|
||||||
specifier: ^6.2.1
|
specifier: ^6.2.1
|
||||||
version: 6.2.1
|
version: 6.2.1
|
||||||
|
@ -4032,6 +4035,12 @@ packages:
|
||||||
integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==,
|
integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sockette@2.0.6:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-W6iG8RGV6Zife3Cj+FhuyHV447E6fqFM2hKmnaQrTvg3OydINV3Msj3WPFbX76blUlUxvQSMMMdrJxce8NqI5Q==,
|
||||||
|
}
|
||||||
|
|
||||||
source-map-js@1.2.0:
|
source-map-js@1.2.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
|
@ -4110,10 +4119,10 @@ packages:
|
||||||
integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==,
|
integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==,
|
||||||
}
|
}
|
||||||
|
|
||||||
swr@1.3.0:
|
swr@2.2.5:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==,
|
integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==,
|
||||||
}
|
}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
||||||
|
@ -4303,6 +4312,14 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
browserslist: ">= 4.21.0"
|
browserslist: ">= 4.21.0"
|
||||||
|
|
||||||
|
use-sync-external-store@1.2.2:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
|
||||||
vfile-message@4.0.2:
|
vfile-message@4.0.2:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
|
@ -7096,6 +7113,8 @@ snapshots:
|
||||||
dot-case: 3.0.4
|
dot-case: 3.0.4
|
||||||
tslib: 2.6.3
|
tslib: 2.6.3
|
||||||
|
|
||||||
|
sockette@2.0.6: {}
|
||||||
|
|
||||||
source-map-js@1.2.0: {}
|
source-map-js@1.2.0: {}
|
||||||
|
|
||||||
source-map-support@0.5.21:
|
source-map-support@0.5.21:
|
||||||
|
@ -7130,9 +7149,11 @@ snapshots:
|
||||||
|
|
||||||
svg-parser@2.0.4: {}
|
svg-parser@2.0.4: {}
|
||||||
|
|
||||||
swr@1.3.0(react@18.3.1):
|
swr@2.2.5(react@18.3.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
client-only: 0.0.1
|
||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
|
use-sync-external-store: 1.2.2(react@18.3.1)
|
||||||
|
|
||||||
systemjs@6.15.1: {}
|
systemjs@6.15.1: {}
|
||||||
|
|
||||||
|
@ -7237,6 +7258,10 @@ snapshots:
|
||||||
escalade: 3.1.2
|
escalade: 3.1.2
|
||||||
picocolors: 1.0.1
|
picocolors: 1.0.1
|
||||||
|
|
||||||
|
use-sync-external-store@1.2.2(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
react: 18.3.1
|
||||||
|
|
||||||
vfile-message@4.0.2:
|
vfile-message@4.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/unist": 3.0.2
|
"@types/unist": 3.0.2
|
||||||
|
|
|
@ -181,15 +181,6 @@ pub async fn restart_sidecar() -> CmdResult {
|
||||||
wrap_err!(CoreManager::global().run_core().await)
|
wrap_err!(CoreManager::global().run_core().await)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn grant_permission(_core: String) -> CmdResult {
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
|
||||||
return wrap_err!(manager::grant_permission(_core));
|
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
|
|
||||||
return Err("Unsupported target".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get the system proxy
|
/// get the system proxy
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_sys_proxy() -> CmdResult<Mapping> {
|
pub fn get_sys_proxy() -> CmdResult<Mapping> {
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/// 给clash内核的tun模式授权
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "linux"))]
|
|
||||||
pub fn grant_permission(core: String) -> anyhow::Result<()> {
|
|
||||||
use std::process::Command;
|
|
||||||
use tauri::utils::platform::current_exe;
|
|
||||||
|
|
||||||
let path = current_exe()?.with_file_name(core).canonicalize()?;
|
|
||||||
let path = path.display().to_string();
|
|
||||||
|
|
||||||
log::debug!("grant_permission path: {path}");
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
let output = {
|
|
||||||
let path = path.replace(' ', "\\\\ ");
|
|
||||||
let shell = format!("chown root:admin {path}\nchmod +sx {path}");
|
|
||||||
let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
|
|
||||||
Command::new("osascript")
|
|
||||||
.args(vec!["-e", &command])
|
|
||||||
.output()?
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
let output = {
|
|
||||||
let path = path.replace(' ', "\\ "); // 避免路径中有空格
|
|
||||||
let shell =
|
|
||||||
format!("setcap cap_net_bind_service,cap_net_admin,cap_dac_override=+ep {path}");
|
|
||||||
|
|
||||||
let sudo = match Command::new("which").arg("pkexec").output() {
|
|
||||||
Ok(output) => {
|
|
||||||
if output.stdout.is_empty() {
|
|
||||||
"sudo"
|
|
||||||
} else {
|
|
||||||
"pkexec"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => "sudo",
|
|
||||||
};
|
|
||||||
|
|
||||||
Command::new(sudo).arg("sh").arg("-c").arg(shell).output()?
|
|
||||||
};
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
|
|
||||||
anyhow::bail!("{stderr}");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ mod core;
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
pub mod hotkey;
|
pub mod hotkey;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod manager;
|
|
||||||
pub mod service;
|
pub mod service;
|
||||||
pub mod sysopt;
|
pub mod sysopt;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
|
@ -44,7 +44,6 @@ fn main() -> std::io::Result<()> {
|
||||||
cmds::get_portable_flag,
|
cmds::get_portable_flag,
|
||||||
// cmds::kill_sidecar,
|
// cmds::kill_sidecar,
|
||||||
cmds::restart_sidecar,
|
cmds::restart_sidecar,
|
||||||
cmds::grant_permission,
|
|
||||||
// clash
|
// clash
|
||||||
cmds::get_clash_info,
|
cmds::get_clash_info,
|
||||||
cmds::get_clash_logs,
|
cmds::get_clash_logs,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useRef } from "react";
|
||||||
import { Box, Typography } from "@mui/material";
|
import { Box, Typography } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
ArrowDownward,
|
ArrowDownward,
|
||||||
|
@ -10,8 +10,14 @@ import { useVerge } from "@/hooks/use-verge";
|
||||||
import { TrafficGraph, type TrafficRef } from "./traffic-graph";
|
import { TrafficGraph, type TrafficRef } from "./traffic-graph";
|
||||||
import { useLogSetup } from "./use-log-setup";
|
import { useLogSetup } from "./use-log-setup";
|
||||||
import { useVisibility } from "@/hooks/use-visibility";
|
import { useVisibility } from "@/hooks/use-visibility";
|
||||||
import { useWebsocket } from "@/hooks/use-websocket";
|
|
||||||
import parseTraffic from "@/utils/parse-traffic";
|
import parseTraffic from "@/utils/parse-traffic";
|
||||||
|
import useSWRSubscription from "swr/subscription";
|
||||||
|
import Sockette from "sockette";
|
||||||
|
|
||||||
|
interface MemoryUsage {
|
||||||
|
inuse: number;
|
||||||
|
oslimit?: number;
|
||||||
|
}
|
||||||
|
|
||||||
// setup the traffic
|
// setup the traffic
|
||||||
export const LayoutTraffic = () => {
|
export const LayoutTraffic = () => {
|
||||||
|
@ -22,51 +28,92 @@ export const LayoutTraffic = () => {
|
||||||
const trafficGraph = verge?.traffic_graph ?? true;
|
const trafficGraph = verge?.traffic_graph ?? true;
|
||||||
|
|
||||||
const trafficRef = useRef<TrafficRef>(null);
|
const trafficRef = useRef<TrafficRef>(null);
|
||||||
const [traffic, setTraffic] = useState({ up: 0, down: 0 });
|
|
||||||
const [memory, setMemory] = useState({ inuse: 0 });
|
|
||||||
const pageVisible = useVisibility();
|
const pageVisible = useVisibility();
|
||||||
|
|
||||||
// setup log ws during layout
|
// setup log ws during layout
|
||||||
useLogSetup();
|
useLogSetup();
|
||||||
|
|
||||||
const trafficWs = useWebsocket(
|
const { data: traffic = { up: 0, down: 0 } } = useSWRSubscription<
|
||||||
(event) => {
|
ITrafficItem,
|
||||||
const data = JSON.parse(event.data) as ITrafficItem;
|
any,
|
||||||
trafficRef.current?.appendData(data);
|
"getRealtimeTraffic" | null
|
||||||
setTraffic(data);
|
>(
|
||||||
|
clashInfo && pageVisible ? "getRealtimeTraffic" : null,
|
||||||
|
(_key, { next }) => {
|
||||||
|
const { server = "", secret = "" } = clashInfo!;
|
||||||
|
|
||||||
|
let errorCount = 10;
|
||||||
|
|
||||||
|
const s = new Sockette(
|
||||||
|
`ws://${server}/traffic?token=${encodeURIComponent(secret)}`,
|
||||||
|
{
|
||||||
|
onmessage(event) {
|
||||||
|
errorCount = 0; // reset counter
|
||||||
|
const data = JSON.parse(event.data) as ITrafficItem;
|
||||||
|
trafficRef.current?.appendData(data);
|
||||||
|
next(null, data);
|
||||||
|
},
|
||||||
|
onerror(event) {
|
||||||
|
errorCount -= 1;
|
||||||
|
|
||||||
|
if (errorCount <= 0) {
|
||||||
|
this.close();
|
||||||
|
next(event, { up: 0, down: 0 });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
s.close();
|
||||||
|
};
|
||||||
},
|
},
|
||||||
{ onError: () => setTraffic({ up: 0, down: 0 }), errorCount: 10 }
|
{
|
||||||
|
fallbackData: { up: 0, down: 0 },
|
||||||
|
keepPreviousData: true,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!clashInfo || !pageVisible) return;
|
|
||||||
|
|
||||||
const { server = "", secret = "" } = clashInfo;
|
|
||||||
trafficWs.connect(
|
|
||||||
`ws://${server}/traffic?token=${encodeURIComponent(secret)}`
|
|
||||||
);
|
|
||||||
return () => trafficWs.disconnect();
|
|
||||||
}, [clashInfo, pageVisible]);
|
|
||||||
|
|
||||||
/* --------- meta memory information --------- */
|
/* --------- meta memory information --------- */
|
||||||
const isMetaCore = verge?.clash_core?.includes("clash-meta");
|
const isMetaCore = verge?.clash_core?.includes("clash-meta");
|
||||||
const displayMemory = isMetaCore && (verge?.enable_memory_usage ?? true);
|
const displayMemory = isMetaCore && (verge?.enable_memory_usage ?? true);
|
||||||
|
|
||||||
const memoryWs = useWebsocket(
|
const { data: memory = { inuse: 0 } } = useSWRSubscription<
|
||||||
(event) => {
|
MemoryUsage,
|
||||||
setMemory(JSON.parse(event.data));
|
any,
|
||||||
},
|
"getRealtimeMemory" | null
|
||||||
{ onError: () => setMemory({ inuse: 0 }), errorCount: 10 }
|
>(
|
||||||
);
|
clashInfo && pageVisible && displayMemory ? "getRealtimeMemory" : null,
|
||||||
|
(_key, { next }) => {
|
||||||
|
const { server = "", secret = "" } = clashInfo!;
|
||||||
|
const ws = new WebSocket(
|
||||||
|
`ws://${server}/memory?token=${encodeURIComponent(secret)}`
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
let errorCount = 10;
|
||||||
if (!clashInfo || !pageVisible || !displayMemory) return;
|
|
||||||
const { server = "", secret = "" } = clashInfo;
|
ws.addEventListener("message", (event) => {
|
||||||
memoryWs.connect(
|
errorCount = 0; // reset counter
|
||||||
`ws://${server}/memory?token=${encodeURIComponent(secret)}`
|
next(null, JSON.parse(event.data));
|
||||||
);
|
});
|
||||||
return () => memoryWs.disconnect();
|
ws.addEventListener("error", (event) => {
|
||||||
}, [clashInfo, pageVisible, displayMemory]);
|
errorCount -= 1;
|
||||||
|
|
||||||
|
if (errorCount <= 0) {
|
||||||
|
ws.close();
|
||||||
|
next(event, { inuse: 0 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
ws.close();
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fallbackData: { inuse: 0 },
|
||||||
|
keepPreviousData: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const [up, upUnit] = parseTraffic(traffic.up);
|
const [up, upUnit] = parseTraffic(traffic.up);
|
||||||
const [down, downUnit] = parseTraffic(traffic.down);
|
const [down, downUnit] = parseTraffic(traffic.down);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||||
import { Box, Button, Typography } from "@mui/material";
|
import { Box, Button, Typography } from "@mui/material";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onChange: (value: string) => void;
|
onChange: (file: File, value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FileInput = (props: Props) => {
|
export const FileInput = (props: Props) => {
|
||||||
|
@ -28,7 +28,7 @@ export const FileInput = (props: Props) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (event) => {
|
reader.onload = (event) => {
|
||||||
resolve(null);
|
resolve(null);
|
||||||
onChange(event.target?.result as string);
|
onChange(file, event.target?.result as string);
|
||||||
};
|
};
|
||||||
reader.onerror = reject;
|
reader.onerror = reject;
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
|
|
|
@ -246,7 +246,15 @@ export const ProfileViewer = forwardRef<ProfileViewerRef, Props>(
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isLocal && openType === "new" && (
|
{isLocal && openType === "new" && (
|
||||||
<FileInput onChange={(val) => (fileDataRef.current = val)} />
|
<FileInput
|
||||||
|
onChange={(file, val) => {
|
||||||
|
if (!formIns.getValues("name")) {
|
||||||
|
const name = file.name.substring(0, file.name.lastIndexOf("."));
|
||||||
|
formIns.setValue("name", name);
|
||||||
|
}
|
||||||
|
fileDataRef.current = val;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isRemote && (
|
{isRemote && (
|
||||||
|
|
|
@ -6,17 +6,9 @@ import { useVerge } from "@/hooks/use-verge";
|
||||||
import { useLockFn } from "ahooks";
|
import { useLockFn } from "ahooks";
|
||||||
import { LoadingButton } from "@mui/lab";
|
import { LoadingButton } from "@mui/lab";
|
||||||
import { SwitchAccessShortcut, RestartAlt } from "@mui/icons-material";
|
import { SwitchAccessShortcut, RestartAlt } from "@mui/icons-material";
|
||||||
import {
|
import { Box, Button, List, ListItemButton, ListItemText } from "@mui/material";
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Tooltip,
|
|
||||||
List,
|
|
||||||
ListItemButton,
|
|
||||||
ListItemText,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { changeClashCore, restartSidecar } from "@/services/cmds";
|
import { changeClashCore, restartSidecar } from "@/services/cmds";
|
||||||
import { closeAllConnections, upgradeCore } from "@/services/api";
|
import { closeAllConnections, upgradeCore } from "@/services/api";
|
||||||
import { grantPermission } from "@/services/cmds";
|
|
||||||
import getSystem from "@/utils/get-system";
|
import getSystem from "@/utils/get-system";
|
||||||
|
|
||||||
const VALID_CORE = [
|
const VALID_CORE = [
|
||||||
|
@ -58,17 +50,6 @@ export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const onGrant = useLockFn(async (core: string) => {
|
|
||||||
try {
|
|
||||||
await grantPermission(core);
|
|
||||||
// 自动重启
|
|
||||||
if (core === clash_core) await restartSidecar();
|
|
||||||
Notice.success(t("Permissions Granted Successfully for _clash Core", { core: `${core}` }), 1000);
|
|
||||||
} catch (err: any) {
|
|
||||||
Notice.error(err?.message || err.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const onRestart = useLockFn(async () => {
|
const onRestart = useLockFn(async () => {
|
||||||
try {
|
try {
|
||||||
await restartSidecar();
|
await restartSidecar();
|
||||||
|
@ -140,22 +121,6 @@ export const ClashCoreViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
onClick={() => onCoreChange(each.core)}
|
onClick={() => onCoreChange(each.core)}
|
||||||
>
|
>
|
||||||
<ListItemText primary={each.name} secondary={`/${each.core}`} />
|
<ListItemText primary={each.name} secondary={`/${each.core}`} />
|
||||||
|
|
||||||
{(OS === "macos" || OS === "linux") && (
|
|
||||||
<Tooltip title={t("Tun mode requires")}>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
onGrant(each.core);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t("Grant")}
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
|
|
|
@ -41,8 +41,11 @@ export const ServiceViewer = forwardRef<DialogRef, Props>((props, ref) => {
|
||||||
const onInstall = useLockFn(async () => {
|
const onInstall = useLockFn(async () => {
|
||||||
try {
|
try {
|
||||||
await installService();
|
await installService();
|
||||||
mutateCheck();
|
await mutateCheck();
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
mutateCheck();
|
||||||
|
}, 2000);
|
||||||
Notice.success(t("Service Installed Successfully"));
|
Notice.success(t("Service Installed Successfully"));
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
mutateCheck();
|
mutateCheck();
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { checkService } from "@/services/cmds";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import getSystem from "@/utils/get-system";
|
import getSystem from "@/utils/get-system";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
const isWIN = getSystem() === "windows";
|
const isWIN = getSystem() === "windows";
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ export const StackModeSwitch = (props: Props) => {
|
||||||
const { verge } = useVerge();
|
const { verge } = useVerge();
|
||||||
const { enable_service_mode } = verge ?? {};
|
const { enable_service_mode } = verge ?? {};
|
||||||
// service mode
|
// service mode
|
||||||
const { data: serviceStatus } = useSWR(
|
const { data: serviceStatus, mutate: mutateCheck } = useSWR(
|
||||||
isWIN ? "checkService" : null,
|
isWIN ? "checkService" : null,
|
||||||
checkService,
|
checkService,
|
||||||
{
|
{
|
||||||
|
@ -28,6 +29,10 @@ export const StackModeSwitch = (props: Props) => {
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
mutateCheck();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
|
|
|
@ -23,7 +23,7 @@ export const WebUIViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const webUIList = verge?.web_ui_list || [
|
const webUIList = verge?.web_ui_list || [
|
||||||
"https://d.metacubex.one/#?hostname=%host&port=%port&secret=%secret",
|
"https://metacubex.github.io/metacubexd/#/setup?http=true&hostname=%host&port=%port&secret=%secret",
|
||||||
"https://yacd.metacubex.one/?host=%host&port=%port&secret=%secret",
|
"https://yacd.metacubex.one/?host=%host&port=%port&secret=%secret",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -142,10 +142,6 @@ export async function restartSidecar() {
|
||||||
return invoke<void>("restart_sidecar");
|
return invoke<void>("restart_sidecar");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function grantPermission(core: string) {
|
|
||||||
return invoke<void>("grant_permission", { core });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAppDir() {
|
export async function getAppDir() {
|
||||||
return invoke<string>("get_app_dir");
|
return invoke<string>("get_app_dir");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user