forked from sonatype-nexus-community/gonexus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nexus.go
155 lines (129 loc) · 4.24 KB
/
nexus.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
package nexus
import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"time"
)
// ServerInfo contains the information needed to connect to a Nexus server
type ServerInfo struct {
Host, Username, Password, CertFile string
}
// Client is the interface which allows interacting with an IQ server
type Client interface {
NewRequest(method, endpoint string, payload io.Reader) (*http.Request, error)
Do(request *http.Request) ([]byte, *http.Response, error)
Get(endpoint string) ([]byte, *http.Response, error)
Post(endpoint string, payload io.Reader) ([]byte, *http.Response, error)
Put(endpoint string, payload io.Reader) ([]byte, *http.Response, error)
Del(endpoint string) (*http.Response, error)
Info() ServerInfo
SetDebug(enable bool)
SetCertFile(certFile string)
}
// DefaultClient provides an HTTP wrapper with optimized for communicating with a Nexus server
type DefaultClient struct {
ServerInfo
Debug bool
}
// NewRequest created an http.Request object based on an endpoint and fills in basic auth
func (s *DefaultClient) NewRequest(method, endpoint string, payload io.Reader) (request *http.Request, err error) {
url := fmt.Sprintf("%s/%s", s.Host, endpoint)
request, err = http.NewRequest(method, url, payload)
if err != nil {
return
}
request.SetBasicAuth(s.Username, s.Password)
if payload != nil {
request.Header.Set("Content-Type", "application/json")
}
return
}
// Do performs an http.Request and reads the body if StatusOK
func (s *DefaultClient) Do(request *http.Request) (body []byte, resp *http.Response, err error) {
if s.Debug {
dump, _ := httputil.DumpRequest(request, true)
log.Println("debug: http request:")
log.Printf("%q\n", dump)
}
client := &http.Client{Timeout: 30 * time.Second}
if s.CertFile != "" {
rootCAs, err := x509.SystemCertPool()
if err != nil {
log.Println("warning: failed to get the system cert pool:", err)
}
if rootCAs == nil {
rootCAs = x509.NewCertPool()
}
certs, err := ioutil.ReadFile(s.CertFile)
if err != nil {
log.Printf("warning: failed to append %s to RootCAs: %s\n", s.CertFile, err)
}
if ok := rootCAs.AppendCertsFromPEM(certs); !ok {
log.Println("warning: no certs appended, using system certs only")
}
client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: rootCAs,
},
}
}
resp, err = client.Do(request)
if err != nil {
return nil, nil, err
}
defer resp.Body.Close()
// TODO: Trying to decide if this is a horrible idea or just kinda bad
if resp.StatusCode == http.StatusOK {
body, err = ioutil.ReadAll(resp.Body)
return
}
err = errors.New(resp.Status)
return
}
func (s *DefaultClient) http(method, endpoint string, payload io.Reader) ([]byte, *http.Response, error) {
request, err := s.NewRequest(method, endpoint, payload)
if err != nil {
return nil, nil, err
}
return s.Do(request)
}
// Get performs an HTTP GET against the indicated endpoint
func (s *DefaultClient) Get(endpoint string) ([]byte, *http.Response, error) {
return s.http(http.MethodGet, endpoint, nil)
}
// Post performs an HTTP POST against the indicated endpoint
func (s *DefaultClient) Post(endpoint string, payload io.Reader) ([]byte, *http.Response, error) {
return s.http(http.MethodPost, endpoint, payload)
}
// Put performs an HTTP PUT against the indicated endpoint
func (s *DefaultClient) Put(endpoint string, payload io.Reader) ([]byte, *http.Response, error) {
return s.http(http.MethodPut, endpoint, payload)
}
// Del performs an HTTP DELETE against the indicated endpoint
func (s *DefaultClient) Del(endpoint string) (resp *http.Response, err error) {
_, resp, err = s.http(http.MethodDelete, endpoint, nil)
return
}
// Info return information about the Nexus server
func (s *DefaultClient) Info() ServerInfo {
return ServerInfo{s.Host, s.Username, s.Password, s.CertFile}
}
// SetDebug will enable or disable debug output on HTTP communication
func (s *DefaultClient) SetDebug(enable bool) {
s.Debug = enable
}
// SetCertFile sets the certificate to use for HTTP communication
func (s *DefaultClient) SetCertFile(certFile string) {
s.CertFile = certFile
}
// SearchQueryBuilder is the interface that a search builder should follow
type SearchQueryBuilder interface {
Build() string
}