github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/worker/gclient/connection/stream_handler.go (about)

     1  package connection
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"sync"
     8  
     9  	"code.cloudfoundry.org/garden/transport"
    10  	"code.cloudfoundry.org/lager"
    11  )
    12  
    13  type streamHandler struct {
    14  	log lager.Logger
    15  	wg  *sync.WaitGroup
    16  }
    17  
    18  func newStreamHandler(log lager.Logger) *streamHandler {
    19  	return &streamHandler{
    20  		log: log,
    21  		wg:  new(sync.WaitGroup),
    22  	}
    23  }
    24  
    25  func (sh *streamHandler) streamIn(processWriter io.WriteCloser, stdin io.Reader) {
    26  	if stdin == nil {
    27  		return
    28  	}
    29  
    30  	go func(processInputStream io.WriteCloser, stdin io.Reader, log lager.Logger) {
    31  		if _, err := io.Copy(processInputStream, stdin); err == nil {
    32  			processInputStream.Close()
    33  		} else {
    34  			log.Error("streaming-stdin-payload", err)
    35  		}
    36  	}(processWriter, stdin, sh.log)
    37  }
    38  
    39  func (sh *streamHandler) streamOut(streamWriter io.Writer, streamReader io.Reader) {
    40  	sh.wg.Add(1)
    41  	go func() {
    42  		io.Copy(streamWriter, streamReader)
    43  		sh.wg.Done()
    44  	}()
    45  }
    46  
    47  type waitReturn struct {
    48  	exitCode int
    49  	err      error
    50  }
    51  
    52  func (sh *streamHandler) wait(decoder *json.Decoder) <-chan waitReturn {
    53  	result := make(chan waitReturn)
    54  	go func() {
    55  		for {
    56  			payload := &transport.ProcessPayload{}
    57  			err := decoder.Decode(payload)
    58  			if err != nil {
    59  				sh.wg.Wait()
    60  				result <- waitReturn{
    61  					0,
    62  					fmt.Errorf("connection: decode failed: %s", err),
    63  				}
    64  				break
    65  			}
    66  
    67  			if payload.Error != nil {
    68  				sh.wg.Wait()
    69  				result <- waitReturn{
    70  					0,
    71  					fmt.Errorf("connection: process error: %s", *payload.Error),
    72  				}
    73  				break
    74  			}
    75  
    76  			if payload.ExitStatus != nil {
    77  				sh.wg.Wait()
    78  				result <- waitReturn{
    79  					int(*payload.ExitStatus),
    80  					nil,
    81  				}
    82  				break
    83  			}
    84  
    85  			// discard other payloads
    86  		}
    87  		defer close(result)
    88  	}()
    89  	return result
    90  }