diff --git a/backend/utils/terminal/ws_session.go b/backend/utils/terminal/ws_session.go index 04e4b579b..11078517b 100644 --- a/backend/utils/terminal/ws_session.go +++ b/backend/utils/terminal/ws_session.go @@ -35,15 +35,17 @@ func (w *safeBuffer) Reset() { } const ( - wsMsgCmd = "cmd" - wsMsgResize = "resize" + wsMsgCmd = "cmd" + wsMsgResize = "resize" + wsMsgHeartbeat = "heartbeat" ) type wsMsg struct { - Type string `json:"type"` - Data string `json:"data,omitempty"` // wsMsgCmd - Cols int `json:"cols,omitempty"` // wsMsgResize - Rows int `json:"rows,omitempty"` // wsMsgResize + Type string `json:"type"` + Data string `json:"data,omitempty"` // wsMsgCmd + Cols int `json:"cols,omitempty"` // wsMsgResize + Rows int `json:"rows,omitempty"` // wsMsgResize + Timestamp int `json:"timestamp,omitempty"` // wsMsgHeartbeat } type LogicSshWsSession struct { @@ -140,6 +142,12 @@ func (sws *LogicSshWsSession) receiveWsMsg(exitCh chan bool) { global.LOG.Errorf("websock cmd string base64 decoding failed, err: %v", err) } sws.sendWebsocketInputCommandToSshSessionStdinPipe(decodeBytes) + case wsMsgHeartbeat: + // 接收到心跳包后将心跳包原样返回,可以用于网络延迟检测等情况 + err = wsConn.WriteMessage(websocket.TextMessage, wsData) + if err != nil { + global.LOG.Errorf("ssh sending heartbeat to webSocket failed, err: %v", err) + } } } } diff --git a/frontend/src/views/host/terminal/terminal/terminal.vue b/frontend/src/views/host/terminal/terminal/terminal.vue index f23bf1ccd..bc9784fce 100644 --- a/frontend/src/views/host/terminal/terminal/terminal.vue +++ b/frontend/src/views/host/terminal/terminal/terminal.vue @@ -34,6 +34,7 @@ const webSocketReady = ref(false); const termReady = ref(false); const terminalSocket = ref(); const term = ref(); +const heartbeatTimer = ref(); const readyWatcher = watch( () => webSocketReady.value && termReady.value, @@ -59,6 +60,10 @@ const onWSReceive = (message: MessageEvent) => { } break; } + case 'heartbeat': { + console.debug('latency', new Date().getTime() - wsMsg.timestamp, 'ms'); + break; + } } }; @@ -71,6 +76,9 @@ const errorRealTerminal = (ex: any) => { }; const closeRealTerminal = (ev: CloseEvent) => { + if (heartbeatTimer.value) { + clearInterval(heartbeatTimer.value); + } if (term.value) { term.value.write(ev.reason); } @@ -125,6 +133,16 @@ const initTerm = () => { terminalSocket.value.onmessage = onWSReceive; terminalSocket.value.onclose = closeRealTerminal; terminalSocket.value.onerror = errorRealTerminal; + heartbeatTimer.value = setInterval(() => { + if (isWsOpen()) { + terminalSocket.value!.send( + JSON.stringify({ + type: 'heartbeat', + timestamp: `${new Date().getTime()}`, + }), + ); + } + }, 1000 * 10); term.value.onData((data: any) => { if (isWsOpen()) { terminalSocket.value!.send(