Refactor: Rename NanoKVM to BatchuKVM and update server URL
This commit is contained in:
110
server/service/vm/terminal.go
Normal file
110
server/service/vm/terminal.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/creack/pty"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
messageWait = 10 * time.Second
|
||||
maxMessageSize = 1024
|
||||
)
|
||||
|
||||
type WinSize struct {
|
||||
Rows uint16 `json:"rows"`
|
||||
Cols uint16 `json:"cols"`
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: maxMessageSize,
|
||||
WriteBufferSize: maxMessageSize,
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
|
||||
func (s *Service) Terminal(c *gin.Context) {
|
||||
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
log.Errorf("failed to init websocket: %s", err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = ws.Close()
|
||||
}()
|
||||
|
||||
cmd := exec.Command("/bin/sh")
|
||||
ptmx, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("failed to start pty: %s", err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = ptmx.Close()
|
||||
_ = cmd.Process.Kill()
|
||||
}()
|
||||
|
||||
go wsWrite(ws, ptmx)
|
||||
wsRead(ws, ptmx)
|
||||
}
|
||||
|
||||
// pty to ws
|
||||
func wsWrite(ws *websocket.Conn, ptmx *os.File) {
|
||||
data := make([]byte, maxMessageSize)
|
||||
|
||||
for {
|
||||
n, err := ptmx.Read(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
_ = ws.SetWriteDeadline(time.Now().Add(messageWait))
|
||||
|
||||
err = ws.WriteMessage(websocket.BinaryMessage, data[:n])
|
||||
if err != nil {
|
||||
log.Errorf("write ws message failed: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ws to pty
|
||||
func wsRead(ws *websocket.Conn, ptmx *os.File) {
|
||||
var zeroTime time.Time
|
||||
_ = ws.SetReadDeadline(zeroTime)
|
||||
|
||||
for {
|
||||
msgType, p, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// resize message
|
||||
if msgType == websocket.BinaryMessage {
|
||||
var winSize WinSize
|
||||
if err := json.Unmarshal(p, &winSize); err == nil {
|
||||
_ = pty.Setsize(ptmx, &pty.Winsize{
|
||||
Rows: winSize.Rows,
|
||||
Cols: winSize.Cols,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = ptmx.Write(p)
|
||||
if err != nil {
|
||||
log.Errorf("failed to write to pty: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user