forked from vnteamopen/godebouncer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdebouncer.go
125 lines (107 loc) · 3.76 KB
/
debouncer.go
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package godebouncer
import (
"errors"
"sync"
"time"
)
const (
// ErrorTypeIncorrectSendSignal if you call SendSignal on something you configured WithAny
ErrorTypeIncorrectSendSignal = "You are using SendSignal with something setup WithAny"
// ErrorTypeIncorrectSendSignalWithAny if you call SendSignalWithAny on something you configured WithTriggered
ErrorTypeIncorrectSendSignalWithAny = "You are using SendSignalWithAny with something setup WithTriggered"
)
// Debouncer main struct for debouncer package
type Debouncer struct {
timeDuration time.Duration
timer *time.Timer
triggeredFunc func()
triggeredAnyFunc func(any)
isAny bool
mu sync.Mutex
done chan struct{}
}
// New creates a new instance of debouncer. Each instance of debouncer works independent, concurrency with different wait duration.
func New(duration time.Duration) *Debouncer {
return &Debouncer{timeDuration: duration, triggeredFunc: func() {}, triggeredAnyFunc: func(any) {}}
}
// WithTriggered attached a triggered function to debouncer instance and return the same instance of debouncer to use.
func (d *Debouncer) WithTriggered(triggeredFunc func()) *Debouncer {
d.triggeredFunc = triggeredFunc
d.isAny = false
return d
}
// WithAny attached a triggered function to debouncer instance and return the same instance of debouncer to use.
func (d *Debouncer) WithAny(triggeredFunc func(any)) *Debouncer {
d.triggeredAnyFunc = triggeredFunc
d.isAny = true
return d
}
// SendSignal makes an action that notifies to invoke the triggered function after a wait duration.
func (d *Debouncer) SendSignal() (err error) {
if d.isAny {
return errors.New(ErrorTypeIncorrectSendSignalWithAny)
}
d.mu.Lock()
defer d.mu.Unlock()
d.Cancel()
d.timer = time.AfterFunc(d.timeDuration, func() {
d.triggeredFunc()
if d.done != nil {
close(d.done)
}
d.done = make(chan struct{})
})
return nil
}
// SendSignalWithData makes an action that notifies to invoke the triggered function after a wait duration.
func (d *Debouncer) SendSignalWithData(anyVar any) (err error) {
if !d.isAny {
return errors.New(ErrorTypeIncorrectSendSignal)
}
d.mu.Lock()
defer d.mu.Unlock()
d.Cancel()
d.timer = time.AfterFunc(d.timeDuration, func() {
d.triggeredAnyFunc(anyVar)
if d.done != nil {
close(d.done)
}
d.done = make(chan struct{})
})
return nil
}
// Do run the signalFunc() and call SendSignal() after all. The signalFunc() and SendSignal() function run sequentially.
func (d *Debouncer) Do(signalFunc func()) {
signalFunc()
d.SendSignal()
}
// DoAny run the signalFunc(any) and call SendSignalWithData(any) after all. The signalFunc() and SendSignal() function run sequentially.
func (d *Debouncer) DoAny(signalFunc func(any), anyVar any) {
signalFunc(anyVar)
d.SendSignalWithData(anyVar)
}
// Cancel the timer from the last function SendSignal(). The scheduled triggered function is cancelled and doesn't invoke.
func (d *Debouncer) Cancel() {
if d.timer != nil {
d.timer.Stop()
}
}
// UpdateTriggeredFunc replaces triggered function.
func (d *Debouncer) UpdateTriggeredFunc(newTriggeredFunc func()) {
d.triggeredFunc = newTriggeredFunc
}
// UpdateAnyFunc replaces triggered function.
func (d *Debouncer) UpdateAnyFunc(newTriggeredFunc func(any)) {
d.triggeredAnyFunc = newTriggeredFunc
}
// UpdateTimeDuration replaces the waiting time duration. You need to call a SendSignal() again to trigger a new timer with a new waiting time duration.
func (d *Debouncer) UpdateTimeDuration(newTimeDuration time.Duration) {
d.timeDuration = newTimeDuration
}
// Done returns a receive-only channel to notify the caller when the triggered func has been executed.
func (d *Debouncer) Done() <-chan struct{} {
if d.done == nil {
d.done = make(chan struct{})
}
return d.done
}