1package statos 2 3import ( 4 "io" 5 "sync" 6 "syscall" 7) 8 9// WriterStatos implements io.Writer 10var _ io.Writer = &WriterStatos{} 11 12type WriterStatos struct { 13 sync.RWMutex 14 iterator io.Writer 15 commChan chan int 16 commClosed bool 17 18 commOnce sync.Once 19} 20 21func (w *WriterStatos) closeCommChan() bool { 22 alreadyClosed := w.wasCommClosed() 23 if !alreadyClosed { 24 w.commOnce.Do(func() { 25 w.Lock() 26 defer w.Unlock() 27 28 close(w.commChan) 29 w.commClosed = true 30 alreadyClosed = w.commClosed 31 }) 32 } 33 return w.commClosed 34} 35 36func NewWriter(w io.Writer) *WriterStatos { 37 return &WriterStatos{ 38 commChan: make(chan int), 39 iterator: w, 40 commClosed: false, 41 } 42} 43 44func (w *WriterStatos) Write(p []byte) (n int, err error) { 45 n, err = w.iterator.Write(p) 46 47 if err != nil && err != syscall.EINTR { 48 w.closeCommChan() 49 return 50 } 51 52 if n >= 0 && !w.wasCommClosed() { 53 w.commChan <- n 54 } 55 return 56} 57 58func (ws *WriterStatos) wasCommClosed() bool { 59 ws.RLock() 60 defer ws.RUnlock() 61 62 return ws.commClosed 63} 64 65func (w *WriterStatos) ProgressChan() chan int { 66 return w.commChan 67} 68