refactor: Use Tauri WebSocket

This commit is contained in:
MystiPanda 2024-01-14 17:30:18 +08:00
parent 1c9bc00acc
commit 71103bb7b9
9 changed files with 142 additions and 47 deletions

View File

@ -44,7 +44,8 @@
"recoil": "^0.7.7", "recoil": "^0.7.7",
"snarkdown": "^2.0.0", "snarkdown": "^2.0.0",
"swr": "^1.3.0", "swr": "^1.3.0",
"tar": "^6.2.0" "tar": "^6.2.0",
"tauri-plugin-websocket-api": "github:tauri-apps/tauri-plugin-websocket#v1"
}, },
"devDependencies": { "devDependencies": {
"@actions/github": "^5.1.1", "@actions/github": "^5.1.1",

22
pnpm-lock.yaml generated
View File

@ -92,6 +92,9 @@ dependencies:
tar: tar:
specifier: ^6.2.0 specifier: ^6.2.0
version: 6.2.0 version: 6.2.0
tauri-plugin-websocket-api:
specifier: github:tauri-apps/tauri-plugin-websocket#v1
version: github.com/tauri-apps/tauri-plugin-websocket/ef0af116e47eea18af92b27629f00db996fd2e15
devDependencies: devDependencies:
"@actions/github": "@actions/github":
@ -1711,6 +1714,14 @@ packages:
engines: { node: ">= 14.6.0", npm: ">= 6.6.0", yarn: ">= 1.19.1" } engines: { node: ">= 14.6.0", npm: ">= 6.6.0", yarn: ">= 1.19.1" }
dev: false dev: false
/@tauri-apps/api@1.5.3:
resolution:
{
integrity: sha512-zxnDjHHKjOsrIzZm6nO5Xapb/BxqUq1tc7cGkFXsFkGTsSWgCPH1D8mm0XS9weJY2OaR73I3k3S+b7eSzJDfqA==,
}
engines: { node: ">= 14.6.0", npm: ">= 6.6.0", yarn: ">= 1.19.1" }
dev: false
/@tauri-apps/cli-darwin-arm64@1.5.6: /@tauri-apps/cli-darwin-arm64@1.5.6:
resolution: resolution:
{ {
@ -4090,3 +4101,14 @@ packages:
} }
engines: { node: ">= 6" } engines: { node: ">= 6" }
dev: false dev: false
github.com/tauri-apps/tauri-plugin-websocket/ef0af116e47eea18af92b27629f00db996fd2e15:
resolution:
{
tarball: https://codeload.github.com/tauri-apps/tauri-plugin-websocket/tar.gz/ef0af116e47eea18af92b27629f00db996fd2e15,
}
name: tauri-plugin-websocket-api
version: 0.0.0
dependencies:
"@tauri-apps/api": 1.5.3
dev: false

93
src-tauri/Cargo.lock generated
View File

@ -595,6 +595,7 @@ dependencies = [
"sysproxy", "sysproxy",
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-websocket",
"tokio", "tokio",
"warp", "warp",
"which 5.0.0", "which 5.0.0",
@ -1786,7 +1787,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http 0.2.11",
"indexmap 2.1.0", "indexmap 2.1.0",
"slab", "slab",
"tokio", "tokio",
@ -1833,7 +1834,7 @@ dependencies = [
"base64 0.21.5", "base64 0.21.5",
"bytes", "bytes",
"headers-core", "headers-core",
"http", "http 0.2.11",
"httpdate", "httpdate",
"mime", "mime",
"sha1", "sha1",
@ -1845,7 +1846,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
dependencies = [ dependencies = [
"http", "http 0.2.11",
] ]
[[package]] [[package]]
@ -1923,6 +1924,17 @@ dependencies = [
"itoa 1.0.9", "itoa 1.0.9",
] ]
[[package]]
name = "http"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
dependencies = [
"bytes",
"fnv",
"itoa 1.0.9",
]
[[package]] [[package]]
name = "http-body" name = "http-body"
version = "0.4.5" version = "0.4.5"
@ -1930,7 +1942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http 0.2.11",
"pin-project-lite", "pin-project-lite",
] ]
@ -1969,7 +1981,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2",
"http", "http 0.2.11",
"http-body", "http-body",
"httparse", "httparse",
"httpdate", "httpdate",
@ -1989,7 +2001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"http", "http 0.2.11",
"hyper", "hyper",
"rustls", "rustls",
"tokio", "tokio",
@ -2631,7 +2643,7 @@ dependencies = [
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-util", "futures-util",
"http", "http 0.2.11",
"httparse", "httparse",
"log 0.4.20", "log 0.4.20",
"memchr", "memchr",
@ -3696,7 +3708,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2",
"http", "http 0.2.11",
"http-body", "http-body",
"hyper", "hyper",
"hyper-rustls", "hyper-rustls",
@ -4620,7 +4632,7 @@ dependencies = [
"glob", "glob",
"gtk", "gtk",
"heck 0.4.1", "heck 0.4.1",
"http", "http 0.2.11",
"ignore", "ignore",
"infer 0.9.0", "infer 0.9.0",
"minisign-verify", "minisign-verify",
@ -4719,6 +4731,23 @@ dependencies = [
"tauri-utils", "tauri-utils",
] ]
[[package]]
name = "tauri-plugin-websocket"
version = "0.0.0"
source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#0cdbde386fd7225810a5a57b039d551d08995b29"
dependencies = [
"futures-util",
"http 1.0.0",
"log 0.4.20",
"rand 0.8.5",
"serde",
"serde_json",
"tauri",
"thiserror",
"tokio",
"tokio-tungstenite 0.21.0",
]
[[package]] [[package]]
name = "tauri-runtime" name = "tauri-runtime"
version = "0.14.1" version = "0.14.1"
@ -4726,7 +4755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07f8e9e53e00e9f41212c115749e87d5cd2a9eebccafca77a19722eeecd56d43" checksum = "07f8e9e53e00e9f41212c115749e87d5cd2a9eebccafca77a19722eeecd56d43"
dependencies = [ dependencies = [
"gtk", "gtk",
"http", "http 0.2.11",
"http-range", "http-range",
"rand 0.8.5", "rand 0.8.5",
"raw-window-handle", "raw-window-handle",
@ -5057,7 +5086,21 @@ dependencies = [
"futures-util", "futures-util",
"log 0.4.20", "log 0.4.20",
"tokio", "tokio",
"tungstenite", "tungstenite 0.20.1",
]
[[package]]
name = "tokio-tungstenite"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
dependencies = [
"futures-util",
"log 0.4.20",
"native-tls",
"tokio",
"tokio-native-tls",
"tungstenite 0.21.0",
] ]
[[package]] [[package]]
@ -5234,7 +5277,7 @@ dependencies = [
"byteorder", "byteorder",
"bytes", "bytes",
"data-encoding", "data-encoding",
"http", "http 0.2.11",
"httparse", "httparse",
"log 0.4.20", "log 0.4.20",
"rand 0.8.5", "rand 0.8.5",
@ -5244,6 +5287,26 @@ dependencies = [
"utf-8", "utf-8",
] ]
[[package]]
name = "tungstenite"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
dependencies = [
"byteorder",
"bytes",
"data-encoding",
"http 1.0.0",
"httparse",
"log 0.4.20",
"native-tls",
"rand 0.8.5",
"sha1",
"thiserror",
"url",
"utf-8",
]
[[package]] [[package]]
name = "typemap-ors" name = "typemap-ors"
version = "1.0.0" version = "1.0.0"
@ -5472,7 +5535,7 @@ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"headers", "headers",
"http", "http 0.2.11",
"hyper", "hyper",
"log 0.4.20", "log 0.4.20",
"mime", "mime",
@ -5487,7 +5550,7 @@ dependencies = [
"serde_urlencoded", "serde_urlencoded",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tokio-tungstenite", "tokio-tungstenite 0.20.1",
"tokio-util", "tokio-util",
"tower-service", "tower-service",
"tracing", "tracing",
@ -6182,7 +6245,7 @@ dependencies = [
"glib", "glib",
"gtk", "gtk",
"html5ever 0.25.2", "html5ever 0.25.2",
"http", "http 0.2.11",
"kuchiki", "kuchiki",
"libc", "libc",
"log 0.4.20", "log 0.4.20",

View File

@ -40,6 +40,7 @@ tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
reqwest = { version = "0.11", features = ["json", "rustls-tls"] } reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
tauri = { version = "1.5", features = [ "notification-all", "icon-png", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] } tauri = { version = "1.5", features = [ "notification-all", "icon-png", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] }
tauri-plugin-websocket = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
runas = "=1.0.0" # 高版本会返回错误 Status runas = "=1.0.0" # 高版本会返回错误 Status

View File

@ -24,6 +24,7 @@ fn main() -> std::io::Result<()> {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut builder = tauri::Builder::default() let mut builder = tauri::Builder::default()
.plugin(tauri_plugin_websocket::init())
.system_tray(SystemTray::new()) .system_tray(SystemTray::new())
.setup(|app| { .setup(|app| {
resolve::resolve_setup(app); resolve::resolve_setup(app);

View File

@ -30,7 +30,7 @@ export const LayoutTraffic = () => {
useLogSetup(); useLogSetup();
const { connect, disconnect } = useWebsocket((event) => { const { connect, disconnect } = useWebsocket((event) => {
const data = JSON.parse(event.data) as ITrafficItem; const data = JSON.parse(event) as ITrafficItem;
trafficRef.current?.appendData(data); trafficRef.current?.appendData(data);
setTraffic(data); setTraffic(data);
}); });
@ -52,7 +52,7 @@ export const LayoutTraffic = () => {
const memoryWs = useWebsocket( const memoryWs = useWebsocket(
(event) => { (event) => {
setMemory(JSON.parse(event.data)); setMemory(JSON.parse(event));
}, },
{ onError: () => setMemory({ inuse: 0 }) } { onError: () => setMemory({ inuse: 0 }) }
); );
@ -63,7 +63,9 @@ export const LayoutTraffic = () => {
memoryWs.connect( memoryWs.connect(
`ws://${server}/memory?token=${encodeURIComponent(secret)}` `ws://${server}/memory?token=${encodeURIComponent(secret)}`
); );
return () => memoryWs.disconnect(); return () => {
memoryWs.disconnect();
};
}, [clashInfo, pageVisible, displayMemory]); }, [clashInfo, pageVisible, displayMemory]);
const [up, upUnit] = parseTraffic(traffic.up); const [up, upUnit] = parseTraffic(traffic.up);

View File

@ -16,7 +16,7 @@ export const useLogSetup = () => {
const setLogData = useSetRecoilState(atomLogData); const setLogData = useSetRecoilState(atomLogData);
const { connect, disconnect } = useWebsocket((event) => { const { connect, disconnect } = useWebsocket((event) => {
const data = JSON.parse(event.data) as ILogItem; const data = JSON.parse(event) as ILogItem;
const time = dayjs().format("MM-DD HH:mm:ss"); const time = dayjs().format("MM-DD HH:mm:ss");
setLogData((l) => { setLogData((l) => {
if (l.length >= MAX_LOG_NUM) l.shift(); if (l.length >= MAX_LOG_NUM) l.shift();

View File

@ -1,20 +1,19 @@
import { useRef } from "react"; import { useRef } from "react";
import WebSocket from "tauri-plugin-websocket-api";
export type WsMsgFn = (event: MessageEvent<any>) => void; export type WsMsgFn = (event: string) => void;
export interface WsOptions { export interface WsOptions {
errorCount?: number; // default is 5 errorCount?: number; // default is 5
retryInterval?: number; // default is 2500 onError?: (e: any) => void;
onError?: () => void;
} }
export const useWebsocket = (onMessage: WsMsgFn, options?: WsOptions) => { export const useWebsocket = (onMessage: WsMsgFn, options?: WsOptions) => {
const wsRef = useRef<WebSocket | null>(null); const wsRef = useRef<WebSocket | null>(null);
const timerRef = useRef<any>(null); const timerRef = useRef<any>(null);
const disconnect = () => { const disconnect = async () => {
if (wsRef.current) { if (wsRef.current) {
wsRef.current.close(); await wsRef.current.disconnect();
wsRef.current = null; wsRef.current = null;
} }
if (timerRef.current) { if (timerRef.current) {
@ -22,31 +21,37 @@ export const useWebsocket = (onMessage: WsMsgFn, options?: WsOptions) => {
} }
}; };
const connect = (url: string) => { const connect = async (url: string) => {
let errorCount = options?.errorCount ?? 5; let errorCount = options?.errorCount ?? 5;
if (!url) return; if (!url) return;
const connectHelper = async () => {
await disconnect();
const ws = await WebSocket.connect(url);
const connectHelper = () => { ws.addListener((event) => {
disconnect(); switch (event.type) {
case "Text": {
const ws = new WebSocket(url); onMessage(event.data);
break;
}
default: {
break;
}
}
});
wsRef.current = ws; wsRef.current = ws;
};
ws.addEventListener("message", onMessage); try {
ws.addEventListener("error", () => { await connectHelper();
} catch (e) {
errorCount -= 1; errorCount -= 1;
if (errorCount >= 0) { if (errorCount >= 0) {
timerRef.current = setTimeout(connectHelper, 2500); timerRef.current = setTimeout(connectHelper, 2500);
} else { } else {
disconnect(); await disconnect();
options?.onError?.(); options?.onError?.(e);
}
} }
});
};
connectHelper();
}; };
return { connect, disconnect }; return { connect, disconnect };

View File

@ -61,7 +61,7 @@ const ConnectionsPage = () => {
const { connect, disconnect } = useWebsocket( const { connect, disconnect } = useWebsocket(
(event) => { (event) => {
// meta v1.15.0 出现data.connections为null的情况 // meta v1.15.0 出现data.connections为null的情况
const data = JSON.parse(event.data) as IConnections; const data = JSON.parse(event) as IConnections;
// 尽量与前一次connections的展示顺序保持一致 // 尽量与前一次connections的展示顺序保持一致
setConnData((old) => { setConnData((old) => {
const oldConn = old.connections; const oldConn = old.connections;
@ -94,7 +94,7 @@ const ConnectionsPage = () => {
return { ...data, connections }; return { ...data, connections };
}); });
}, },
{ errorCount: 3, retryInterval: 1000 } { errorCount: 3 }
); );
useEffect(() => { useEffect(() => {