diff --git a/src/components/proxy/proxy-global.tsx b/src/components/proxy/proxy-global.tsx
index 9053cd4..a6f5d46 100644
--- a/src/components/proxy/proxy-global.tsx
+++ b/src/components/proxy/proxy-global.tsx
@@ -2,7 +2,7 @@ import useSWR, { useSWRConfig } from "swr";
import { useEffect, useRef, useState } from "react";
import { useLockFn } from "ahooks";
import { Virtuoso } from "react-virtuoso";
-import { updateProxy } from "@/services/api";
+import { providerHealthCheck, updateProxy } from "@/services/api";
import { getProfiles, patchProfile } from "@/services/cmds";
import delayManager from "@/services/delay";
import useSortProxy from "./use-sort-proxy";
@@ -74,10 +74,23 @@ const ProxyGlobal = (props: Props) => {
};
const onCheckAll = useLockFn(async () => {
- const names = sortedProxies.map((p) => p.name);
+ const providers = new Set(
+ sortedProxies.map((p) => p.provider!).filter(Boolean)
+ );
- await delayManager.checkListDelay({ names, groupName, skipNum: 8 }, () =>
- mutate("getProxies")
+ if (providers.size) {
+ Promise.allSettled(
+ [...providers].map((p) => providerHealthCheck(p))
+ ).then(() => mutate("getProxies"));
+ }
+
+ await delayManager.checkListDelay(
+ {
+ names: sortedProxies.filter((p) => !p.provider).map((p) => p.name),
+ groupName,
+ skipNum: 16,
+ },
+ () => mutate("getProxies")
);
});
diff --git a/src/components/proxy/proxy-group.tsx b/src/components/proxy/proxy-group.tsx
index 716b0ba..eb1b4c0 100644
--- a/src/components/proxy/proxy-group.tsx
+++ b/src/components/proxy/proxy-group.tsx
@@ -15,7 +15,7 @@ import {
ExpandLessRounded,
ExpandMoreRounded,
} from "@mui/icons-material";
-import { updateProxy } from "@/services/api";
+import { providerHealthCheck, updateProxy } from "@/services/api";
import { getProfiles, patchProfile } from "@/services/cmds";
import delayManager from "@/services/delay";
import useSortProxy from "./use-sort-proxy";
@@ -94,11 +94,23 @@ const ProxyGroup = ({ group }: Props) => {
};
const onCheckAll = useLockFn(async () => {
- const names = sortedProxies.map((p) => p.name);
- const groupName = group.name;
+ const providers = new Set(
+ sortedProxies.map((p) => p.provider!).filter(Boolean)
+ );
- await delayManager.checkListDelay({ names, groupName, skipNum: 16 }, () =>
- mutate("getProxies")
+ if (providers.size) {
+ Promise.allSettled(
+ [...providers].map((p) => providerHealthCheck(p))
+ ).then(() => mutate("getProxies"));
+ }
+
+ await delayManager.checkListDelay(
+ {
+ names: sortedProxies.filter((p) => !p.provider).map((p) => p.name),
+ groupName: group.name,
+ skipNum: 16,
+ },
+ () => mutate("getProxies")
);
});
diff --git a/src/components/proxy/proxy-item.tsx b/src/components/proxy/proxy-item.tsx
index 60d8824..7c7c07d 100644
--- a/src/components/proxy/proxy-item.tsx
+++ b/src/components/proxy/proxy-item.tsx
@@ -46,8 +46,17 @@ const ProxyItem = (props: Props) => {
const [delay, setDelay] = useState(-1);
useEffect(() => {
- if (proxy) {
+ if (!proxy) return;
+
+ if (!proxy.provider) {
setDelay(delayManager.getDelay(proxy.name, groupName));
+ return;
+ }
+
+ const { history = [] } = proxy;
+ if (history.length > 0) {
+ // 0ms以error显示
+ setDelay(history[history.length - 1].delay || 1e6);
}
}, [proxy]);
@@ -95,6 +104,9 @@ const ProxyItem = (props: Props) => {
<>
{proxy.name}
+ {showType && !!proxy.provider && (
+ {proxy.provider}
+ )}
{showType && {proxy.type}}
{showType && proxy.udp && UDP}
>
@@ -104,23 +116,27 @@ const ProxyItem = (props: Props) => {
- {
- e.preventDefault();
- e.stopPropagation();
- onDelay();
- }}
- sx={(theme) => ({
- ":hover": { bgcolor: alpha(theme.palette.primary.main, 0.15) },
- })}
- >
- Check
-
+ {!proxy.provider && (
+ {
+ e.preventDefault();
+ e.stopPropagation();
+ onDelay();
+ }}
+ sx={(theme) => ({
+ ":hover": { bgcolor: alpha(theme.palette.primary.main, 0.15) },
+ })}
+ >
+ Check
+
+ )}
{
+ if (proxy.provider) return;
+
e.preventDefault();
e.stopPropagation();
onDelay();
@@ -132,9 +148,11 @@ const ProxyItem = (props: Props) => {
? "success.main"
: "text.secondary"
}
- sx={(theme) => ({
- ":hover": { bgcolor: alpha(theme.palette.primary.main, 0.15) },
- })}
+ sx={({ palette }) =>
+ !proxy.provider
+ ? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } }
+ : {}
+ }
>
{delay > 1e5 ? "Error" : delay > 3000 ? "Timeout" : `${delay}ms`}
diff --git a/src/services/api.ts b/src/services/api.ts
index 39cb226..4794cf7 100644
--- a/src/services/api.ts
+++ b/src/services/api.ts
@@ -85,64 +85,93 @@ export async function updateProxy(group: string, proxy: string) {
return instance.put(`/proxies/${encodeURIComponent(group)}`, { name: proxy });
}
+// get proxy
+async function getProxiesInner() {
+ try {
+ const instance = await getAxios();
+ const response = await instance.get("/proxies");
+ return (response?.proxies || {}) as Record;
+ } catch {
+ return {};
+ }
+}
+
/// Get the Proxy infomation
export async function getProxies() {
- const instance = await getAxios();
- const response = await instance.get("/proxies");
- const records = (response?.proxies ?? {}) as Record<
- string,
- ApiType.ProxyItem
- >;
+ const [proxyRecord, providerRecord] = await Promise.all([
+ getProxiesInner(),
+ getProviders(),
+ ]);
- const global = records["GLOBAL"];
- const direct = records["DIRECT"];
- const reject = records["REJECT"];
- const order = global?.all;
-
- let groups: ApiType.ProxyGroupItem[] = [];
+ // provider name map
+ const providerMap = Object.fromEntries(
+ Object.entries(providerRecord).flatMap(([provider, item]) =>
+ item.proxies.map((p) => [p.name, { ...p, provider }])
+ )
+ );
// compatible with proxy-providers
const generateItem = (name: string) => {
- if (records[name]) return records[name];
+ if (proxyRecord[name]) return proxyRecord[name];
+ if (providerMap[name]) return providerMap[name];
return { name, type: "unknown", udp: false, history: [] };
};
- if (order) {
- groups = order
- .filter((name) => records[name]?.all)
- .map((name) => records[name])
+ const { GLOBAL: global, DIRECT: direct, REJECT: reject } = proxyRecord;
+
+ let groups: ApiType.ProxyGroupItem[] = [];
+
+ if (global?.all) {
+ groups = global.all
+ .filter((name) => proxyRecord[name]?.all)
+ .map((name) => proxyRecord[name])
.map((each) => ({
...each,
all: each.all!.map((item) => generateItem(item)),
}));
} else {
- groups = Object.values(records)
+ groups = Object.values(proxyRecord)
.filter((each) => each.name !== "GLOBAL" && each.all)
.map((each) => ({
...each,
all: each.all!.map((item) => generateItem(item)),
- }));
- groups.sort((a, b) => b.name.localeCompare(a.name));
+ }))
+ .sort((a, b) => b.name.localeCompare(a.name));
}
const proxies = [direct, reject].concat(
- Object.values(records).filter(
+ Object.values(proxyRecord).filter(
(p) => !p.all?.length && p.name !== "DIRECT" && p.name !== "REJECT"
)
);
- return { global, direct, groups, records, proxies };
+ return { global, direct, groups, records: proxyRecord, proxies };
}
-// todo: get proxy providers
+// get proxy providers
export async function getProviders() {
- const instance = await getAxios();
- const response = await instance.get("/providers/proxies");
- return response.providers as any;
+ try {
+ const instance = await getAxios();
+ const response = await instance.get("/providers/proxies");
+
+ const providers = (response.providers || {}) as Record<
+ string,
+ ApiType.ProviderItem
+ >;
+
+ return Object.fromEntries(
+ Object.entries(providers).filter(([key, item]) => {
+ const type = item.vehicleType.toLowerCase();
+ return type === "http" || type === "file";
+ })
+ );
+ } catch {
+ return {};
+ }
}
-// todo: proxy providers health check
-export async function getProviderHealthCheck(name: string) {
+// proxy providers health check
+export async function providerHealthCheck(name: string) {
const instance = await getAxios();
return instance.get(
`/providers/proxies/${encodeURIComponent(name)}/healthcheck`
diff --git a/src/services/types.d.ts b/src/services/types.d.ts
index caf3331..37115a6 100644
--- a/src/services/types.d.ts
+++ b/src/services/types.d.ts
@@ -31,12 +31,21 @@ declare namespace ApiType {
}[];
all?: string[];
now?: string;
+ provider?: string; // 记录是否来自provider
}
type ProxyGroupItem = Omit & {
all: ProxyItem[];
};
+ interface ProviderItem {
+ name: string;
+ type: string;
+ proxies: ProxyItem[];
+ updatedAt: string;
+ vehicleType: string;
+ }
+
interface TrafficItem {
up: number;
down: number;