2020-09-26 08:41:54 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
2020-10-19 19:39:24 +00:00
|
|
|
"sync"
|
2020-09-26 08:41:54 +00:00
|
|
|
|
2020-10-10 09:10:17 +00:00
|
|
|
"github.com/gorilla/websocket"
|
|
|
|
)
|
2020-09-26 08:41:54 +00:00
|
|
|
|
|
|
|
const (
|
|
|
|
MsgIDWrite = "Write"
|
|
|
|
MsgIDWinSize = "WinSize"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Message used to encapsulate the rest of the bessages bellow
|
2020-10-10 09:10:17 +00:00
|
|
|
type MsgWrapper struct {
|
2020-09-26 08:41:54 +00:00
|
|
|
Type string
|
|
|
|
Data []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type MsgTTYWrite struct {
|
|
|
|
Data []byte
|
|
|
|
Size int
|
|
|
|
}
|
|
|
|
|
|
|
|
type MsgTTYWinSize struct {
|
|
|
|
Cols int
|
|
|
|
Rows int
|
|
|
|
}
|
|
|
|
|
2020-10-10 09:10:17 +00:00
|
|
|
type OnMsgWrite func(data []byte)
|
|
|
|
type OnMsgWinSize func(cols, rows int)
|
2020-09-26 08:41:54 +00:00
|
|
|
|
2020-10-19 19:39:24 +00:00
|
|
|
type TTYProtocolWSLocked struct {
|
2020-10-10 09:10:17 +00:00
|
|
|
ws *websocket.Conn
|
2020-10-19 19:39:24 +00:00
|
|
|
lock sync.Mutex
|
2020-10-10 09:10:17 +00:00
|
|
|
}
|
2020-09-26 08:41:54 +00:00
|
|
|
|
2020-10-19 19:39:24 +00:00
|
|
|
func NewTTYProtocolWSLocked(ws *websocket.Conn) *TTYProtocolWSLocked {
|
|
|
|
return &TTYProtocolWSLocked{
|
2020-10-10 09:10:17 +00:00
|
|
|
ws: ws,
|
2020-09-26 08:41:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-10 09:10:17 +00:00
|
|
|
func marshalMsg(aMessage interface{}) (_ []byte, err error) {
|
|
|
|
var msg MsgWrapper
|
2020-09-26 08:41:54 +00:00
|
|
|
|
|
|
|
if writeMsg, ok := aMessage.(MsgTTYWrite); ok {
|
|
|
|
msg.Type = MsgIDWrite
|
|
|
|
msg.Data, err = json.Marshal(writeMsg)
|
|
|
|
//fmt.Printf("Sent write message %s\n", string(writeMsg.Data))
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return json.Marshal(msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
if winChangedMsg, ok := aMessage.(MsgTTYWinSize); ok {
|
|
|
|
msg.Type = MsgIDWinSize
|
|
|
|
msg.Data, err = json.Marshal(winChangedMsg)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return json.Marshal(msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-19 19:39:24 +00:00
|
|
|
func (handler *TTYProtocolWSLocked) ReadAndHandle(onWrite OnMsgWrite, onWinSize OnMsgWinSize) (err error) {
|
2020-10-10 09:10:17 +00:00
|
|
|
var msg MsgWrapper
|
|
|
|
|
|
|
|
_, r, err := handler.ws.NextReader()
|
2020-09-26 08:41:54 +00:00
|
|
|
if err != nil {
|
2020-10-10 09:10:17 +00:00
|
|
|
// underlaying conn is closed. signal that through io.EOF
|
|
|
|
return io.EOF
|
2020-09-26 08:41:54 +00:00
|
|
|
}
|
|
|
|
|
2020-10-10 09:10:17 +00:00
|
|
|
err = json.NewDecoder(r).Decode(&msg)
|
2020-09-26 08:41:54 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-10-10 09:10:17 +00:00
|
|
|
switch msg.Type {
|
|
|
|
case MsgIDWrite:
|
|
|
|
var msgWrite MsgTTYWrite
|
|
|
|
err = json.Unmarshal(msg.Data, &msgWrite)
|
|
|
|
if err == nil {
|
|
|
|
onWrite(msgWrite.Data)
|
|
|
|
}
|
|
|
|
case MsgIDWinSize:
|
|
|
|
var msgRemoteWinSize MsgTTYWinSize
|
|
|
|
err = json.Unmarshal(msg.Data, &msgRemoteWinSize)
|
|
|
|
if err == nil {
|
|
|
|
onWinSize(msgRemoteWinSize.Cols, msgRemoteWinSize.Rows)
|
|
|
|
}
|
2020-09-26 08:41:54 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-10-19 19:39:24 +00:00
|
|
|
func (handler *TTYProtocolWSLocked) SetWinSize(cols, rows int) (err error) {
|
2020-09-26 08:41:54 +00:00
|
|
|
msgWinChanged := MsgTTYWinSize{
|
|
|
|
Cols: cols,
|
|
|
|
Rows: rows,
|
|
|
|
}
|
2020-10-10 09:10:17 +00:00
|
|
|
data, err := marshalMsg(msgWinChanged)
|
|
|
|
if err != nil {
|
2020-10-19 19:39:24 +00:00
|
|
|
return
|
2020-10-10 09:10:17 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 19:39:24 +00:00
|
|
|
handler.lock.Lock()
|
|
|
|
err = handler.ws.WriteMessage(websocket.TextMessage, data)
|
|
|
|
handler.lock.Unlock()
|
|
|
|
return
|
2020-09-26 08:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Function to send data from one the sender to the server and the other way around.
|
2020-10-19 19:39:24 +00:00
|
|
|
func (handler *TTYProtocolWSLocked) Write(buff []byte) (n int, err error) {
|
2020-09-26 08:41:54 +00:00
|
|
|
msgWrite := MsgTTYWrite{
|
|
|
|
Data: buff,
|
|
|
|
Size: len(buff),
|
|
|
|
}
|
2020-10-10 09:10:17 +00:00
|
|
|
data, err := marshalMsg(msgWrite)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2020-09-26 08:41:54 +00:00
|
|
|
|
2020-10-19 19:39:24 +00:00
|
|
|
handler.lock.Lock()
|
|
|
|
n, err = len(buff), handler.ws.WriteMessage(websocket.TextMessage, data)
|
|
|
|
handler.lock.Unlock()
|
|
|
|
return
|
2020-09-26 08:41:54 +00:00
|
|
|
}
|