feat: enable change mixed port
This commit is contained in:
parent
d49fd37656
commit
d0b87fd7c3
@ -7,7 +7,7 @@ interface Props<Value> {
|
|||||||
onChangeProps?: string;
|
onChangeProps?: string;
|
||||||
onChange?: (value: Value) => void;
|
onChange?: (value: Value) => void;
|
||||||
onFormat?: (...args: any[]) => Value;
|
onFormat?: (...args: any[]) => Value;
|
||||||
onGuard?: (value: Value) => Promise<void>;
|
onGuard?: (value: Value, oldValue: Value) => Promise<void>;
|
||||||
onCatch?: (error: Error) => void;
|
onCatch?: (error: Error) => void;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ function GuardState<T>(props: Props<T>) {
|
|||||||
const newValue = (onFormat as any)(...args);
|
const newValue = (onFormat as any)(...args);
|
||||||
// 先在ui上响应操作
|
// 先在ui上响应操作
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
await onGuard(newValue);
|
await onGuard(newValue, oldValue!);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
// 状态回退
|
// 状态回退
|
||||||
onChange(oldValue!);
|
onChange(oldValue!);
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useDebounceFn } from "ahooks";
|
||||||
|
import { useSetRecoilState } from "recoil";
|
||||||
import useSWR, { useSWRConfig } from "swr";
|
import useSWR, { useSWRConfig } from "swr";
|
||||||
import {
|
import {
|
||||||
ListItemText,
|
ListItemText,
|
||||||
@ -9,11 +12,13 @@ import {
|
|||||||
import { getClashConfig, updateConfigs } from "../../services/api";
|
import { getClashConfig, updateConfigs } from "../../services/api";
|
||||||
import { SettingList, SettingItem } from "./setting";
|
import { SettingList, SettingItem } from "./setting";
|
||||||
import { patchClashConfig } from "../../services/cmds";
|
import { patchClashConfig } from "../../services/cmds";
|
||||||
|
import { atomClashPort } from "../../states/setting";
|
||||||
import { ApiType } from "../../services/types";
|
import { ApiType } from "../../services/types";
|
||||||
import GuardState from "./guard-state";
|
import GuardState from "./guard-state";
|
||||||
|
import Notice from "../notice";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onError?: (err: Error) => void;
|
onError: (err: Error) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SettingClash = ({ onError }: Props) => {
|
const SettingClash = ({ onError }: Props) => {
|
||||||
@ -24,9 +29,14 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
ipv6 = false,
|
ipv6 = false,
|
||||||
"allow-lan": allowLan = false,
|
"allow-lan": allowLan = false,
|
||||||
"log-level": logLevel = "silent",
|
"log-level": logLevel = "silent",
|
||||||
"mixed-port": mixedPort = 7890,
|
"mixed-port": thePort = 0,
|
||||||
} = clashConfig ?? {};
|
} = clashConfig ?? {};
|
||||||
|
|
||||||
|
const setPort = useSetRecoilState(atomClashPort);
|
||||||
|
const [mixedPort, setMixedPort] = useState(thePort);
|
||||||
|
|
||||||
|
useEffect(() => setMixedPort(thePort), [thePort]);
|
||||||
|
|
||||||
const onSwitchFormat = (_e: any, value: boolean) => value;
|
const onSwitchFormat = (_e: any, value: boolean) => value;
|
||||||
const onChangeData = (patch: Partial<ApiType.ConfigData>) => {
|
const onChangeData = (patch: Partial<ApiType.ConfigData>) => {
|
||||||
mutate("getClashConfig", { ...clashConfig, ...patch }, false);
|
mutate("getClashConfig", { ...clashConfig, ...patch }, false);
|
||||||
@ -36,6 +46,28 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
await patchClashConfig(patch);
|
await patchClashConfig(patch);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// restart clash when port is changed
|
||||||
|
const { run: onUpdatePort } = useDebounceFn(
|
||||||
|
async (port: number) => {
|
||||||
|
(async () => {
|
||||||
|
if (port < 1000) {
|
||||||
|
throw new Error("The port should not < 1000");
|
||||||
|
}
|
||||||
|
if (port > 65536) {
|
||||||
|
throw new Error("The port should not > 65536");
|
||||||
|
}
|
||||||
|
await patchClashConfig({ "mixed-port": port });
|
||||||
|
onChangeData({ "mixed-port": port });
|
||||||
|
setPort(port);
|
||||||
|
Notice.success("Change Clash port successfully!");
|
||||||
|
})().catch((err: any) => {
|
||||||
|
setMixedPort(thePort); // back to old port value
|
||||||
|
Notice.error(err.message ?? err.toString());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ wait: 1000 }
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingList title="Clash Setting">
|
<SettingList title="Clash Setting">
|
||||||
<SettingItem>
|
<SettingItem>
|
||||||
@ -87,12 +119,14 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
|
|
||||||
<SettingItem>
|
<SettingItem>
|
||||||
<ListItemText primary="Mixed Port" />
|
<ListItemText primary="Mixed Port" />
|
||||||
<TextField
|
<GuardState
|
||||||
size="small"
|
|
||||||
value={mixedPort!}
|
value={mixedPort!}
|
||||||
sx={{ width: 120 }}
|
onFormat={(e: any) => +e.target.value?.replace(/\D+/, "")}
|
||||||
disabled
|
onChange={setMixedPort}
|
||||||
/>
|
onGuard={onUpdatePort}
|
||||||
|
>
|
||||||
|
<TextField autoComplete="off" size="small" sx={{ width: 120 }} />
|
||||||
|
</GuardState>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
</SettingList>
|
</SettingList>
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { useRecoilValue } from "recoil";
|
||||||
import { Box, Typography } from "@mui/material";
|
import { Box, Typography } from "@mui/material";
|
||||||
import { ArrowDownward, ArrowUpward } from "@mui/icons-material";
|
import { ArrowDownward, ArrowUpward } from "@mui/icons-material";
|
||||||
import { getInfomation } from "../services/api";
|
import { getInfomation } from "../services/api";
|
||||||
import { ApiType } from "../services/types";
|
import { ApiType } from "../services/types";
|
||||||
|
import { atomClashPort } from "../states/setting";
|
||||||
import parseTraffic from "../utils/parse-traffic";
|
import parseTraffic from "../utils/parse-traffic";
|
||||||
|
|
||||||
const Traffic = () => {
|
const Traffic = () => {
|
||||||
|
const portValue = useRecoilValue(atomClashPort);
|
||||||
const [traffic, setTraffic] = useState({ up: 0, down: 0 });
|
const [traffic, setTraffic] = useState({ up: 0, down: 0 });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -21,7 +24,7 @@ const Traffic = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return () => ws?.close();
|
return () => ws?.close();
|
||||||
}, []);
|
}, [portValue]);
|
||||||
|
|
||||||
const [up, upUnit] = parseTraffic(traffic.up);
|
const [up, upUnit] = parseTraffic(traffic.up);
|
||||||
const [down, downUnit] = parseTraffic(traffic.down);
|
const [down, downUnit] = parseTraffic(traffic.down);
|
||||||
|
@ -9,3 +9,8 @@ export const atomThemeBlur = atom<boolean>({
|
|||||||
key: "atomThemeBlur",
|
key: "atomThemeBlur",
|
||||||
default: false,
|
default: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const atomClashPort = atom<number>({
|
||||||
|
key: "atomClashPort",
|
||||||
|
default: 0,
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user