mirror of
https://github.com/Buriburizaem0n/admin-frontend-domain.git
synced 2026-02-05 05:00:06 +00:00
fix: websocket
This commit is contained in:
7
package-lock.json
generated
7
package-lock.json
generated
@@ -40,7 +40,6 @@
|
|||||||
"react-hook-form": "^7.53.1",
|
"react-hook-form": "^7.53.1",
|
||||||
"react-i18next": "^15.1.2",
|
"react-i18next": "^15.1.2",
|
||||||
"react-router-dom": "^6.27.0",
|
"react-router-dom": "^6.27.0",
|
||||||
"react-use-websocket": "^4.10.1",
|
|
||||||
"react-virtuoso": "^4.12.0",
|
"react-virtuoso": "^4.12.0",
|
||||||
"sonner": "^1.6.1",
|
"sonner": "^1.6.1",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
@@ -5604,12 +5603,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-use-websocket": {
|
|
||||||
"version": "4.10.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-4.10.1.tgz",
|
|
||||||
"integrity": "sha512-PrZbKj3BSy9kRU9otKEoMi0FOcEVh1abyYxJDzB/oL7kMBDBs+ZXhnWWed/sc679nPHAWMOn1gotoV04j5gJUw==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/react-virtuoso": {
|
"node_modules/react-virtuoso": {
|
||||||
"version": "4.12.0",
|
"version": "4.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.12.0.tgz",
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
"react-hook-form": "^7.53.1",
|
"react-hook-form": "^7.53.1",
|
||||||
"react-i18next": "^15.1.2",
|
"react-i18next": "^15.1.2",
|
||||||
"react-router-dom": "^6.27.0",
|
"react-router-dom": "^6.27.0",
|
||||||
"react-use-websocket": "^4.10.1",
|
|
||||||
"react-virtuoso": "^4.12.0",
|
"react-virtuoso": "^4.12.0",
|
||||||
"sonner": "^1.6.1",
|
"sonner": "^1.6.1",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
import { IconButton } from "./xui/icon-button"
|
import { IconButton } from "./xui/icon-button"
|
||||||
import { createFM } from "@/api/fm"
|
import { createFM } from "@/api/fm"
|
||||||
import { ModelCreateFMResponse, FMEntry, FMOpcode, FMIdentifier, FMWorkerData, FMWorkerOpcode } from "@/types"
|
import { ModelCreateFMResponse, FMEntry, FMOpcode, FMIdentifier, FMWorkerData, FMWorkerOpcode } from "@/types"
|
||||||
import useWebSocket from "react-use-websocket"
|
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { ColumnDef } from "@tanstack/react-table"
|
import { ColumnDef } from "@tanstack/react-table"
|
||||||
import { Folder, File } from "lucide-react"
|
import { Folder, File } from "lucide-react"
|
||||||
@@ -174,70 +173,63 @@ const FMComponent: React.FC<FMProps & JSX.IntrinsicElements["div"]> = ({ wsUrl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { sendMessage, getWebSocket } = useWebSocket(wsUrl, {
|
|
||||||
share: false,
|
|
||||||
onOpen: () => {
|
|
||||||
listFile();
|
|
||||||
},
|
|
||||||
onClose: (e) => {
|
|
||||||
console.log('WebSocket connection closed:', e);
|
|
||||||
},
|
|
||||||
onError: (e) => {
|
|
||||||
console.error(e);
|
|
||||||
toast("Websocket" + " " + t("Error"), {
|
|
||||||
description: t("Results.UnExpectedError"),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onMessage: async (e) => {
|
|
||||||
try {
|
|
||||||
const buf: ArrayBufferLike = e.data;
|
|
||||||
|
|
||||||
if (firstChunk.current) {
|
|
||||||
const identifier = new Uint8Array(buf, 0, 4);
|
|
||||||
if (arraysEqual(identifier, FMIdentifier.file)) {
|
|
||||||
worker.postMessage({ operation: 1, arrayBuffer: buf, fileName: currentBasename.current });
|
|
||||||
firstChunk.current = false;
|
|
||||||
} else if (arraysEqual(identifier, FMIdentifier.fileName)) {
|
|
||||||
const { path, fmList } = await fm.parseFMList(buf);
|
|
||||||
setPath(path);
|
|
||||||
setFMEntries(fmList);
|
|
||||||
} else if (arraysEqual(identifier, FMIdentifier.error)) {
|
|
||||||
const errBytes = buf.slice(4);
|
|
||||||
const errMsg = new TextDecoder('utf-8').decode(errBytes);
|
|
||||||
throw new Error(errMsg);
|
|
||||||
} else if (arraysEqual(identifier, FMIdentifier.complete)) {
|
|
||||||
// Upload completed
|
|
||||||
if (uOpen) setuOpen(false);
|
|
||||||
listFile();
|
|
||||||
} else {
|
|
||||||
throw new Error(t("Results.UnknownIdentifier"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await waitForHandleReady();
|
|
||||||
worker.postMessage({ operation: 2, arrayBuffer: buf, fileName: currentBasename.current });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error processing received data:', error);
|
|
||||||
toast("FM" + " " + t("Error"), {
|
|
||||||
description: t("Results.UnExpectedError"),
|
|
||||||
})
|
|
||||||
if (dOpen) setdOpen(false);
|
|
||||||
if (uOpen) setuOpen(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const socket = getWebSocket();
|
|
||||||
useEffect(() => {
|
|
||||||
if (socket && 'binaryType' in socket)
|
|
||||||
socket.binaryType = 'arraybuffer';
|
|
||||||
}, [socket])
|
|
||||||
|
|
||||||
const [currentPath, setPath] = useState('');
|
const [currentPath, setPath] = useState('');
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
listFile();
|
listFile();
|
||||||
}, [currentPath])
|
}, [currentPath])
|
||||||
|
|
||||||
|
const ws = new WebSocket(wsUrl);
|
||||||
|
ws.binaryType = 'arraybuffer';
|
||||||
|
ws.onopen = () => {
|
||||||
|
listFile();
|
||||||
|
}
|
||||||
|
ws.onclose = (e) => {
|
||||||
|
console.log('WebSocket connection closed:', e);
|
||||||
|
}
|
||||||
|
ws.onerror = (e) => {
|
||||||
|
console.error(e);
|
||||||
|
toast("Websocket" + " " + t("Error"), {
|
||||||
|
description: t("Results.UnExpectedError"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ws.onmessage = async (e) => {
|
||||||
|
try {
|
||||||
|
const buf: ArrayBufferLike = e.data;
|
||||||
|
|
||||||
|
if (firstChunk.current) {
|
||||||
|
const identifier = new Uint8Array(buf, 0, 4);
|
||||||
|
if (arraysEqual(identifier, FMIdentifier.file)) {
|
||||||
|
worker.postMessage({ operation: 1, arrayBuffer: buf, fileName: currentBasename.current });
|
||||||
|
firstChunk.current = false;
|
||||||
|
} else if (arraysEqual(identifier, FMIdentifier.fileName)) {
|
||||||
|
const { path, fmList } = await fm.parseFMList(buf);
|
||||||
|
setPath(path);
|
||||||
|
setFMEntries(fmList);
|
||||||
|
} else if (arraysEqual(identifier, FMIdentifier.error)) {
|
||||||
|
const errBytes = buf.slice(4);
|
||||||
|
const errMsg = new TextDecoder('utf-8').decode(errBytes);
|
||||||
|
throw new Error(errMsg);
|
||||||
|
} else if (arraysEqual(identifier, FMIdentifier.complete)) {
|
||||||
|
// Upload completed
|
||||||
|
if (uOpen) setuOpen(false);
|
||||||
|
listFile();
|
||||||
|
} else {
|
||||||
|
throw new Error(t("Results.UnknownIdentifier"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await waitForHandleReady();
|
||||||
|
worker.postMessage({ operation: 2, arrayBuffer: buf, fileName: currentBasename.current });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error processing received data:', error);
|
||||||
|
toast("FM" + " " + t("Error"), {
|
||||||
|
description: t("Results.UnExpectedError"),
|
||||||
|
})
|
||||||
|
if (dOpen) setdOpen(false);
|
||||||
|
if (uOpen) setuOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const listFile = () => {
|
const listFile = () => {
|
||||||
const prefix = new Int8Array([FMOpcode.List]);
|
const prefix = new Int8Array([FMOpcode.List]);
|
||||||
const pathMsg = new TextEncoder().encode(currentPath);
|
const pathMsg = new TextEncoder().encode(currentPath);
|
||||||
@@ -246,7 +238,7 @@ const FMComponent: React.FC<FMProps & JSX.IntrinsicElements["div"]> = ({ wsUrl,
|
|||||||
msg.set(prefix);
|
msg.set(prefix);
|
||||||
msg.set(pathMsg, prefix.length);
|
msg.set(pathMsg, prefix.length);
|
||||||
|
|
||||||
sendMessage(msg);
|
ws.send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadFile = (basename: string) => {
|
const downloadFile = (basename: string) => {
|
||||||
@@ -258,7 +250,7 @@ const FMComponent: React.FC<FMProps & JSX.IntrinsicElements["div"]> = ({ wsUrl,
|
|||||||
msg.set(prefix);
|
msg.set(prefix);
|
||||||
msg.set(filePathMessage, prefix.length);
|
msg.set(filePathMessage, prefix.length);
|
||||||
|
|
||||||
sendMessage(msg);
|
ws.send(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadFile = async (file: File) => {
|
const uploadFile = async (file: File) => {
|
||||||
@@ -267,13 +259,13 @@ const FMComponent: React.FC<FMProps & JSX.IntrinsicElements["div"]> = ({ wsUrl,
|
|||||||
|
|
||||||
// Send header
|
// Send header
|
||||||
const header = fm.buildUploadHeader({ path: currentPath, file: file });
|
const header = fm.buildUploadHeader({ path: currentPath, file: file });
|
||||||
sendMessage(header);
|
ws.send(header);
|
||||||
|
|
||||||
// Send data chunks
|
// Send data chunks
|
||||||
while (offset < file.size) {
|
while (offset < file.size) {
|
||||||
const chunk = file.slice(offset, offset + chunkSize);
|
const chunk = file.slice(offset, offset + chunkSize);
|
||||||
const arrayBuffer = await fm.readFileAsArrayBuffer(chunk);
|
const arrayBuffer = await fm.readFileAsArrayBuffer(chunk);
|
||||||
if (arrayBuffer) sendMessage(arrayBuffer);
|
if (arrayBuffer) ws.send(arrayBuffer);
|
||||||
offset += chunkSize;
|
offset += chunkSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { AttachAddon } from "@xterm/addon-attach";
|
|||||||
import { FitAddon } from '@xterm/addon-fit';
|
import { FitAddon } from '@xterm/addon-fit';
|
||||||
import { useRef, useEffect, useState } from "react";
|
import { useRef, useEffect, useState } from "react";
|
||||||
import { sleep } from "@/lib/utils";
|
import { sleep } from "@/lib/utils";
|
||||||
import useWebSocket from "react-use-websocket";
|
|
||||||
import { IconButton } from "./xui/icon-button";
|
import { IconButton } from "./xui/icon-button";
|
||||||
import "@xterm/xterm/css/xterm.css";
|
import "@xterm/xterm/css/xterm.css";
|
||||||
import { createTerminal } from "@/api/terminal";
|
import { createTerminal } from "@/api/terminal";
|
||||||
@@ -30,24 +29,22 @@ interface XtermProps {
|
|||||||
const XtermComponent: React.FC<XtermProps & JSX.IntrinsicElements["div"]> = ({ wsUrl, setClose, ...props }) => {
|
const XtermComponent: React.FC<XtermProps & JSX.IntrinsicElements["div"]> = ({ wsUrl, setClose, ...props }) => {
|
||||||
const terminalRef = useRef<HTMLDivElement>(null);
|
const terminalRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { sendMessage, getWebSocket } = useWebSocket(wsUrl, {
|
const ws = new WebSocket(wsUrl);
|
||||||
share: false,
|
ws.binaryType = "arraybuffer";
|
||||||
onOpen: () => {
|
ws.onopen = () => {
|
||||||
onResize();
|
onResize();
|
||||||
},
|
}
|
||||||
onClose: () => {
|
ws.onclose = () => {
|
||||||
terminal.dispose();
|
terminal.dispose();
|
||||||
setClose(true);
|
setClose(true);
|
||||||
},
|
}
|
||||||
onError: (e) => {
|
ws.onerror = (e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
toast("Websocket error", {
|
toast("Websocket error", {
|
||||||
description: "View console for details.",
|
description: "View console for details.",
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
});
|
|
||||||
|
|
||||||
const socket = getWebSocket();
|
|
||||||
const terminal = useRef(
|
const terminal = useRef(
|
||||||
new Terminal({
|
new Terminal({
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
@@ -76,7 +73,7 @@ const XtermComponent: React.FC<XtermProps & JSX.IntrinsicElements["div"]> = ({ w
|
|||||||
msg.set(prefix);
|
msg.set(prefix);
|
||||||
msg.set(resizeMessage, prefix.length);
|
msg.set(resizeMessage, prefix.length);
|
||||||
|
|
||||||
sendMessage(msg);
|
ws.send(msg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -95,25 +92,20 @@ const XtermComponent: React.FC<XtermProps & JSX.IntrinsicElements["div"]> = ({ w
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket && "binaryType" in socket && terminalRef.current) {
|
if (!ws || !terminalRef.current) return;
|
||||||
socket.binaryType = "arraybuffer";
|
|
||||||
const attachAddon = new AttachAddon(socket);
|
|
||||||
|
|
||||||
terminal.loadAddon(attachAddon);
|
|
||||||
terminal.loadAddon(fitAddon);
|
|
||||||
|
|
||||||
terminal.open(terminalRef.current);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const attachAddon = new AttachAddon(ws);
|
||||||
|
terminal.loadAddon(attachAddon);
|
||||||
|
terminal.loadAddon(fitAddon);
|
||||||
|
terminal.open(terminalRef.current);
|
||||||
window.addEventListener('resize', onResize);
|
window.addEventListener('resize', onResize);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('resize', onResize);
|
window.removeEventListener('resize', onResize);
|
||||||
if (socket) {
|
if (ws) {
|
||||||
socket.close();
|
ws.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [socket, terminal]);
|
}, [ws, terminal]);
|
||||||
|
|
||||||
return <div ref={terminalRef} {...props} />;
|
return <div ref={terminalRef} {...props} />;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user