feat: 代理功能

This commit is contained in:
song_xiao_lin
2024-05-15 14:43:04 +08:00
committed by go0p
parent 06fff8f92e
commit 7af4124da8
4 changed files with 300 additions and 304 deletions
+3 -5
View File
@@ -1,10 +1,9 @@
import React from "react"; import React from "react";
import "./App.css"; import "./App.css";
import { ConfigProvider } from "antd"; import { ConfigProvider } from "antd";
import { Contro } from "@components/Contro"; // import { Contro } from "@components/Contro";
import { Prox } from "@components/Prox"; import { Proxifier } from "@components/Proxifier";
// import { Controller } from "./components/Controller"; // import { Controller } from "./components/Controller";
import {Proxifier} from "./components/Proxifier";
function App() { function App() {
return ( return (
@@ -17,9 +16,8 @@ function App() {
> >
<div className="App"> <div className="App">
{/* <Contro /> */} {/* <Contro /> */}
<Prox />
{/* <Controller/> */} {/* <Controller/> */}
{/* <Proxifier/> */} <Proxifier/>
</div> </div>
</ConfigProvider> </ConfigProvider>
); );
-216
View File
@@ -1,216 +0,0 @@
import React, { useEffect, useState } from "react";
import { Space, Select, Input, Switch } from "antd";
import { PlusSmIcon, TrashIcon } from "@assets/icon/icon";
import { wsc } from "@network/chrome";
import "./Prox.css";
interface ProxyConfig {
id: string;
scheme: "http" | "socks5";
host: string;
port: string;
hostStatus: "error" | "";
portStatus: "error" | "";
open: boolean;
}
export interface ProxProps {}
export const Prox: React.FC<ProxProps> = () => {
const [proxyList, setProxyList] = useState<ProxyConfig[]>([]);
// proxy
useEffect(() => {
const update = () => {
wsc.updateProxyStatus();
};
update();
const id = setInterval(update, 500);
return () => {
clearInterval(id);
};
}, []);
useEffect(() => {
wsc.onProxyStatusMessage((msg) => {
if (msg["proxy"] === undefined || msg["enable"] === undefined) {
return;
}
console.log("当前代理:", msg);
});
}, []);
const hostOnchange = (value: string, id: string) => {
const ipPattern = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
const domainPattern = /^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const copyProxyList = structuredClone(proxyList);
if (value === "" || ipPattern.test(value) || domainPattern.test(value)) {
copyProxyList.forEach((i) => {
if (i.id === id) {
i.hostStatus = "";
i.host = value;
}
});
} else {
copyProxyList.forEach((i) => {
if (i.id === id) {
i.hostStatus = "error";
i.host = value;
}
});
}
setProxyList(copyProxyList);
};
const portOnchange = (value: string, id: string) => {
const portNumber = parseInt(value, 10);
const copyProxyList = structuredClone(proxyList);
if (
value === "" ||
(/^\d+$/.test(value) && portNumber >= 0 && portNumber <= 65535)
) {
copyProxyList.forEach((i) => {
if (i.id === id) {
i.portStatus = "";
i.port = value === "" ? "" : portNumber + "";
}
});
} else {
copyProxyList.forEach((i) => {
if (i.id === id) {
i.portStatus = "error";
i.port = value;
}
});
}
setProxyList(copyProxyList);
};
return (
<div className="Prox">
<div className="Prox-title-wrap">
<div className="Prox-title-wrap-left">
<span className="prox-title">设置代理</span>
<span className="prox-number">{proxyList.length}</span>
</div>
<div
className="Prox-title-wrap-right"
onClick={() => {
setProxyList([
...proxyList,
{
id: Math.random() + "",
scheme: "http",
host: "",
port: "",
hostStatus: "",
portStatus: "",
open: false,
},
]);
}}
>
<span className="Prox-add-text">添加</span>
<PlusSmIcon className="Prox-add-icon" />
</div>
</div>
<div className="Prox-list-wrap">
{proxyList.length ? (
proxyList.map((item) => (
<div className="Prox-list-item-wrap" key={item.id}>
<Space className="Prox-list-item-space">
<Space.Compact>
<Select
value={item.scheme}
style={{ width: 88 }}
disabled={item.open}
onChange={(value, option) => {
const copyProxyList = structuredClone(proxyList);
copyProxyList.forEach((i) => {
if (i.id === item.id) {
i.scheme = value;
}
});
setProxyList(copyProxyList);
}}
>
<Select.Option value="http">HTTP</Select.Option>
<Select.Option value="socks5">Socks5</Select.Option>
</Select>
<Input
value={item.host}
style={{ width: 136 }}
disabled={item.open}
status={item.hostStatus}
onChange={(e) => hostOnchange(e.target.value, item.id)}
/>
<Input
value={item.port}
style={{ width: 64 }}
disabled={item.open}
status={item.portStatus}
onChange={(e) => portOnchange(e.target.value, item.id)}
/>
</Space.Compact>
</Space>
{!item.open && (
<TrashIcon
className="proxy-list-del-icon"
onClick={() => {
setProxyList(proxyList.filter((i) => i.id !== item.id));
}}
/>
)}
<Switch
checkedChildren="启"
unCheckedChildren="停"
value={item.open}
disabled={
item.hostStatus === "error" ||
item.portStatus === "error" ||
item.host === "" ||
item.port === ""
}
onChange={(checked: boolean) => {
wsc.clearproxy();
const copyProxyList = structuredClone(proxyList);
copyProxyList.forEach((i) => {
if (i.id === item.id) {
i.open = checked;
if (checked) {
wsc.setproxy(item.scheme, item.host, Number(item.port));
}
} else {
i.open = false;
}
});
setProxyList(copyProxyList);
}}
/>
</div>
))
) : (
<div
className="add-list"
onClick={() => {
setProxyList([
{
id: Math.random() + "",
scheme: "http",
host: "127.0.0.1",
port: "8083",
hostStatus: "",
portStatus: "",
open: false,
},
]);
}}
>
<PlusSmIcon className="add-list-icon" />
<span className="add-list-text">添加</span>
</div>
)}
</div>
</div>
);
};
+297 -83
View File
@@ -1,93 +1,307 @@
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import {Button, Card, Form, Input, InputNumber, Select, Space} from "antd"; import { Space, Select, Input, Switch } from "antd";
import {wsc} from "../network/chrome"; import { PlusSmIcon, TrashIcon } from "@assets/icon/icon";
import { wsc } from "@network/chrome";
export interface ProxifierProp { import "./Proxifier.css";
}
const {Compact} = Space;
type Scheme = "http" | "socks5";
interface ProxyConfig { interface ProxyConfig {
scheme: "http" | "socks5"; id: string;
host: string; scheme: Scheme;
port: number; host: string;
port: string;
hostStatus: "error" | "";
portStatus: "error" | "";
open: boolean;
proxy: string;
} }
export const Proxifier: React.FC<ProxifierProp> = (props) => { export interface ProxifierProps {}
const [config, setConfig] = useState<ProxyConfig>({ export const Proxifier: React.FC<ProxifierProps> = () => {
scheme: "http", const [proxyList, setProxyList] = useState<ProxyConfig[]>(() => {
host: "127.0.0.1", const storageProxyList = localStorage.getItem("yakit-proxy-list") || "[]";
port: 8083 return JSON.parse(storageProxyList);
}); });
const [init, setInit] = useState(false);
const [proxyEnable, setProxyEnable] = useState(false);
const [currentProxy, setCurrentProxy] = useState("");
useEffect(() => { useEffect(() => {
if (init) { localStorage.setItem("yakit-proxy-list", JSON.stringify(proxyList));
return }, [proxyList]);
const addNewProxyListItem = (
scheme: Scheme,
host: string,
port: string,
open: boolean,
proxy: string
) => {
const proxyItem: ProxyConfig = {
id: Math.random() + "",
scheme: scheme as Scheme,
host: host,
port: port,
hostStatus: "",
portStatus: "",
open: open,
proxy: proxy,
};
return proxyItem;
};
const parseUrl = (url: string) => {
const regex = /^(.*?):\/\/(.*?):(\d+)/;
const match = url.match(regex);
if (match) {
const scheme = match[1];
const host = match[2];
const port = match[3];
return {
scheme,
host,
port,
};
} else {
return null; // 不匹配格式
}
};
useEffect(() => {
wsc.updateProxyStatus();
wsc.onProxyStatusMessage((msg) => {
if (!msg.proxy || !msg.enable) {
if (proxyList.some((i) => i.open)) {
const copyProxyList = [...proxyList];
copyProxyList.forEach((i) => {
i.open = false;
});
setProxyList(copyProxyList);
} }
return;
}
wsc.onProxyStatusMessage(msg => { if (msg.proxy && msg.enable) {
if (msg['proxy'] === undefined || msg['enable'] === undefined) { const copyProxyList = [...proxyList];
return let newProxyItem: ProxyConfig = undefined;
if (!copyProxyList.length) {
const urlObj = parseUrl(msg.proxy);
if (urlObj) {
newProxyItem = addNewProxyListItem(
urlObj.scheme as Scheme,
urlObj.host,
urlObj.port,
true,
msg.proxy
);
}
} else {
const proxyExist = copyProxyList.some((i) => i.proxy === msg.proxy);
if (proxyExist) {
const proxyOpen = copyProxyList.some(
(i) => i.open && i.proxy === msg.proxy
);
if (!proxyOpen) {
copyProxyList.forEach((i) => {
i.open = false;
});
for (let i = 0; i < copyProxyList.length; i++) {
if (copyProxyList[i].proxy === msg.proxy) {
copyProxyList[i].open = true;
break;
}
}
} }
} else {
setInit(true) copyProxyList.forEach((i) => {
setProxyEnable(msg.enable) i.open = false;
setCurrentProxy(msg.proxy) });
}) const urlObj = parseUrl(msg.proxy);
}, [init]) if (urlObj) {
newProxyItem = addNewProxyListItem(
// proxy urlObj.scheme as Scheme,
useEffect(() => { urlObj.host,
const update = () => { urlObj.port,
wsc.updateProxyStatus() true,
msg.proxy
);
}
}
} }
update()
const id = setInterval(update, 500)
return () => {
clearInterval(id)
}
}, [])
return <Card title={`Proxy Set: ${proxyEnable ? currentProxy : "Non-Config"}`} size={"small"} extra={<>{ if (newProxyItem) {
proxyEnable ? <Button size={"small"} onClick={() => { copyProxyList.unshift(newProxyItem);
wsc.clearproxy() }
}}>停用</Button> : undefined setProxyList(copyProxyList);
}</>}> }
<Form size={"small"} onSubmitCapture={e => { });
e.preventDefault() }, []);
setInit(false)
wsc.setproxy(config.scheme, config.host, config.port) const hostOnchange = (value: string, id: string) => {
}} disabled={!init || proxyEnable}> const ipPattern = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
<Form.Item label={"Proxy Setting"}> const domainPattern = /^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
<Compact> const copyProxyList = structuredClone(proxyList);
<Select if (value === "" || ipPattern.test(value) || domainPattern.test(value)) {
style={{width: 86}} copyProxyList.forEach((i) => {
value={config.scheme} if (i.id === id) {
onChange={e => (setConfig({...config, scheme: e}))} i.hostStatus = "";
> i.host = value;
<Select.Option value={"http"}>HTTP</Select.Option> i.proxy = i.scheme + "://" + value + ":" + i.port;
<Select.Option value={"socks5"}>Socks5</Select.Option> }
</Select> });
<Input } else {
style={{width: 100}} copyProxyList.forEach((i) => {
placeholder={"ProxyHost"} if (i.id === id) {
value={config.host} i.hostStatus = "error";
onChange={e => (setConfig({...config, host: e.target.value}))}/> i.host = value;
<InputNumber i.proxy = i.scheme + "://" + value + ":" + i.port;
style={{width: 65}} }
placeholder={"Port"} });
value={config.port} }
onChange={e => (setConfig({...config, port: e}))} setProxyList(copyProxyList);
/> };
</Compact>
</Form.Item> const portOnchange = (value: string, id: string) => {
<Form.Item> const portNumber = parseInt(value, 10);
<Button type={"primary"} htmlType={"submit"} loading={!init}>Enable Proxy</Button> const copyProxyList = structuredClone(proxyList);
</Form.Item> if (
</Form> value === "" ||
</Card> (/^\d+$/.test(value) && portNumber >= 0 && portNumber <= 65535)
}; ) {
copyProxyList.forEach((i) => {
if (i.id === id) {
i.portStatus = "";
const port = value === "" ? "" : portNumber + "";
i.port = port;
i.proxy = i.scheme + "://" + i.host + ":" + port;
}
});
} else {
copyProxyList.forEach((i) => {
if (i.id === id) {
i.portStatus = "error";
i.port = value;
i.proxy = i.scheme + "://" + i.host + ":" + value;
}
});
}
setProxyList(copyProxyList);
};
return (
<div className="Prox">
<div className="Prox-title-wrap">
<div className="Prox-title-wrap-left">
<span className="prox-title">设置代理</span>
<span className="prox-number">{proxyList.length}</span>
</div>
<div
className="Prox-title-wrap-right"
onClick={() => {
setProxyList([
...proxyList,
addNewProxyListItem("http", "", "", false, "http://"),
]);
}}
>
<span className="Prox-add-text">添加</span>
<PlusSmIcon className="Prox-add-icon" />
</div>
</div>
<div className="Prox-list-wrap">
{proxyList.length ? (
proxyList.map((item) => (
<div className="Prox-list-item-wrap" key={item.id}>
<Space className="Prox-list-item-space">
<Space.Compact>
<Select
value={item.scheme}
style={{ width: 88 }}
disabled={item.open}
onChange={(value, option) => {
const copyProxyList = structuredClone(proxyList);
copyProxyList.forEach((i) => {
if (i.id === item.id) {
i.scheme = value;
i.proxy = value + "://" + i.host + ":" + i.port;
}
});
setProxyList(copyProxyList);
}}
>
<Select.Option value="http">HTTP</Select.Option>
<Select.Option value="socks5">Socks5</Select.Option>
</Select>
<Input
value={item.host}
style={{ width: 136 }}
disabled={item.open}
status={item.hostStatus}
onChange={(e) => hostOnchange(e.target.value, item.id)}
/>
<Input
value={item.port}
style={{ width: 64 }}
disabled={item.open}
status={item.portStatus}
onChange={(e) => portOnchange(e.target.value, item.id)}
/>
</Space.Compact>
</Space>
{!item.open && (
<TrashIcon
className="proxy-list-del-icon"
onClick={() => {
setProxyList(proxyList.filter((i) => i.id !== item.id));
}}
/>
)}
<Switch
checkedChildren="启"
unCheckedChildren="停"
value={item.open}
disabled={
item.hostStatus === "error" ||
item.portStatus === "error" ||
item.host === "" ||
item.port === ""
}
onChange={(checked: boolean) => {
wsc.clearproxy();
const copyProxyList = structuredClone(proxyList);
copyProxyList.forEach((i) => {
if (i.id === item.id) {
i.open = checked;
if (checked) {
wsc.setproxy(item.scheme, item.host, Number(item.port));
}
} else {
i.open = false;
}
});
setProxyList(copyProxyList);
}}
/>
</div>
))
) : (
<div
className="add-list"
onClick={() => {
setProxyList([
addNewProxyListItem(
"http",
"127.0.0.1",
"8083",
false,
"http://127.0.0.1:8083"
),
]);
}}
>
<PlusSmIcon className="add-list-icon" />
<span className="add-list-text">添加</span>
</div>
)}
</div>
</div>
);
};