pipeline.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package pty
  2. import (
  3. "encoding/json"
  4. "github.com/0xJacky/Nginx-UI/server/settings"
  5. "github.com/creack/pty"
  6. "github.com/gorilla/websocket"
  7. "github.com/pkg/errors"
  8. "os"
  9. "os/exec"
  10. "time"
  11. "unicode/utf8"
  12. )
  13. type Pipeline struct {
  14. Pty *os.File
  15. ws *websocket.Conn
  16. }
  17. type Message struct {
  18. Type MsgType
  19. Data json.RawMessage
  20. }
  21. const bufferSize = 2048
  22. func NewPipeLine(conn *websocket.Conn) (p *Pipeline, err error) {
  23. c := exec.Command(settings.ServerSettings.StartCmd)
  24. ptmx, err := pty.StartWithSize(c, &pty.Winsize{Cols: 90, Rows: 60})
  25. if err != nil {
  26. return nil, errors.Wrap(err, "start pty error")
  27. }
  28. p = &Pipeline{
  29. Pty: ptmx,
  30. ws: conn,
  31. }
  32. return
  33. }
  34. func (p *Pipeline) ReadWsAndWritePty(errorChan chan error) {
  35. for {
  36. msgType, payload, err := p.ws.ReadMessage()
  37. if err != nil {
  38. if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNoStatusReceived,
  39. websocket.CloseNormalClosure) {
  40. errorChan <- errors.Wrap(err, "Error ReadWsAndWritePty unexpected close")
  41. return
  42. }
  43. errorChan <- err
  44. return
  45. }
  46. if msgType != websocket.TextMessage {
  47. errorChan <- errors.Errorf("Error ReadWsAndWritePty Invalid msgType: %v", msgType)
  48. return
  49. }
  50. var msg Message
  51. err = json.Unmarshal(payload, &msg)
  52. if err != nil {
  53. errorChan <- errors.Wrap(err, "Error ReadWsAndWritePty json.Unmarshal")
  54. return
  55. }
  56. switch msg.Type {
  57. case TypeData:
  58. var data string
  59. err = json.Unmarshal(msg.Data, &data)
  60. if err != nil {
  61. errorChan <- errors.Wrap(err, "Error ReadWsAndWritePty json.Unmarshal msg.Data")
  62. return
  63. }
  64. _, err = p.Pty.Write([]byte(data))
  65. if err != nil {
  66. errorChan <- errors.Wrap(err, "Error ReadWsAndWritePty write pty")
  67. return
  68. }
  69. case TypeResize:
  70. var win struct {
  71. Cols uint16
  72. Rows uint16
  73. }
  74. err = json.Unmarshal(msg.Data, &win)
  75. if err != nil {
  76. errorChan <- errors.Wrap(err, "Error ReadSktAndWritePty Invalid resize message")
  77. return
  78. }
  79. err = pty.Setsize(p.Pty, &pty.Winsize{Rows: win.Rows, Cols: win.Cols})
  80. if err != nil {
  81. errorChan <- errors.Wrap(err, "Error ReadSktAndWritePty set pty size")
  82. return
  83. }
  84. case TypePing:
  85. err = p.ws.WriteControl(websocket.PongMessage, []byte{}, time.Now().Add(time.Second))
  86. if err != nil {
  87. errorChan <- errors.Wrap(err, "Error ReadSktAndWritePty write pong")
  88. return
  89. }
  90. default:
  91. errorChan <- errors.Errorf("Error ReadWsAndWritePty unknown msg.Type %v", msg.Type)
  92. return
  93. }
  94. }
  95. }
  96. func (p *Pipeline) ReadPtyAndWriteWs(errorChan chan error) {
  97. buf := make([]byte, bufferSize)
  98. for {
  99. n, err := p.Pty.Read(buf)
  100. if err != nil {
  101. errorChan <- errors.Wrap(err, "Error ReadPtyAndWriteWs read pty")
  102. return
  103. }
  104. processedOutput := validString(string(buf[:n]))
  105. err = p.ws.WriteMessage(websocket.TextMessage, []byte(processedOutput))
  106. if err != nil {
  107. if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
  108. errorChan <- errors.Wrap(err, "Error ReadPtyAndWriteWs websocket write")
  109. return
  110. }
  111. errorChan <- err
  112. return
  113. }
  114. }
  115. }
  116. func validString(s string) string {
  117. if !utf8.ValidString(s) {
  118. v := make([]rune, 0, len(s))
  119. for i, r := range s {
  120. if r == utf8.RuneError {
  121. _, size := utf8.DecodeRuneInString(s[i:])
  122. if size == 1 {
  123. continue
  124. }
  125. }
  126. v = append(v, r)
  127. }
  128. s = string(v)
  129. }
  130. return s
  131. }