// New takes a websocket and creates a ShellClient object implementing the
// engines.Shell interface.
func New(ws *websocket.Conn) *ShellClient {
	stdinReader, stdin := ioext.BlockedPipe()
	tellOut := make(chan int, 10)
	tellErr := make(chan int, 10)
	stdout, stdoutWriter := ioext.AsyncPipe(shellconsts.ShellMaxPendingBytes, tellOut)
	stderr, stderrWriter := ioext.AsyncPipe(shellconsts.ShellMaxPendingBytes, tellErr)
	stdinReader.Unblock(shellconsts.ShellMaxPendingBytes)

	s := &ShellClient{
		ws:           ws,
		stdin:        stdin,
		stdout:       stdout,
		stderr:       stderr,
		stdinReader:  stdinReader,
		stdoutWriter: stdoutWriter,
		stderrWriter: stderrWriter,
		done:         make(chan struct{}),
	}

	ws.SetReadLimit(shellconsts.ShellMaxMessageSize)
	ws.SetReadDeadline(time.Now().Add(shellconsts.ShellPongTimeout))
	ws.SetPongHandler(s.pongHandler)

	go s.writeMessages()
	go s.readMessages()
	go s.sendPings()
	go s.sendAck(shellconsts.StreamStdout, tellOut)
	go s.sendAck(shellconsts.StreamStderr, tellErr)

	return s
}
// NewShellHandler returns a new ShellHandler structure for that can
// serve/expose a shell over a websocket.
func NewShellHandler(ws *websocket.Conn, log *logrus.Entry) *ShellHandler {
	tellIn := make(chan int, 10)
	stdin, stdinWriter := ioext.AsyncPipe(shellconsts.ShellMaxPendingBytes, tellIn)
	stdoutReader, stdout := ioext.BlockedPipe()
	stderrReader, stderr := ioext.BlockedPipe()
	stdoutReader.Unblock(shellconsts.ShellMaxPendingBytes)
	stderrReader.Unblock(shellconsts.ShellMaxPendingBytes)

	s := &ShellHandler{
		log:          log,
		ws:           ws,
		stdin:        stdin,
		stdout:       stdout,
		stderr:       stderr,
		stdinWriter:  stdinWriter,
		stdoutReader: stdoutReader,
		stderrReader: stderrReader,
		tellIn:       tellIn,
	}

	ws.SetReadLimit(shellconsts.ShellMaxMessageSize)

	return s
}