86 lines
2.2 KiB
TypeScript
86 lines
2.2 KiB
TypeScript
import { WebSocket as ReconnectingWebSocket } from "partysocket";
|
|
import { useCallback, useEffect, useRef } from "react";
|
|
import { toast } from "sonner";
|
|
import { useAppStore } from "../stores/app-store";
|
|
|
|
function getWsUrl(): string {
|
|
const proto = location.protocol === "https:" ? "wss:" : "ws:";
|
|
const params = new URLSearchParams(location.search);
|
|
const token = params.get("token") || "";
|
|
const q = token ? `?token=${encodeURIComponent(token)}` : "";
|
|
return `${proto}//${location.host}/ws${q}`;
|
|
}
|
|
|
|
export function useWebSocket() {
|
|
const wsRef = useRef<ReconnectingWebSocket | null>(null);
|
|
|
|
const sendJSON = useCallback((obj: Record<string, unknown>) => {
|
|
const ws = wsRef.current;
|
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
ws.send(JSON.stringify(obj));
|
|
}
|
|
}, []);
|
|
|
|
const sendBinary = useCallback((data: Int16Array) => {
|
|
const ws = wsRef.current;
|
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
ws.send(data.buffer as ArrayBuffer);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
useAppStore.getState().setConnectionStatus("connecting");
|
|
|
|
const ws = new ReconnectingWebSocket(getWsUrl(), undefined, {
|
|
minReconnectionDelay: 1000,
|
|
maxReconnectionDelay: 16000,
|
|
});
|
|
ws.binaryType = "arraybuffer";
|
|
|
|
ws.onopen = () => {
|
|
useAppStore.getState().setConnectionStatus("connected");
|
|
};
|
|
|
|
ws.onmessage = (e: MessageEvent) => {
|
|
if (typeof e.data !== "string") return;
|
|
try {
|
|
const msg = JSON.parse(e.data);
|
|
const store = useAppStore.getState();
|
|
switch (msg.type) {
|
|
case "partial":
|
|
store.setPreview(msg.text || "", false);
|
|
break;
|
|
case "final":
|
|
store.setPreview(msg.text || "", true);
|
|
if (msg.text) store.addHistory(msg.text);
|
|
break;
|
|
case "pasted":
|
|
toast.success("已粘贴");
|
|
break;
|
|
case "error":
|
|
toast.error(msg.message || "错误");
|
|
break;
|
|
}
|
|
} catch {
|
|
// Ignore malformed messages
|
|
}
|
|
};
|
|
|
|
ws.onclose = () => {
|
|
const store = useAppStore.getState();
|
|
store.setConnectionStatus("disconnected");
|
|
if (store.recording) store.setRecording(false);
|
|
if (store.pendingStart) store.setPendingStart(false);
|
|
};
|
|
|
|
wsRef.current = ws;
|
|
|
|
return () => {
|
|
ws.close();
|
|
wsRef.current = null;
|
|
};
|
|
}, []);
|
|
|
|
return { sendJSON, sendBinary };
|
|
}
|