github.com/akashshinde/docker@v1.9.1/pkg/ioutils/writeflusher.go (about) 1 package ioutils 2 3 import ( 4 "errors" 5 "io" 6 "net/http" 7 "sync" 8 ) 9 10 // WriteFlusher wraps the Write and Flush operation ensuring that every write 11 // is a flush. In addition, the Close method can be called to intercept 12 // Read/Write calls if the targets lifecycle has already ended. 13 type WriteFlusher struct { 14 mu sync.Mutex 15 w io.Writer 16 flusher http.Flusher 17 flushed bool 18 closed error 19 20 // TODO(stevvooe): Use channel for closed instead, remove mutex. Using a 21 // channel will allow one to properly order the operations. 22 } 23 24 var errWriteFlusherClosed = errors.New("writeflusher: closed") 25 26 func (wf *WriteFlusher) Write(b []byte) (n int, err error) { 27 wf.mu.Lock() 28 defer wf.mu.Unlock() 29 if wf.closed != nil { 30 return 0, wf.closed 31 } 32 33 n, err = wf.w.Write(b) 34 wf.flush() // every write is a flush. 35 return n, err 36 } 37 38 // Flush the stream immediately. 39 func (wf *WriteFlusher) Flush() { 40 wf.mu.Lock() 41 defer wf.mu.Unlock() 42 43 wf.flush() 44 } 45 46 // flush the stream immediately without taking a lock. Used internally. 47 func (wf *WriteFlusher) flush() { 48 if wf.closed != nil { 49 return 50 } 51 52 wf.flushed = true 53 wf.flusher.Flush() 54 } 55 56 // Flushed returns the state of flushed. 57 // If it's flushed, return true, or else it return false. 58 func (wf *WriteFlusher) Flushed() bool { 59 // BUG(stevvooe): Remove this method. Its use is inherently racy. Seems to 60 // be used to detect whether or a response code has been issued or not. 61 // Another hook should be used instead. 62 wf.mu.Lock() 63 defer wf.mu.Unlock() 64 65 return wf.flushed 66 } 67 68 // Close closes the write flusher, disallowing any further writes to the 69 // target. After the flusher is closed, all calls to write or flush will 70 // result in an error. 71 func (wf *WriteFlusher) Close() error { 72 wf.mu.Lock() 73 defer wf.mu.Unlock() 74 75 if wf.closed != nil { 76 return wf.closed 77 } 78 79 wf.closed = errWriteFlusherClosed 80 return nil 81 } 82 83 // NewWriteFlusher returns a new WriteFlusher. 84 func NewWriteFlusher(w io.Writer) *WriteFlusher { 85 var flusher http.Flusher 86 if f, ok := w.(http.Flusher); ok { 87 flusher = f 88 } else { 89 flusher = &NopFlusher{} 90 } 91 return &WriteFlusher{w: w, flusher: flusher} 92 }