forked from keybase/client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
api.go
116 lines (97 loc) · 2.84 KB
/
api.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
// Modified from https://github.com/aktau/github-release/blob/master/api.go
package github
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
)
const (
APIURL = "https://api.github.com"
)
// materializeFile takes a physical file or stream (named pipe, user input,
// ...) and returns an io.Reader and the number of bytes that can be read
// from it.
func materializeFile(f *os.File) (io.Reader, int64, error) {
fi, err := f.Stat()
if err != nil {
return nil, 0, err
}
// If the file is actually a char device (like user typed input)
// or a named pipe (like a streamed in file), buffer it up.
//
// When uploading a file, you need to either explicitly set the
// Content-Length header or send a chunked request. Since the
// github upload server doesn't accept chunked encoding, we have
// to set the size of the file manually. Since a stream doesn't have a
// predefined length, it's read entirely into a byte buffer.
if fi.Mode()&(os.ModeCharDevice|os.ModeNamedPipe) == 1 {
var buf bytes.Buffer
n, err := buf.ReadFrom(f)
if err != nil {
return nil, 0, errors.New("req: could not buffer up input stream: " + err.Error())
}
return &buf, n, err
}
// We know the os.File is most likely an actual file now.
n, err := GetFileSize(f)
return f, n, err
}
// NewAuthRequest creates a new request that sends the auth token
func NewAuthRequest(method, url, bodyType, token string, headers map[string]string, body io.Reader) (*http.Request, error) {
var n int64 // content length
var err error
if f, ok := body.(*os.File); ok {
// Retrieve the content-length and buffer up if necessary.
body, n, err = materializeFile(f)
if err != nil {
return nil, err
}
}
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
}
if n != 0 {
req.ContentLength = n
}
if bodyType != "" {
req.Header.Set("Content-Type", bodyType)
}
req.Header.Set("Authorization", fmt.Sprintf("token %s", token))
for k, v := range headers {
req.Header.Set(k, v)
}
return req, nil
}
func DoAuthRequest(method, url, bodyType, token string, headers map[string]string, body io.Reader) (*http.Response, error) {
req, err := NewAuthRequest(method, url, bodyType, token, headers, body)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}
func Get(uri string, v interface{}) error {
resp, err := http.Get(APIURL + uri)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return fmt.Errorf("could not fetch releases, %v", err)
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("github did not response with 200 OK but with %v", resp.Status)
}
var r io.Reader = resp.Body
if err = json.NewDecoder(r).Decode(v); err != nil {
return fmt.Errorf("could not unmarshall JSON into Release struct, %v", err)
}
return nil
}