forked from moriyoshi/s3-sftp-proxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
merged_context.go
85 lines (77 loc) · 1.54 KB
/
merged_context.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
package main
import (
"context"
"reflect"
"time"
)
type mergedContext struct {
ctxs []context.Context
doneChan chan struct{}
err error
}
func (ctxs *mergedContext) Deadline() (time.Time, bool) {
retval := time.Time{}
retvalAvail := false
for _, ctx := range ctxs.ctxs {
if dl, ok := ctx.Deadline(); ok {
if !retval.IsZero() || retval.After(dl) {
retval = dl
retvalAvail = true
}
}
}
return retval, retvalAvail
}
func (ctxs *mergedContext) Done() <-chan struct{} {
return ctxs.doneChan
}
func (ctxs *mergedContext) Err() error {
return ctxs.err
}
func (ctxs *mergedContext) Value(key interface{}) interface{} {
for _, ctx := range ctxs.ctxs {
v := ctx.Value(key)
if v != nil {
return v
}
}
return nil
}
func (ctxs *mergedContext) watcher() {
if len(ctxs.ctxs) == 2 {
go func() {
select {
case <-ctxs.ctxs[0].Done():
ctxs.err = ctxs.ctxs[0].Err()
case <-ctxs.ctxs[1].Done():
ctxs.err = ctxs.ctxs[0].Err()
}
close(ctxs.doneChan)
}()
} else {
cases := []reflect.SelectCase{}
for _, ctx := range ctxs.ctxs {
cases = append(cases, reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(ctx.Done()),
})
}
go func() {
chosen, _, _ := reflect.Select(cases)
ctxs.err = ctxs.ctxs[chosen].Err()
close(ctxs.doneChan)
}()
}
}
func combineContext(ctxs ...context.Context) context.Context {
if len(ctxs) == 1 {
return ctxs[0]
}
ctx := &mergedContext{
ctxs: ctxs,
doneChan: make(chan struct{}),
err: nil,
}
ctx.watcher()
return ctx
}