-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsigtrap.go
84 lines (73 loc) · 1.39 KB
/
sigtrap.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
package sigtrap
import (
"context"
"fmt"
"os"
"os/signal"
"github.com/x-mod/event"
)
type Handler func()
type Capture struct {
notify chan os.Signal
traps map[string]Handler
close chan struct{}
serving *event.Event
stopped *event.Event
}
type CaptureOpt func(*Capture)
func Trap(sig os.Signal, handler Handler) CaptureOpt {
return func(ca *Capture) {
if handler != nil {
ca.traps[sig.String()] = handler
}
}
}
func New(opts ...CaptureOpt) *Capture {
ca := &Capture{
traps: make(map[string]Handler),
close: make(chan struct{}),
serving: event.New(),
stopped: event.New(),
}
for _, o := range opts {
o(ca)
}
ca.notify = make(chan os.Signal, 1)
return ca
}
func (cap *Capture) Serve(ctx context.Context) error {
if ctx == nil {
return fmt.Errorf("context required")
}
if len(cap.traps) == 0 {
return nil
}
signal.Notify(cap.notify)
defer cap.stopped.Fire()
cap.serving.Fire()
for {
select {
case <-cap.close:
return nil
case <-ctx.Done():
return ctx.Err()
case sig := <-cap.notify:
cap.fire(sig)
}
}
}
func (cap *Capture) fire(sig os.Signal) {
if handler, ok := cap.traps[sig.String()]; ok {
handler()
}
}
func (cap *Capture) Serving() <-chan struct{} {
return cap.serving.Done()
}
func (cap *Capture) Close() <-chan struct{} {
if cap.serving.HasFired() {
close(cap.close)
return cap.stopped.Done()
}
return event.Done()
}