From 68ad5e23201f6f0728ef3d4e429d3ddea1d28893 Mon Sep 17 00:00:00 2001 From: GyDi Date: Sun, 10 Apr 2022 02:09:36 +0800 Subject: [PATCH] feat: support sort proxy node and custom test url --- src/components/proxy/proxy-global.tsx | 35 ++------ src/components/proxy/proxy-group.tsx | 106 ++++++----------------- src/components/proxy/proxy-head.tsx | 33 ++++--- src/components/proxy/use-filter-proxy.ts | 3 - src/components/proxy/use-sort-proxy.ts | 38 ++++++++ src/services/delay.ts | 12 ++- 6 files changed, 104 insertions(+), 123 deletions(-) create mode 100644 src/components/proxy/use-sort-proxy.ts diff --git a/src/components/proxy/proxy-global.tsx b/src/components/proxy/proxy-global.tsx index 75d110b..7529dcb 100644 --- a/src/components/proxy/proxy-global.tsx +++ b/src/components/proxy/proxy-global.tsx @@ -1,14 +1,15 @@ import useSWR, { useSWRConfig } from "swr"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useLockFn } from "ahooks"; import { Virtuoso } from "react-virtuoso"; import { ApiType } from "../../services/types"; import { updateProxy } from "../../services/api"; import { getProfiles, patchProfile } from "../../services/cmds"; -import useFilterProxy, { ProxySortType } from "./use-filter-proxy"; +import useSortProxy, { ProxySortType } from "./use-sort-proxy"; +import useFilterProxy from "./use-filter-proxy"; import delayManager from "../../services/delay"; -import ProxyItem from "./proxy-item"; import ProxyHead from "./proxy-head"; +import ProxyItem from "./proxy-item"; interface Props { groupName: string; @@ -25,34 +26,11 @@ const ProxyGlobal = (props: Props) => { const [showType, setShowType] = useState(true); const [sortType, setSortType] = useState(0); - - const [urlText, setUrlText] = useState(""); const [filterText, setFilterText] = useState(""); const virtuosoRef = useRef(); const filterProxies = useFilterProxy(proxies, groupName, filterText); - - const sortedProxies = useMemo(() => { - if (sortType === 0) return filterProxies; - - const list = filterProxies.slice(); - - if (sortType === 1) { - list.sort((a, b) => a.name.localeCompare(b.name)); - } else { - list.sort((a, b) => { - const ad = delayManager.getDelay(a.name, groupName); - const bd = delayManager.getDelay(b.name, groupName); - - if (ad === -1) return 1; - if (bd === -1) return -1; - - return ad - bd; - }); - } - - return list; - }, [filterProxies, sortType, groupName]); + const sortedProxies = useSortProxy(filterProxies, groupName, sortType); const { data: profiles } = useSWR("getProfiles", getProfiles); @@ -129,13 +107,12 @@ const ProxyGlobal = (props: Props) => { sx={{ px: 3, my: 0.5, button: { mr: 0.5 } }} showType={showType} sortType={sortType} - urlText={urlText} + groupName={groupName} filterText={filterText} onLocation={onLocation} onCheckDelay={onCheckAll} onShowType={setShowType} onSortType={setSortType} - onUrlText={setUrlText} onFilterText={setFilterText} /> diff --git a/src/components/proxy/proxy-group.tsx b/src/components/proxy/proxy-group.tsx index cef5acb..61b8298 100644 --- a/src/components/proxy/proxy-group.tsx +++ b/src/components/proxy/proxy-group.tsx @@ -6,28 +6,22 @@ import { Box, Collapse, Divider, - IconButton, List, ListItem, ListItemText, - TextField, } from "@mui/material"; import { SendRounded, ExpandLessRounded, ExpandMoreRounded, - MyLocationRounded, - NetworkCheckRounded, - FilterAltRounded, - FilterAltOffRounded, - VisibilityRounded, - VisibilityOffRounded, } from "@mui/icons-material"; import { ApiType } from "../../services/types"; import { updateProxy } from "../../services/api"; import { getProfiles, patchProfile } from "../../services/cmds"; -import delayManager from "../../services/delay"; +import useSortProxy, { ProxySortType } from "./use-sort-proxy"; import useFilterProxy from "./use-filter-proxy"; +import delayManager from "../../services/delay"; +import ProxyHead from "./proxy-head"; import ProxyItem from "./proxy-item"; interface Props { @@ -38,12 +32,14 @@ const ProxyGroup = ({ group }: Props) => { const { mutate } = useSWRConfig(); const [open, setOpen] = useState(false); const [now, setNow] = useState(group.now); + const [showType, setShowType] = useState(false); - const [showFilter, setShowFilter] = useState(false); + const [sortType, setSortType] = useState(0); const [filterText, setFilterText] = useState(""); const virtuosoRef = useRef(); const filterProxies = useFilterProxy(group.all, group.name, filterText); + const sortedProxies = useSortProxy(filterProxies, group.name, sortType); const { data: profiles } = useSWR("getProfiles", getProfiles); @@ -81,7 +77,7 @@ const ProxyGroup = ({ group }: Props) => { }); const onLocation = (smooth = true) => { - const index = filterProxies.findIndex((p) => p.name === now); + const index = sortedProxies.findIndex((p) => p.name === now); if (index >= 0) { virtuosoRef.current?.scrollToIndex?.({ @@ -93,7 +89,7 @@ const ProxyGroup = ({ group }: Props) => { }; const onCheckAll = useLockFn(async () => { - const names = filterProxies.map((p) => p.name); + const names = sortedProxies.map((p) => p.name); const groupName = group.name; await delayManager.checkListDelay( @@ -104,10 +100,6 @@ const ProxyGroup = ({ group }: Props) => { mutate("getProxies"); }); - useEffect(() => { - if (!showFilter) setFilterText(""); - }, [showFilter]); - // auto scroll to current index useEffect(() => { if (open) { @@ -135,66 +127,20 @@ const ProxyGroup = ({ group }: Props) => { - - onLocation(true)} - > - - + - - - - - setShowType(!showType)} - > - {showType ? : } - - - setShowFilter(!showFilter)} - > - {showFilter ? : } - - - {showFilter && ( - setFilterText(e.target.value)} - sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }} - /> - )} - - - {!filterProxies.length && ( + {!sortedProxies.length && ( { )} - {filterProxies.length >= 10 ? ( + {sortedProxies.length >= 10 ? ( ( { disablePadding sx={{ maxHeight: "320px", overflow: "auto", mb: "4px" }} > - {filterProxies.map((proxy) => ( + {sortedProxies.map((proxy) => ( void; onCheckDelay: () => void; onShowType: (val: boolean) => void; onSortType: (val: ProxySortType) => void; - onUrlText: (val: string) => void; onFilterText: (val: string) => void; } const ProxyHead = (props: Props) => { - const { sx = {}, showType, sortType, urlText, filterText } = props; + const { sx = {}, groupName, showType, sortType, filterText } = props; const [textState, setTextState] = useState<"url" | "filter" | null>(null); + const [testUrl, setTestUrl] = useState(delayManager.getUrl(groupName) || ""); + return ( { size="small" color="inherit" title="delay check" - onClick={props.onCheckDelay} + onClick={() => { + // Remind the user that it is custom test url + if (testUrl?.trim() && textState !== "filter") { + setTextState("url"); + } + props.onCheckDelay(); + }} > @@ -57,12 +65,12 @@ const ProxyHead = (props: Props) => { props.onSortType(((sortType + 1) % 3) as ProxySortType)} > {sortType === 0 && } - {sortType === 1 && } - {sortType === 2 && } + {sortType === 1 && } + {sortType === 2 && } { props.onUrlText(e.target.value)} + onChange={(e) => { + setTestUrl(e.target.value); + delayManager.setUrl(groupName, e.target.value); + }} sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }} /> )} diff --git a/src/components/proxy/use-filter-proxy.ts b/src/components/proxy/use-filter-proxy.ts index 231a09c..66cea1a 100644 --- a/src/components/proxy/use-filter-proxy.ts +++ b/src/components/proxy/use-filter-proxy.ts @@ -5,9 +5,6 @@ import delayManager from "../../services/delay"; const regex1 = /delay([=<>])(\d+|timeout|error)/i; const regex2 = /type=(.*)/i; -// default | alpha | delay -export type ProxySortType = 0 | 1 | 2; - /** * filter the proxy * according to the regular conditions diff --git a/src/components/proxy/use-sort-proxy.ts b/src/components/proxy/use-sort-proxy.ts new file mode 100644 index 0000000..e80736f --- /dev/null +++ b/src/components/proxy/use-sort-proxy.ts @@ -0,0 +1,38 @@ +import { useMemo } from "react"; +import { ApiType } from "../../services/types"; +import delayManager from "../../services/delay"; + +// default | delay | alpha +export type ProxySortType = 0 | 1 | 2; + +/** + * sort the proxy + */ +export default function useSortProxy( + proxies: ApiType.ProxyItem[], + groupName: string, + sortType: ProxySortType +) { + return useMemo(() => { + if (!proxies) return []; + if (sortType === 0) return proxies; + + const list = proxies.slice(); + + if (sortType === 1) { + list.sort((a, b) => { + const ad = delayManager.getDelay(a.name, groupName); + const bd = delayManager.getDelay(b.name, groupName); + + if (ad === -1) return 1; + if (bd === -1) return -1; + + return ad - bd; + }); + } else { + list.sort((a, b) => a.name.localeCompare(b.name)); + } + + return list; + }, [proxies, groupName, sortType]); +} diff --git a/src/services/delay.ts b/src/services/delay.ts index 8004144..9cdf90c 100644 --- a/src/services/delay.ts +++ b/src/services/delay.ts @@ -4,6 +4,15 @@ const hashKey = (name: string, group: string) => `${group ?? ""}::${name}`; class DelayManager { private cache = new Map(); + private urlMap = new Map(); + + setUrl(group: string, url: string) { + this.urlMap.set(group, url); + } + + getUrl(group: string) { + return this.urlMap.get(group); + } setDelay(name: string, group: string, delay: number) { this.cache.set(hashKey(name, group), [Date.now(), delay]); @@ -23,7 +32,8 @@ class DelayManager { let delay = -1; try { - const result = await getProxyDelay(name); + const url = this.getUrl(group); + const result = await getProxyDelay(name, url); delay = result.delay; } catch { delay = 1e6; // error