diff --git a/common/protocol.go b/common/protocol.go index a98a335..8cb63a5 100644 --- a/common/protocol.go +++ b/common/protocol.go @@ -10,19 +10,22 @@ import ( type ProtocolMessageIDType string const ( - MsgIDSenderInitRequest = "SenderInitRequest" - MsgIDSenderInitReply = "SenderInitReply" - MsgIDReceiverInitRequest = "ReceiverInitRequest" - MsgIDReceiverInitReply = "ReceiverInitReply" - MsgIDWrite = "Write" - MsgIDWinSize = "WinSize" + MsgIDSenderInitRequest = "SenderInitRequest" + MsgIDSenderInitReply = "SenderInitReply" + MsgIDSenderNewReceiverConnected = "SenderNewReceiverConnected" + MsgIDReceiverInitRequest = "ReceiverInitRequest" + MsgIDReceiverInitReply = "ReceiverInitReply" + MsgIDWrite = "Write" + MsgIDWinSize = "WinSize" ) +// Message used to encapsulate the rest of the bessages bellow type MsgAll struct { Type ProtocolMessageIDType Data []byte } +// These messages are used between the server and the sender/receiver type MsgTTYSenderInitRequest struct { Salt string PasswordVerifierA string @@ -32,6 +35,10 @@ type MsgTTYSenderInitReply struct { ReceiverURLWebReadWrite string } +type MsgTTYSenderNewReceiverConnected struct { + Name string +} + type MsgTTYReceiverInitRequest struct { ChallengeReply string } @@ -39,6 +46,8 @@ type MsgTTYReceiverInitRequest struct { type MsgTTYReceiverInitReply struct { } +// These messages are not intended for the server, so they are just forwarded by it to the remote +// side. type MsgTTYWrite struct { Data []byte Size int @@ -107,6 +116,15 @@ func MarshalMsg(aMessage interface{}) (_ []byte, err error) { return json.Marshal(msg) } + if newRcvMsg, ok := aMessage.(MsgTTYSenderNewReceiverConnected); ok { + msg.Type = MsgIDSenderNewReceiverConnected + msg.Data, err = json.Marshal(newRcvMsg) + if err != nil { + return + } + return json.Marshal(msg) + } + return nil, nil } diff --git a/tty-sender/main.go b/tty-sender/main.go index 67006a3..f82ae3e 100644 --- a/tty-sender/main.go +++ b/tty-sender/main.go @@ -114,6 +114,13 @@ func main() { json.Unmarshal(msg.Data, &msgWrite) ptyMaster.Write(msgWrite.Data[:msgWrite.Size]) } + if msg.Type == common.MsgIDSenderNewReceiverConnected { + var msgReceiverConnected common.MsgTTYSenderNewReceiverConnected + json.Unmarshal(msg.Data, &msgReceiverConnected) + + ptyMaster.Refresh() + fmt.Printf("New receiver connected: %s ", msgReceiverConnected.Name) + } } }() diff --git a/tty-sender/pty_master.go b/tty-sender/pty_master.go index 3155394..6889dba 100644 --- a/tty-sender/pty_master.go +++ b/tty-sender/pty_master.go @@ -5,6 +5,7 @@ import ( "os/exec" "os/signal" "syscall" + "time" ptyDevice "github.com/elisescu/pty" "golang.org/x/crypto/ssh/terminal" @@ -61,7 +62,8 @@ func (pty *ptyMaster) Start(command string, args []string, winChangedCB onWindow } func (pty *ptyMaster) GetWinSize() (int, int, error) { - return terminal.GetSize(0) + cols, rows, err := terminal.GetSize(0) + return cols, rows, err } func (pty *ptyMaster) Write(b []byte) (int, error) { @@ -76,6 +78,23 @@ func (pty *ptyMaster) SetWinSize(rows, cols int) { ptyDevice.Setsize(pty.ptyFile, rows, cols) } +func (pty *ptyMaster) Refresh() { + // We wanna force the app to re-draw itself, but there doesn't seem to be a way to do that + // so we fake it by resizing the window quickly, making it smaller and then back big + cols, rows, err := pty.GetWinSize() + + if err != nil { + return + } + + pty.SetWinSize(rows-1, cols) + + go func() { + time.Sleep(time.Millisecond * 50) + pty.SetWinSize(rows, cols) + }() +} + func (pty *ptyMaster) Wait() (err error) { err = pty.command.Wait() // The terminal has to be restored from the RAW state, to its initial state diff --git a/tty-server/session.go b/tty-server/session.go index 3cbebe4..fa4fc7f 100644 --- a/tty-server/session.go +++ b/tty-server/session.go @@ -153,6 +153,16 @@ func (session *ttyShareSession) HandleReceiver(rawConn *WSConnection) { // Sending the initial size of the window, if we have one rcvProtoConn.WriteRawData(lastWindowSize) + // Notify the tty-sender that we got a new receiver connected + msgRcvConnected, err := MarshalMsg(MsgTTYSenderNewReceiverConnected{ + Name: rawConn.Address(), + }) + senderConn.WriteRawData(msgRcvConnected) + + if err != nil { + log.Errorf("Cannot notify tty-sender. Error: %s", err.Error()) + } + // Wait until the TTYReceiver will close the connection on its end for { msg, err := rcvProtoConn.ReadMessage()