github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/imagebuilder/rpcd/buildImage.go (about)

     1  package rpcd
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/Cloud-Foundations/Dominator/lib/errors"
    10  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    11  	proto "github.com/Cloud-Foundations/Dominator/proto/imaginator"
    12  )
    13  
    14  type logWriterType struct {
    15  	conn         *srpc.Conn
    16  	mutex        sync.Mutex // Protect everything below.
    17  	err          error
    18  	flushPending bool
    19  }
    20  
    21  func (t *srpcType) BuildImage(conn *srpc.Conn) error {
    22  	var request proto.BuildImageRequest
    23  	if err := conn.Decode(&request); err != nil {
    24  		_, err = conn.WriteString(err.Error() + "\n")
    25  		return err
    26  	}
    27  	if _, err := conn.WriteString("\n"); err != nil {
    28  		return err
    29  	}
    30  	buildLogBuffer := &bytes.Buffer{}
    31  	var logWriter io.Writer
    32  	if request.StreamBuildLog {
    33  		logWriter = &logWriterType{conn: conn}
    34  	} else {
    35  		logWriter = buildLogBuffer
    36  	}
    37  	image, name, err := t.builder.BuildImage(request, conn.GetAuthInformation(),
    38  		logWriter)
    39  	reply := proto.BuildImageResponse{
    40  		Image:       image,
    41  		ImageName:   name,
    42  		BuildLog:    buildLogBuffer.Bytes(),
    43  		ErrorString: errors.ErrorToString(err),
    44  	}
    45  	return conn.Encode(reply)
    46  }
    47  
    48  func (w *logWriterType) delayedFlush() {
    49  	time.Sleep(time.Millisecond * 100)
    50  	w.flush()
    51  }
    52  
    53  func (w *logWriterType) flush() error {
    54  	w.mutex.Lock()
    55  	defer w.mutex.Unlock()
    56  	w.flushPending = false
    57  	if w.err != nil {
    58  		return w.err
    59  	}
    60  	w.err = w.conn.Flush()
    61  	return w.err
    62  }
    63  
    64  func (w *logWriterType) lockAndScheduleFlush() {
    65  	w.mutex.Lock()
    66  	if w.flushPending {
    67  		return
    68  	}
    69  	w.flushPending = true
    70  	go w.delayedFlush()
    71  }
    72  
    73  func (w *logWriterType) Write(p []byte) (int, error) {
    74  	w.lockAndScheduleFlush()
    75  	defer w.mutex.Unlock()
    76  	if w.err != nil {
    77  		return 0, w.err
    78  	}
    79  	reply := proto.BuildImageResponse{BuildLog: p}
    80  	if err := w.conn.Encode(reply); err != nil {
    81  		return 0, err
    82  	}
    83  	return len(p), nil
    84  }