import { serverRequest } from '@/utils/request' type TerminalCallback = (data: string) => void interface TerminalConnection { ws: WebSocket callbacks: Set isConnected: boolean buffer: string[] // 添加缓存数组 } export interface TerminalSession { id: string } export interface TerminalInfo { id: string } class TerminalManager { private connections: Map = new Map() private readonly MAX_BUFFER_SIZE = 1000 // 限制缓存大小 async createTerminal(cols: number, rows: number): Promise { const { data } = await serverRequest.post>( '/Log/terminal/create', { cols, rows } ) return data.data } async closeTerminal(id: string): Promise { await serverRequest.post(`/Log/terminal/${id}/close`) } async getTerminalList(): Promise { const { data } = await serverRequest.get>( '/Log/terminal/list' ) return data.data } connectTerminal(id: string, callback: TerminalCallback): WebSocket { let conn = this.connections.get(id) if (!conn) { const url = new URL(window.location.href) url.protocol = url.protocol.replace('http', 'ws') url.pathname = `/api/ws/terminal` url.searchParams.set('id', id) const token = JSON.parse(localStorage.getItem('token') || '') if (!token) { throw new Error('No token found') } url.searchParams.set('token', token) const ws = new WebSocket(url.toString()) conn = { ws, callbacks: new Set([callback]), isConnected: false, buffer: [] // 初始化缓存 } ws.onmessage = (event) => { const data = event.data // 保存到缓存 conn?.buffer.push(data) if ((conn?.buffer.length ?? 0) > this.MAX_BUFFER_SIZE) { conn?.buffer.shift() } conn?.callbacks.forEach((cb) => cb(data)) } ws.onopen = () => { if (conn) conn.isConnected = true } ws.onclose = () => { if (conn) conn.isConnected = false } this.connections.set(id, conn) } else { conn.callbacks.add(callback) // 恢复历史内容 conn.buffer.forEach((data) => callback(data)) } return conn.ws } disconnectTerminal(id: string, callback: TerminalCallback) { const conn = this.connections.get(id) if (!conn) return conn.callbacks.delete(callback) } removeTerminal(id: string) { const conn = this.connections.get(id) if (conn?.ws.readyState === WebSocket.OPEN) { conn.ws.close() } this.connections.delete(id) } sendInput(id: string, data: string) { const conn = this.connections.get(id) if (conn?.ws.readyState === WebSocket.OPEN) { conn.ws.send(JSON.stringify({ type: 'input', data })) } } } const terminalManager = new TerminalManager() export default terminalManager