diff --git a/backend/app/api/v1/terminal.go b/backend/app/api/v1/terminal.go
index 7f6e74aec..52d5b933c 100644
--- a/backend/app/api/v1/terminal.go
+++ b/backend/app/api/v1/terminal.go
@@ -1,6 +1,8 @@
package v1
import (
+ "encoding/base64"
+ "encoding/json"
"fmt"
"net/http"
"strconv"
@@ -196,7 +198,15 @@ func wshandleError(ws *websocket.Conn, err error) bool {
global.LOG.Errorf("handler ws faled:, err: %v", err)
dt := time.Now().Add(time.Second)
if ctlerr := ws.WriteControl(websocket.CloseMessage, []byte(err.Error()), dt); ctlerr != nil {
- _ = ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))
+ wsData, err := json.Marshal(terminal.WsMsg{
+ Type: terminal.WsMsgCmd,
+ Data: base64.StdEncoding.EncodeToString([]byte(err.Error())),
+ })
+ if err != nil {
+ _ = ws.WriteMessage(websocket.TextMessage, []byte("{\"type\":\"cmd\",\"data\":\"failed to encoding to json\"}"))
+ } else {
+ _ = ws.WriteMessage(websocket.TextMessage, wsData)
+ }
}
return true
}
diff --git a/backend/utils/terminal/ws_local_session.go b/backend/utils/terminal/ws_local_session.go
index 04350bc3a..d9221b6cc 100644
--- a/backend/utils/terminal/ws_local_session.go
+++ b/backend/utils/terminal/ws_local_session.go
@@ -52,11 +52,17 @@ func (sws *LocalWsSession) handleSlaveEvent(exitCh chan bool) {
func (sws *LocalWsSession) masterWrite(data []byte) error {
sws.writeMutex.Lock()
defer sws.writeMutex.Unlock()
- err := sws.wsConn.WriteMessage(websocket.TextMessage, data)
+ wsData, err := json.Marshal(WsMsg{
+ Type: WsMsgCmd,
+ Data: base64.StdEncoding.EncodeToString(data),
+ })
+ if err != nil {
+ return errors.Wrapf(err, "failed to encoding to json")
+ }
+ err = sws.wsConn.WriteMessage(websocket.TextMessage, wsData)
if err != nil {
return errors.Wrapf(err, "failed to write to master")
}
-
return nil
}
@@ -74,21 +80,27 @@ func (sws *LocalWsSession) receiveWsMsg(exitCh chan bool) {
global.LOG.Errorf("reading webSocket message failed, err: %v", err)
return
}
- msgObj := wsMsg{}
+ msgObj := WsMsg{}
_ = json.Unmarshal(wsData, &msgObj)
switch msgObj.Type {
- case wsMsgResize:
+ case WsMsgResize:
if msgObj.Cols > 0 && msgObj.Rows > 0 {
if err := sws.slave.ResizeTerminal(msgObj.Cols, msgObj.Rows); err != nil {
global.LOG.Errorf("ssh pty change windows size failed, err: %v", err)
}
}
- case wsMsgCmd:
+ case WsMsgCmd:
decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Data)
if err != nil {
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/backend/utils/terminal/ws_session.go b/backend/utils/terminal/ws_session.go
index 11078517b..7c30c65ab 100644
--- a/backend/utils/terminal/ws_session.go
+++ b/backend/utils/terminal/ws_session.go
@@ -35,17 +35,17 @@ func (w *safeBuffer) Reset() {
}
const (
- wsMsgCmd = "cmd"
- wsMsgResize = "resize"
- wsMsgHeartbeat = "heartbeat"
+ WsMsgCmd = "cmd"
+ WsMsgResize = "resize"
+ WsMsgHeartbeat = "heartbeat"
)
-type wsMsg struct {
+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
- Timestamp int `json:"timestamp,omitempty"` // wsMsgHeartbeat
+ 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 {
@@ -127,22 +127,22 @@ func (sws *LogicSshWsSession) receiveWsMsg(exitCh chan bool) {
if err != nil {
return
}
- msgObj := wsMsg{}
+ msgObj := WsMsg{}
_ = json.Unmarshal(wsData, &msgObj)
switch msgObj.Type {
- case wsMsgResize:
+ case WsMsgResize:
if msgObj.Cols > 0 && msgObj.Rows > 0 {
if err := sws.session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
global.LOG.Errorf("ssh pty change windows size failed, err: %v", err)
}
}
- case wsMsgCmd:
+ case WsMsgCmd:
decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Data)
if err != nil {
global.LOG.Errorf("websock cmd string base64 decoding failed, err: %v", err)
}
sws.sendWebsocketInputCommandToSshSessionStdinPipe(decodeBytes)
- case wsMsgHeartbeat:
+ case WsMsgHeartbeat:
// 接收到心跳包后将心跳包原样返回,可以用于网络延迟检测等情况
err = wsConn.WriteMessage(websocket.TextMessage, wsData)
if err != nil {
@@ -173,8 +173,8 @@ func (sws *LogicSshWsSession) sendComboOutput(exitCh chan bool) {
}
bs := sws.comboOutput.Bytes()
if len(bs) > 0 {
- wsData, err := json.Marshal(wsMsg{
- Type: wsMsgCmd,
+ wsData, err := json.Marshal(WsMsg{
+ Type: WsMsgCmd,
Data: base64.StdEncoding.EncodeToString(bs),
})
if err != nil {
diff --git a/frontend/src/components/terminal/index.vue b/frontend/src/components/terminal/index.vue
index e13cffdb5..dd6c6e19f 100644
--- a/frontend/src/components/terminal/index.vue
+++ b/frontend/src/components/terminal/index.vue
@@ -68,14 +68,16 @@ const initError = (errorInfo: string) => {
}
};
-function onClose() {
+function onClose(isKeepShow: boolean = false) {
window.removeEventListener('resize', changeTerminalSize);
try {
terminalSocket.value?.close();
} catch {}
- try {
- term.value.dispose();
- } catch {}
+ if (!isKeepShow) {
+ try {
+ term.value.dispose();
+ } catch {}
+ }
}
// terminal 相关代码 start
@@ -162,7 +164,7 @@ const onWSReceive = (message: MessageEvent) => {
switch (wsMsg.type) {
case 'cmd': {
term.value.element && term.value.focus();
- term.value.write(Base64.decode(wsMsg.data));
+ wsMsg.data && term.value.write(Base64.decode(wsMsg.data)); // 这里理论上不用判断,但是Redis和Ctr还没实现Alive处理,所以exit后会一直发数据,todo
break;
}
case 'heartbeat': {
diff --git a/frontend/src/views/container/container/terminal/index.vue b/frontend/src/views/container/container/terminal/index.vue
index daca454d8..070818750 100644
--- a/frontend/src/views/container/container/terminal/index.vue
+++ b/frontend/src/views/container/container/terminal/index.vue
@@ -44,7 +44,7 @@
{{ $t('commons.button.conn') }}