-
Notifications
You must be signed in to change notification settings - Fork 0
/
goprana.go
140 lines (120 loc) · 3.52 KB
/
goprana.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
// Copyright 2015 The goprana Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package goprana is a Prana client for Go.
*/
package goprana
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
)
// A Client represents a Prana client.
type Client struct {
url string
httpcli *http.Client
// FollowRedirects allows to specify if the client should follow redirects.
FollowRedirects bool
}
// DefaultPort is default Prana port.
const DefaultPort = 8078
// NewClient returns Prana Client.
func NewClient(port int) Client {
c := Client{
url: fmt.Sprintf("http://localhost:%v", port),
httpcli: &http.Client{
Transport: &http.Transport{},
},
FollowRedirects: true,
}
return c
}
// DynamicProperties returns a map with the requested IDs and their values.
func (c Client) DynamicProperties(ids ...string) (props map[string]string, err error) {
if len(ids) == 0 {
return nil, errors.New("invalid ids value")
}
idsStr := ""
for _, id := range ids {
idsStr += fmt.Sprintf("id=%v&", id)
}
idsStr = idsStr[:len(idsStr)-1]
url := fmt.Sprintf("%v/dynamicproperties?%v", c.url, idsStr)
resp, err := c.httpcli.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New("status code is not 200 OK")
}
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&props)
return
}
// Get sends a GET request to the specified VIP and path via Ribbon.
func (c Client) Get(vip, path string) (resp *http.Response, err error) {
req, err := http.NewRequest("GET", "", nil)
if err != nil {
return nil, err
}
return c.Do(vip, path, req)
}
// Post sends a POST request to the specified VIP and path via Ribbon. Caller
// should close resp.Body when done reading from it. If the provided body is an
// io.Closer, it is closed after the request.
func (c Client) Post(vip, path, bodyType string, body io.Reader) (resp *http.Response, err error) {
req, err := http.NewRequest("POST", "", body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", bodyType)
return c.Do(vip, path, req)
}
// Do sends a request to the specified VIP and path via Ribbon. Caller should
// close resp.Body when done reading from it. If the provided body is an
// io.Closer, it is closed after the request.
func (c Client) Do(vip, path string, req *http.Request) (resp *http.Response, err error) {
if vip == "" || path == "" {
return nil, errors.New("invalid vip or path values")
}
rawurl := fmt.Sprintf("%v/proxy?vip=%v&path=%v", c.url, vip, path)
url, err := url.Parse(rawurl)
if err != nil {
return nil, err
}
req.URL = url
if c.FollowRedirects {
resp, err = c.httpcli.Do(req)
} else {
resp, err = c.httpcli.Transport.RoundTrip(req)
}
return
}
// Hosts returns a list of hosts which are marked as UP in Eureka for the
// specific application and VIP passed as query parameters. If a VIP name is
// passed we filter the hosts matching that VIP name.
func (c Client) Hosts(appName, vip string) (hosts []string, err error) {
if appName == "" {
return nil, errors.New("invalid appName value")
}
url := fmt.Sprintf("%v/eureka/hosts?appName=%v", c.url, appName)
if vip != "" {
url += fmt.Sprintf("&vip=%v", vip)
}
resp, err := c.httpcli.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.New("status code is not 200 OK")
}
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&hosts)
return
}