From e4807953837c8fad259d31c2db906cc41da9e2c7 Mon Sep 17 00:00:00 2001 From: divisey <18656007202@163.com> Date: Fri, 9 Aug 2024 14:59:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20update=20network=20state?= =?UTF-8?q?=20(#950)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- enjoy/src/i18n/en.json | 4 +- enjoy/src/i18n/zh-CN.json | 6 +- .../components/preferences/network-state.tsx | 252 ++++++++++-------- 3 files changed, 148 insertions(+), 114 deletions(-) diff --git a/enjoy/src/i18n/en.json b/enjoy/src/i18n/en.json index aa23dd2f..297b2bd3 100644 --- a/enjoy/src/i18n/en.json +++ b/enjoy/src/i18n/en.json @@ -655,8 +655,10 @@ "enrollments": "Enrollments", "noLikesYet": "No likes yet", "apiConnectTime": "API Connect Time ({{apiUrl}})", + "storageConnectTime": "Storage Connect Time", "ipInfo": "IP Information", "platformInfo": "Platform Information", "networkState": "Network State", - "connectError": "Connect Error" + "connectError": "Connect Error", + "refresh": "refresh" } diff --git a/enjoy/src/i18n/zh-CN.json b/enjoy/src/i18n/zh-CN.json index 3d024095..fb59bc71 100644 --- a/enjoy/src/i18n/zh-CN.json +++ b/enjoy/src/i18n/zh-CN.json @@ -654,9 +654,11 @@ "enrollNow": "加入练习", "enrollments": "参加的课程", "noLikesYet": "还没有点赞", - "apiConnectTime": "API 延时 ({{apiUrl}})", + "apiConnectTime": "接口服务器延时 ({{apiUrl}})", + "storageConnectTime": "资源服务器延时", "ipInfo": "IP 信息", "platformInfo": "设备信息", "networkState": "网络状态", - "connectError": "连接错误" + "connectError": "连接错误", + "refresh": "刷新" } diff --git a/enjoy/src/renderer/components/preferences/network-state.tsx b/enjoy/src/renderer/components/preferences/network-state.tsx index 41b63845..aa3ecb73 100644 --- a/enjoy/src/renderer/components/preferences/network-state.tsx +++ b/enjoy/src/renderer/components/preferences/network-state.tsx @@ -1,77 +1,133 @@ -import { Client } from "@/api"; import { t } from "i18next"; -import { useState, useContext, useEffect, useMemo } from "react"; +import React, { + useState, + useContext, + useEffect, + useMemo, + useRef, + useImperativeHandle, +} from "react"; import { AppSettingsProviderContext } from "@renderer/context"; import { LoaderIcon } from "lucide-react"; +import { STORAGE_WORKER_ENDPOINT } from "@/constants"; +import { Button } from "@/renderer/components/ui"; export const NetworkState = () => { const { apiUrl, EnjoyApp } = useContext(AppSettingsProviderContext); - - let timeoutId: ReturnType = null; - - const [apiConnected, setApiConnected] = useState(false); - const [apiConnecting, setApiConnecting] = useState(false); - const [apiConnectError, setApiConnectError] = useState(false); - const [apiConnectTime, setApiConnectTime] = useState(null); - - const [ipInfoError, setIpInfoError] = useState(false); - const [ipInfo, setIpInfo] = useState(null); - - const [platformInfo, setPlatformInfo] = useState(null); + const [refreshing, setRefreshing] = useState(false); + const apiStateRef = useRef(null); + const storeageStateRef = useRef(null); + const ipStateRef = useRef(null); const items = useMemo(() => { - const apiStateColor = - apiConnectTime < 200 - ? "text-green-500" - : apiConnectTime < 800 - ? "text-yellow-500" - : "text-red-500"; - return [ { title: t("apiConnectTime", { apiUrl }), - loading: !apiConnected && apiConnecting, - error: apiConnectError, - value: {apiConnectTime}ms, + ref: apiStateRef, + refresh: true, + action: () => getConnectDelayTime(apiUrl + "/up"), + }, + { + title: t("storageConnectTime"), + refresh: true, + ref: storeageStateRef, + action: () => getConnectDelayTime(STORAGE_WORKER_ENDPOINT), }, { title: t("ipInfo"), - loading: false, - error: ipInfoError, - value: ( - - {ipInfo - ? `${ipInfo.ip} (${ipInfo.city}, ${ipInfo.country_name})` - : "-"} - - ), + ref: ipStateRef, + refresh: true, + action: async () => + await fetch("https://ipapi.co/json") + .then((resp) => resp.json()) + .then((info) => ({ + text: `${info.ip} (${info.city}, ${info.country_name})`, + })), }, { title: t("platformInfo"), - loading: false, - error: false, - value: ( - - {platformInfo - ? `${platformInfo.platform} ${platformInfo.arch} ${platformInfo.version}` - : "-"} - - ), + refresh: false, + action: async () => + await EnjoyApp.app.getPlatformInfo().then((info) => ({ + text: `${info.platform} ${info.arch} ${info.version}`, + })), }, ]; - }, [ - apiConnectTime, - apiConnecting, - apiConnected, - apiConnectError, - ipInfo, - ipInfoError, - platformInfo, - ]); + }, [apiUrl]); + + async function handleRefresh() { + if (refreshing) return; + setRefreshing(true); + + await Promise.all([ + apiStateRef?.current.getConnectState({ force: true }), + storeageStateRef?.current.getConnectState({ force: true }), + ipStateRef?.current.getConnectState({ force: true }), + ]); + + setRefreshing(false); + } + + async function getConnectDelayTime(url: string) { + const startTime = new Date().getTime(); + await fetch(url); + const duration = new Date().getTime() - startTime; + + return { + color: + duration < 200 + ? "text-green-500" + : duration < 800 + ? "text-yellow-500" + : "text-red-500", + text: `${duration}ms`, + }; + } + + return ( +
+
+
{t("networkState")}
+ +
+ +
+ {items.map((item, index) => ( + + ))} +
+
+ ); +}; + +const NetworkStateItem = React.forwardRef(function ( + { + title, + action, + refresh, + }: { + title: string; + refresh: boolean; + action: () => Promise<{ color?: string; text: string }>; + }, + ref +) { + useImperativeHandle(ref, () => { + return { getConnectState }; + }); + + let timeoutId: ReturnType = null; + + const [connected, setConnected] = useState(false); + const [connecting, setConnecting] = useState(false); + const [connectError, setConnectError] = useState(false); + const [color, setColor] = useState(""); + const [text, setText] = useState(""); useEffect(() => { - pollingAction(); - getPlatformInfo(); + startPolling(); return () => { if (timeoutId) { @@ -80,71 +136,45 @@ export const NetworkState = () => { }; }, []); - async function pollingAction() { - await Promise.all([getApiConnectTime(), getIpInfo()]); + async function startPolling() { + await getConnectState(); - timeoutId = setTimeout(() => pollingAction(), 10000); - } - - async function getApiConnectTime() { - setApiConnecting(true); - try { - const client = new Client({ baseUrl: apiUrl }); - const startTime = new Date().getTime(); - await client.up(); - const endTime = new Date().getTime(); - - setApiConnectTime(endTime - startTime); - setApiConnected(true); - } catch (error) { - setApiConnectError(true); - setApiConnected(false); - } - setApiConnecting(false); - } - - async function getIpInfo() { - try { - await fetch("https://ipapi.co/json") - .then((resp) => resp.json()) - .then((info) => setIpInfo(info)); - } catch (error) { - setIpInfoError(true); + if (refresh) { + timeoutId = setTimeout(() => startPolling(), 10000); } } - async function getPlatformInfo() { - const info = await EnjoyApp.app.getPlatformInfo(); - setPlatformInfo(info); + async function getConnectState( + { force }: { force?: boolean } = { force: false } + ) { + if (force) setConnected(false); + + setConnecting(true); + try { + const { color, text } = await action(); + + setColor(color); + setText(text); + setConnected(true); + } catch (error) { + setConnectError(true); + setConnected(false); + } + setConnecting(false); } return ( -
-
-
{t("networkState")}
-
- -
- {items.map((item, index) => { - return ( -
-
{item.title}
-
- {item.loading ? ( - - ) : item.error ? ( - {t("connectError")} - ) : ( - item.value - )} -
-
- ); - })} +
+
{title}
+
+ {!connected && connecting ? ( + + ) : connectError ? ( + {t("connectError")} + ) : ( + {text} + )}
); -}; +});