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