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 }