func (s *ShellServer) handleShell(ws *websocket.Conn, shell engines.Shell) { done := make(chan struct{}) // Create a shell handler s.updateRefCount(1) handler := NewShellHandler(ws, s.log.WithField("shell-instance-id", s.nextID())) // Connect pipes go ioext.CopyAndClose(shell.StdinPipe(), handler.StdinPipe()) go ioext.CopyAndClose(handler.StdoutPipe(), shell.StdoutPipe()) go ioext.CopyAndClose(handler.StderrPipe(), shell.StderrPipe()) // Start streaming handler.Communicate(shell.SetSize, shell.Abort) // Wait for call to abort all shells go func() { select { case <-s.done: shell.Abort() case <-done: } }() // Wait for the shell to terminate success, _ := shell.Wait() handler.Terminated(success) s.updateRefCount(-1) // Close done so we stop waiting for abort on all shells select { case <-done: default: close(done) } }