summaryrefslogtreecommitdiff
path: root/go/src/lib/statusline/stopwatch.go
blob: 4e3bb5bec69902cff3b0cbbcd9df24e4a36bd240 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package statusline

import (
	"fmt"
	"sync"
	"time"
)

type stopWatch struct {
	inner     StatusLine
	precision time.Duration

	start time.Time
	line  string

	once sync.Once

	lines chan string
	end1  chan bool
	end2  chan struct{}
}

func StopWatch(sl StatusLine, precision time.Duration) StatusLine {
	return &stopWatch{
		inner:     sl,
		precision: precision,
		lines:     make(chan string),
		end1:      make(chan bool),
		end2:      make(chan struct{}),
	}
}

func (sw *stopWatch) startWorker() {
	go func() {
		sw.start = time.Now()
		ticker := time.NewTicker(sw.precision)
		for {
			select {
			case <-ticker.C:
				sw.tick()
			case sw.line = <-sw.lines:
				sw.tick()
			case keep := <-sw.end1:
				sw.tick()
				sw.inner.End(keep)
				ticker.Stop()
				sw.end2 <- struct{}{}
				close(sw.end2)
				return
			}
		}
	}()
}

func (sw *stopWatch) tick() {
	d := time.Now().Sub(sw.start).Round(sw.precision)
	sw.inner.Put(fmt.Sprintf("[ %v ] %s", d, sw.line))
}

func (sl *stopWatch) Put(line string) {
	sl.once.Do(sl.startWorker)
	sl.lines <- line
}

func (sl *stopWatch) End(keep bool) {
	sl.once.Do(sl.startWorker)
	sl.end1 <- keep
	close(sl.lines)
	close(sl.end1)
	<-sl.end2
}