summaryrefslogtreecommitdiffhomepage
path: root/dhcpv6/future.go
blob: d0ae6cdd44bcc9a74b48a35989cb9a0c45b81e8a (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
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, 1)
}

// 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")
	}
}