package ws import ( "encoding/json" "net" "net/http" "rkkvm/config" "rkkvm/hid" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" log "github.com/sirupsen/logrus" "time" ) type Stream struct { Type string `json:"type"` State int `json:"state"` } const ( KeyboardEvent int = 1 MouseEvent int = 2 ) type client struct { conn *websocket.Conn hid *hid.Hid keyboard chan []int mouse chan []int watcher chan struct{} } var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true }, } func ConnHandler(c *gin.Context) { conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { log.Errorf("Couldn't upgrade websocket: %s", err) return } log.Debugf("websocket connected") // Get the underlying net.Conn from the WebSocket connection netConn := conn.UnderlyingConn() // Enable TCP_NODELAY if tcpConn, ok := netConn.(*net.TCPConn); ok { if err := tcpConn.SetNoDelay(true); err != nil { log.Println("Failed to set TCP_NODELAY:", err) return } } cl := &client{ hid: hid.GetHid(), conn: conn, keyboard: make(chan []int, 200), mouse: make(chan []int, 200), watcher: make(chan struct{}, 1), } go cl.Start() } func (c *client) Start() { defer c.Clean() c.hid.Open() go c.hid.Keyboard(c.keyboard) go c.hid.Mouse(c.mouse) if config.Get().NanoKVMUISupport { go c.Watch() } _ = c.Read() } func (c *client) Read() error { var zeroTime time.Time _ = c.conn.SetReadDeadline(zeroTime) for { _, message, err := c.conn.ReadMessage() if err != nil { return err } log.Tracef("receive message: %s", message) var event []int err = json.Unmarshal(message, &event) if err != nil { log.Debugf("receive invalid message: %s", message) continue } if event[0] == KeyboardEvent { c.keyboard <- event[1:] } else if event[0] == MouseEvent { c.mouse <- event[1:] } } } func (c *client) Write(message []byte) error { _ = c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second)) return c.conn.WriteMessage(websocket.TextMessage, message) } func (c *client) Watch() { ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() for { select { case <-ticker.C: { //state := stream.Get().GetState() /*state, err := stream.GetState() if err != nil { continue }*/ message, _ := json.Marshal(&Stream{ Type: "stream", //State: utils.BoolToInt(state.Result.Source.Online), State: 1, }) err := c.Write(message) if err != nil { return } } case <-c.watcher: return } } } func (c *client) Clean() { _ = c.conn.Close() go clearQueue(c.keyboard) close(c.keyboard) go clearQueue(c.mouse) close(c.mouse) close(c.watcher) c.hid.Close() log.Debug("websocket disconnected") } func clearQueue(queue chan []int) { for range queue { } }