func (s *sessionManager) waitForShell(shell engines.Shell) {
	// Wait for shell to finish
	shell.Wait()

	// Lock access to s.shells
	s.m.Lock()
	defer s.m.Unlock()

	// Remove shell from s.shells
	shells := s.shells[:0]
	for _, sh := range s.shells {
		if sh != shell {
			shells = append(shells, sh)
		}
	}
	s.shells = shells

	// Notify threads waiting if all shells are done
	if len(s.shells) == 0 && len(s.displays) == 0 {
		s.empty.Broadcast()
	}
}
예제 #2
0
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)
	}
}