-
Notifications
You must be signed in to change notification settings - Fork 11
/
get.go
156 lines (141 loc) · 4.51 KB
/
get.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package service
import (
etcd "github.com/coreos/etcd/client"
"golang.org/x/net/context"
errgo "gopkg.in/errgo.v1"
)
// ServiceResponse is the interface used to provide a response to the service.Get() Method.
// This interface provide a standard API used for mathod chaining like:
// url, err := Get("my-service").First().URL()
//
// To provide such API, go errors need to be stored and sent at the last moment.
// To do so, each "final" method (like Url or All), will check if the Response is errored, before
// continuing to their own logic.
type ServiceResponse interface {
// Err is the method used to check if the Response is errored.
Err() error
// Service return the Service struct representing the requested service
Service() (*Service, error)
// One return a host of the service choosen randomly
One() HostResponse
// First return the first host of the serice
First() HostResponse
// All return all the hosts registred for this service
All() (Hosts, error)
// URL returns a valid url for this service
URL(scheme, path string) (string, error)
}
// Get a service by its name. This method does not directly return the Service, but a ServiceResponse. This permit method chaining like:
// url, err := Get("my-service").First().URL()
//
// If there was an error during the acquisition of the service, this error will be stored in the ServiceResponse. Final methods will check for this error before doing actual logic.
// If the service is not found, we won't render an error, but will return a service with minimal informations. This is done to provide maximal backwerd compatibility since older versions does not register themself to the "/services_infos" directory.
func Get(service string) ServiceResponse {
res, err := KAPI().Get(context.Background(), "/services_infos/"+service, nil)
if err != nil {
if etcd.IsKeyNotFound(err) {
return &GetServiceResponse{
err: nil,
service: &Service{
Name: service,
},
}
}
return &GetServiceResponse{
err: errgo.Mask(err),
service: nil,
}
}
s, err := buildServiceFromNode(res.Node)
if err != nil {
return &GetServiceResponse{
err: errgo.Mask(err),
service: nil,
}
}
return &GetServiceResponse{
err: nil,
service: s,
}
}
// GetServiceResponse is the implementation of the ServiceResponse interface used by the Get method
// This only provide the error wrapping logic, all the actual logic for thsese mêthod are done by the Service struct.
type GetServiceResponse struct {
service *Service
err error
}
// Err wil return an error if an error happend when you've called tre Get method, or nil if no error were detected.
func (q *GetServiceResponse) Err() error {
return q.err
}
// Service will return the service returned by the Get method. If the service was not found, no error will be return but the service will only contains a Name field.
func (q *GetServiceResponse) Service() (*Service, error) {
if q.err != nil {
return nil, errgo.Mask(q.err)
}
return q.service, nil
}
// All will return a slice of all the hosts registred to the service
func (q *GetServiceResponse) All() (Hosts, error) {
if q.err != nil {
return nil, q.err
}
hosts, err := q.service.All()
if err != nil {
return nil, errgo.Mask(err)
}
return hosts, nil
}
// One will return a host choosen randomly in all the hosts of the service
// If the ServiceResponse is errored, the errors will be passed to the HostResponse
func (q *GetServiceResponse) One() HostResponse {
if q.err != nil {
return &GetHostResponse{
err: errgo.Mask(q.err),
host: nil,
}
}
host, err := q.service.One()
if err != nil {
return &GetHostResponse{
err: errgo.Mask(err),
host: nil,
}
}
return &GetHostResponse{
err: nil,
host: host,
}
}
// First will return the first host registred to the service
// If the ServiceResponse is errored, the errors will be passed to the HostResponse
func (q *GetServiceResponse) First() HostResponse {
if q.err != nil {
return &GetHostResponse{
err: errgo.Mask(q.err),
host: nil,
}
}
host, err := q.service.First()
if err != nil {
return &GetHostResponse{
err: errgo.Mask(err),
host: nil,
}
}
return &GetHostResponse{
host: host,
err: nil,
}
}
// URL build url for the specified service. If the service is not public, a random host will be choosen and an url will be generated.
func (q *GetServiceResponse) URL(scheme, path string) (string, error) {
if q.err != nil {
return "", errgo.Mask(q.err)
}
url, err := q.service.URL(scheme, path)
if err != nil {
return "", errgo.Mask(err)
}
return url, nil
}