home » torr/wssrv.git
ID: 430fa1e4c3b152c220b9e1009046979f4065c128
80 lines — 2K — View raw


package ws

import (
	"context"
	"fmt"
	"wssrv/log"

	"github.com/gorilla/websocket"
	"golang.org/x/sys/unix"
)

const (
	bufSize = 8
	quitKey = 17 // Key '<c-q>'.
)

func sendRawStdin(ctx context.Context, cancel context.CancelCauseFunc, con *websocket.Conn, fd int) {
	var (
		err error
		n   int

		buf, clean = make([]byte, bufSize), make([]byte, bufSize)
	)

	for {
		select {
		case <-ctx.Done():
			return
		default:
			buf = clean
			if n, err = unix.Read(fd, buf); err != nil {
				cancel(fmt.Errorf("unable to read from descriptor '%d': %v", fd, err))
				return
			}
			if n == 1 && buf[0] == quitKey {
				cancel(nil)
				return
			}
			fmt.Printf("> byte '%d'\n", buf[:n])
			if err = con.WriteMessage(websocket.BinaryMessage, buf[:n]); err != nil {
				cancel(fmt.Errorf("unable write on websocket on '%s': %v", con.RemoteAddr(), err))
				return
			}
		}
	}
}

func sendRawStdinStream(con *websocket.Conn) error {
	var (
		err  error
		fd   int
		term *unix.Termios

		ctx, cancel = context.WithCancelCause(context.Background())
	)

	if fd, term, err = setupTerm(); err != nil {
		return fmt.Errorf("unable to setup terminal for raw input: %v", err)
	}
	defer func(fd int, term *unix.Termios) {
		var err error
		if err = unix.IoctlSetTermios(fd, unix.TCSETS, term); err != nil {
			log.Err.Printf("unable to restore terminal with descriptor '%d': %v", fd, err)
		}
	}(fd, term)

	go readMessage(ctx, cancel, con)
	go sendRawStdin(ctx, cancel, con, fd)

	<-ctx.Done()
	return context.Cause(ctx)
}

func SendRawStdinStream(con *websocket.Conn) error {
	switch {
	case con == nil:
		return fmt.Errorf("nil connection parameter")
	}
	return sendRawStdinStream(con)
}