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
|
package dhcpv6
import (
"errors"
"time"
)
// Response represents a value which Future resolves to
type Response interface {
Value() DHCPv6
Error() error
}
// Future is a result of an asynchronous DHCPv6 call
type Future (<-chan Response)
// SuccessFun can be used as a success callback
type SuccessFun func(val DHCPv6) Future
// FailureFun can be used as a failure callback
type FailureFun func(err error) Future
type response struct {
val DHCPv6
err error
}
func (r *response) Value() DHCPv6 {
return r.val
}
func (r *response) Error() error {
return r.err
}
// NewFuture creates a new future, which can be written to
func NewFuture() chan Response {
return make(chan Response)
}
// NewResponse creates a new future response
func NewResponse(val DHCPv6, err error) Response {
return &response{val: val, err: err}
}
// NewSuccessFuture creates a future that resolves to a value
func NewSuccessFuture(val DHCPv6) Future {
f := NewFuture()
go func() {
f <- NewResponse(val, nil)
}()
return f
}
// NewFailureFuture creates a future that resolves to an error
func NewFailureFuture(err error) Future {
f := NewFuture()
go func() {
f <- NewResponse(nil, err)
}()
return f
}
// Then allows to chain the futures executing appropriate function depending
// on the previous future value
func (f Future) Then(success SuccessFun, failure FailureFun) Future {
g := NewFuture()
go func() {
r := <-f
if r.Error() != nil {
r = <-failure(r.Error())
g <- r
} else {
r = <-success(r.Value())
g <- r
}
}()
return g
}
// OnSuccess allows to chain the futures executing next one only if the first
// one succeeds
func (f Future) OnSuccess(success SuccessFun) Future {
return f.Then(success, func(err error) Future {
return NewFailureFuture(err)
})
}
// OnFailure allows to chain the futures executing next one only if the first
// one fails
func (f Future) OnFailure(failure FailureFun) Future {
return f.Then(func(val DHCPv6) Future {
return NewSuccessFuture(val)
}, failure)
}
// Wait blocks the execution until a future resolves
func (f Future) Wait() (DHCPv6, error) {
r := <-f
return r.Value(), r.Error()
}
// WaitTimeout blocks the execution until a future resolves or times out
func (f Future) WaitTimeout(timeout time.Duration) (DHCPv6, error) {
select {
case r := <-f:
return r.Value(), r.Error()
case <-time.After(timeout):
return nil, errors.New("Timed out")
}
}
|