-
Notifications
You must be signed in to change notification settings - Fork 342
/
dataclient.go
133 lines (110 loc) · 3.01 KB
/
dataclient.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
126
127
128
129
130
131
132
133
/*
Package testdataclient provides a test implementation for the DataClient
interface of the skipper/routing package.
It uses in-memory route definitions that are passed in on construction,
and can upserted/deleted programmatically.
*/
package testdataclient
import (
"errors"
"github.com/zalando/skipper/eskip"
)
type incomingUpdate struct {
upsert []*eskip.Route
deletedIDs []string
}
// DataClient implementation.
type Client struct {
routes map[string]*eskip.Route
upsert []*eskip.Route
deletedIDs []string
failNext int
signalUpdate chan incomingUpdate
quit chan struct{}
}
// Creates a Client with an initial set of route definitions.
func New(initial []*eskip.Route) *Client {
routes := make(map[string]*eskip.Route)
for _, r := range initial {
routes[r.Id] = r
}
return &Client{
routes: routes,
signalUpdate: make(chan incomingUpdate),
quit: make(chan struct{}),
}
}
// Creates a Client with an initial set of route definitions in eskip
// format. If parsing the eskip document fails, returns an error.
func NewDoc(doc string) (*Client, error) {
routes, err := eskip.Parse(doc)
if err != nil {
return nil, err
}
return New(routes), nil
}
// Returns the initial/current set of route definitions.
func (c *Client) LoadAll() ([]*eskip.Route, error) {
if c.failNext > 0 {
c.upsert, c.deletedIDs = nil, nil
c.failNext--
return nil, errors.New("failed to get routes")
}
var routes []*eskip.Route
for _, r := range c.routes {
routes = append(routes, r)
}
return routes, nil
}
// Returns the route definitions upserted/deleted since the last call to
// LoadAll.
func (c *Client) LoadUpdate() ([]*eskip.Route, []string, error) {
select {
case update := <-c.signalUpdate:
c.upsert, c.deletedIDs = update.upsert, update.deletedIDs
case <-c.quit:
return nil, nil, nil
}
for _, id := range c.deletedIDs {
delete(c.routes, id)
}
for _, r := range c.upsert {
c.routes[r.Id] = r
}
if c.failNext > 0 {
c.upsert, c.deletedIDs = nil, nil
c.failNext--
return nil, nil, errors.New("failed to get routes")
}
var (
u []*eskip.Route
d []string
)
u, d, c.upsert, c.deletedIDs = c.upsert, c.deletedIDs, nil, nil
return u, d, nil
}
// Updates the current set of routes with new/modified and deleted
// route definitions.
func (c *Client) Update(upsert []*eskip.Route, deletedIDs []string) {
c.signalUpdate <- incomingUpdate{upsert, deletedIDs}
}
// Updates the current set of routes with new/modified and deleted
// route definitions in eskip format. In case the parsing of the
// document fails, it returns an error.
func (c *Client) UpdateDoc(upsertDoc string, deletedIDs []string) error {
routes, err := eskip.Parse(upsertDoc)
if err != nil {
return err
}
c.Update(routes, deletedIDs)
return nil
}
// Sets the Client to fail on the next call to LoadAll or LoadUpdate.
// Repeated call to FailNext will result the Client to fail as many
// times as it was called.
func (c *Client) FailNext() {
c.failNext++
}
func (c *Client) Close() {
close(c.quit)
}