mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-15 19:22:26 +08:00
feat: display network interface
This commit is contained in:
parent
32212a46e2
commit
48f7c15035
14
src-tauri/Cargo.lock
generated
14
src-tauri/Cargo.lock
generated
|
@ -803,6 +803,7 @@ dependencies = [
|
|||
"log 0.4.22",
|
||||
"log4rs",
|
||||
"nanoid",
|
||||
"network-interface",
|
||||
"once_cell",
|
||||
"open 5.2.0",
|
||||
"parking_lot",
|
||||
|
@ -3243,6 +3244,19 @@ dependencies = [
|
|||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "network-interface"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "433419f898328beca4f2c6c73a1b52540658d92b0a99f0269330457e0fd998d5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
|
|
|
@ -38,6 +38,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
|
||||
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
||||
tauri = { version="1", features = [ "fs-read-file", "fs-exists", "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "icon-ico", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "devtools"] }
|
||||
network-interface = { version = "2.0.0", features = ["serde"] }
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
deelevate = "0.2.0"
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
|||
};
|
||||
use crate::{ret_err, wrap_err};
|
||||
use anyhow::{Context, Result};
|
||||
use network_interface::NetworkInterface;
|
||||
use serde_yaml::Mapping;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use sysproxy::{Autoproxy, Sysproxy};
|
||||
|
@ -339,6 +340,25 @@ pub fn get_network_interfaces() -> Vec<String> {
|
|||
return result;
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_network_interfaces_info() -> CmdResult<Vec<NetworkInterface>> {
|
||||
use network_interface::NetworkInterface;
|
||||
use network_interface::NetworkInterfaceConfig;
|
||||
|
||||
let names = get_network_interfaces();
|
||||
let interfaces = wrap_err!(NetworkInterface::show())?;
|
||||
|
||||
let mut result = Vec::new();
|
||||
|
||||
for interface in interfaces {
|
||||
if names.contains(&interface.name) {
|
||||
result.push(interface);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_devtools(app_handle: tauri::AppHandle) {
|
||||
if let Some(window) = app_handle.get_window("main") {
|
||||
|
|
|
@ -74,6 +74,7 @@ fn main() -> std::io::Result<()> {
|
|||
cmds::download_icon_cache,
|
||||
cmds::open_devtools,
|
||||
cmds::exit_app,
|
||||
cmds::get_network_interfaces_info,
|
||||
// cmds::update_hotkeys,
|
||||
// profile
|
||||
cmds::get_profiles,
|
||||
|
|
135
src/components/setting/mods/network-interface-viewer.tsx
Normal file
135
src/components/setting/mods/network-interface-viewer.tsx
Normal file
|
@ -0,0 +1,135 @@
|
|||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||
import { getNetworkInterfacesInfo } from "@/services/cmds";
|
||||
import { alpha, Box, Button, Chip, IconButton } from "@mui/material";
|
||||
import { ContentCopyRounded } from "@mui/icons-material";
|
||||
import { writeText } from "@tauri-apps/api/clipboard";
|
||||
|
||||
export const NetworkInterfaceViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [networkInterfaces, setNetworkInterfaces] = useState<
|
||||
INetworkInterface[]
|
||||
>([]);
|
||||
const [isV4, setIsV4] = useState(true);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => {
|
||||
setOpen(true);
|
||||
},
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
getNetworkInterfacesInfo().then((res) => {
|
||||
console.log(res);
|
||||
setNetworkInterfaces(res);
|
||||
});
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
{t("Network Interface")}
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
setIsV4((prev) => !prev);
|
||||
}}
|
||||
>
|
||||
{isV4 ? t("Ipv6") : t("Ipv4")}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
contentSx={{ width: 450, maxHeight: 330 }}
|
||||
okBtn={t("Save")}
|
||||
cancelBtn={t("Cancel")}
|
||||
onClose={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
>
|
||||
{networkInterfaces.map((item) => (
|
||||
<Box key={item.name}>
|
||||
<h4>{item.name}</h4>
|
||||
<Box>
|
||||
{isV4 && (
|
||||
<>
|
||||
{item.addr.map(
|
||||
(address) =>
|
||||
address.V4 && (
|
||||
<AddressDisplay
|
||||
key={address.V4.ip}
|
||||
label="Address"
|
||||
content={address.V4.ip}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<AddressDisplay label="Mac" content={item.mac_addr ?? ""} />
|
||||
</>
|
||||
)}
|
||||
{!isV4 && (
|
||||
<>
|
||||
{item.addr.map(
|
||||
(address) =>
|
||||
address.V6 && (
|
||||
<AddressDisplay
|
||||
key={address.V6.ip}
|
||||
label="Address"
|
||||
content={address.V6.ip}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<AddressDisplay label="Mac" content={item.mac_addr ?? ""} />
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</BaseDialog>
|
||||
);
|
||||
});
|
||||
|
||||
const AddressDisplay = (props: { label: string; content: string }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
margin: "8px 0",
|
||||
}}
|
||||
>
|
||||
<Box>{props.label}</Box>
|
||||
<Box
|
||||
sx={({ palette }) => ({
|
||||
borderRadius: "8px",
|
||||
padding: "2px",
|
||||
background:
|
||||
palette.mode === "dark"
|
||||
? alpha(palette.background.paper, 0.3)
|
||||
: alpha(palette.grey[400], 0.3),
|
||||
})}
|
||||
>
|
||||
<Box sx={{ display: "inline", userSelect: "text" }}>
|
||||
{props.content}
|
||||
</Box>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
await writeText(props.content);
|
||||
Notice.success(t("Copy Success"));
|
||||
}}
|
||||
>
|
||||
<ContentCopyRounded sx={{ fontSize: "18px" }} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
|
@ -2,7 +2,11 @@ import { useRef } from "react";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { TextField, Select, MenuItem, Typography } from "@mui/material";
|
||||
|
||||
import { Settings, Shuffle } from "@mui/icons-material";
|
||||
import {
|
||||
SettingsRounded,
|
||||
ShuffleRounded,
|
||||
LanRounded,
|
||||
} from "@mui/icons-material";
|
||||
import { DialogRef, Notice, Switch } from "@/components/base";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import { GuardState } from "./mods/guard-state";
|
||||
|
@ -16,6 +20,7 @@ import getSystem from "@/utils/get-system";
|
|||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { updateGeoData } from "@/services/api";
|
||||
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
||||
import { NetworkInterfaceViewer } from "./mods/network-interface-viewer";
|
||||
|
||||
const isWIN = getSystem() === "windows";
|
||||
|
||||
|
@ -37,6 +42,7 @@ const SettingClash = ({ onError }: Props) => {
|
|||
const portRef = useRef<DialogRef>(null);
|
||||
const ctrlRef = useRef<DialogRef>(null);
|
||||
const coreRef = useRef<DialogRef>(null);
|
||||
const networkRef = useRef<DialogRef>(null);
|
||||
|
||||
const onSwitchFormat = (_e: any, value: boolean) => value;
|
||||
const onChangeData = (patch: Partial<IConfigData>) => {
|
||||
|
@ -60,8 +66,21 @@ const SettingClash = ({ onError }: Props) => {
|
|||
<ClashPortViewer ref={portRef} />
|
||||
<ControllerViewer ref={ctrlRef} />
|
||||
<ClashCoreViewer ref={coreRef} />
|
||||
<NetworkInterfaceViewer ref={networkRef} />
|
||||
|
||||
<SettingItem label={t("Allow Lan")}>
|
||||
<SettingItem
|
||||
label={t("Allow Lan")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("Network Interface")}
|
||||
color={"inherit"}
|
||||
icon={LanRounded}
|
||||
onClick={() => {
|
||||
networkRef.current?.open();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<GuardState
|
||||
value={allowLan ?? false}
|
||||
valueProps="checked"
|
||||
|
@ -112,7 +131,7 @@ const SettingClash = ({ onError }: Props) => {
|
|||
<TooltipIcon
|
||||
title={t("Random Port")}
|
||||
color={enable_random_port ? "primary" : "inherit"}
|
||||
icon={Shuffle}
|
||||
icon={ShuffleRounded}
|
||||
onClick={() => {
|
||||
Notice.success(
|
||||
t("Restart Application to Apply Modifications"),
|
||||
|
@ -148,7 +167,7 @@ const SettingClash = ({ onError }: Props) => {
|
|||
label={t("Clash Core")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
icon={Settings}
|
||||
icon={SettingsRounded}
|
||||
onClick={() => coreRef.current?.open()}
|
||||
/>
|
||||
}
|
||||
|
|
|
@ -241,3 +241,7 @@ export async function downloadIconCache(url: string, name: string) {
|
|||
export async function getNetworkInterfaces() {
|
||||
return invoke<string[]>("get_network_interfaces");
|
||||
}
|
||||
|
||||
export async function getNetworkInterfacesInfo() {
|
||||
return invoke<INetworkInterface[]>("get_network_interfaces_info");
|
||||
}
|
||||
|
|
18
src/services/types.d.ts
vendored
18
src/services/types.d.ts
vendored
|
@ -197,6 +197,24 @@ interface IVergeTestItem {
|
|||
icon?: string;
|
||||
url: string;
|
||||
}
|
||||
interface IAddress {
|
||||
V4?: {
|
||||
ip: string;
|
||||
broadcast?: string;
|
||||
netmask?: string;
|
||||
};
|
||||
V6?: {
|
||||
ip: string;
|
||||
broadcast?: string;
|
||||
netmask?: string;
|
||||
};
|
||||
}
|
||||
interface INetworkInterface {
|
||||
name: string;
|
||||
addr: IAddress[];
|
||||
mac_addr?: string;
|
||||
index: number;
|
||||
}
|
||||
|
||||
interface ISeqProfileConfig {
|
||||
prepend: [];
|
||||
|
|
Loading…
Reference in New Issue
Block a user