Skip to content

Commit f552dcf

Browse files
committed
[dev] draft for request make
1 parent 143008f commit f552dcf

File tree

2 files changed

+126
-4
lines changed

2 files changed

+126
-4
lines changed

client.go

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,94 @@
77

88
package etherscan
99

10-
import "net/http"
10+
import (
11+
"bytes"
12+
"encoding/json"
13+
"fmt"
14+
"io"
15+
"net/http"
16+
"net/url"
17+
)
1118

1219
// Client etherscan API client
1320
// Clients are safe for concurrent use by multiple goroutines.
1421
type Client struct {
15-
network Network
1622
coon *http.Client
23+
network Network
24+
key string
25+
baseURL string
26+
27+
// Verbose when true, talks a lot
28+
Verbose bool
29+
30+
// BeforeRequest runs before every client request, in the same goroutine.
31+
// May be used in rate limit.
32+
// Request will be aborted, if BeforeRequest returns non-nil err.
33+
BeforeRequest func(module, action string, param map[string]interface{}) error
34+
35+
// AfterRequest runs after every client request, even when there is an error.
36+
AfterRequest func(module, action string, param map[string]interface{}, outcome interface{}, requestErr error)
1737
}
1838

1939
// New initialize a new etherscan API client
2040
// please use pre-defined network value
21-
func New(network Network) *Client {
41+
func New(network Network, APIKey string) *Client {
2242
return &Client{
23-
network: network,
2443
coon: &http.Client{},
44+
network: network,
45+
key: APIKey,
46+
baseURL: fmt.Sprintf(`https://%s.etherscan.io/api?`, network.SubDomain()),
47+
}
48+
}
49+
50+
// call does almost all the dirty work.
51+
func (c *Client) call(module, action string, param map[string]interface{}, outcome interface{}) (err error) {
52+
// todo: fire hooks
53+
// todo: verbose mode
54+
55+
req, err := http.NewRequest(http.MethodGet, c.craftURL(param), http.NoBody)
56+
if err != nil {
57+
err = wrapErr(err, "http.NewRequest")
58+
return
59+
}
60+
61+
res, err := c.coon.Do(req)
62+
if err != nil {
63+
err = wrapErr(err, "sending request")
64+
return
2565
}
66+
defer res.Body.Close()
67+
68+
var content bytes.Buffer
69+
if _, err = io.Copy(&content, res.Body); err != nil {
70+
err = wrapErr(err, "reading response")
71+
return
72+
}
73+
74+
if res.StatusCode != http.StatusOK {
75+
err = fmt.Errorf("response status %v %s, response body: %s", res.StatusCode, res.Status, content.String())
76+
return
77+
}
78+
79+
err = json.Unmarshal(content.Bytes(), outcome)
80+
if err != nil {
81+
err = wrapErr(err, "json unmarshal")
82+
return
83+
}
84+
85+
return
86+
}
87+
88+
// craftURL returns desired URL via param provided
89+
func (c *Client) craftURL(param map[string]interface{}) (URL string) {
90+
q := url.Values{
91+
"apikey": []string{c.key},
92+
}
93+
94+
for k, v := range param {
95+
q[k] = extractValue(v)
96+
}
97+
98+
URL = c.baseURL + q.Encode()
99+
return
26100
}

reflect.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2018 LI Zhennan
3+
*
4+
* Use of this work is governed by a MIT License.
5+
* You may find a license copy in project root.
6+
*/
7+
8+
package etherscan
9+
10+
import (
11+
"fmt"
12+
"reflect"
13+
"strconv"
14+
)
15+
16+
// extractValue obtains string-formed slice representation via
17+
// input. It only handles string, int, and their slice form, and
18+
// panics otherwise.
19+
func extractValue(input interface{}) (output []string) {
20+
v := reflect.ValueOf(input)
21+
22+
if v.Kind() == reflect.Slice {
23+
length := v.Len()
24+
output = make([]string, length)
25+
26+
for i := 0; i < length; i++ {
27+
output[i] = valueToStr(v.Index(i))
28+
}
29+
} else {
30+
output = append(output, valueToStr(v))
31+
}
32+
33+
return
34+
}
35+
36+
// valueToStr convert v into proper string representation
37+
// Only handles int and string, panic otherwise.
38+
func valueToStr(v reflect.Value) (str string) {
39+
switch v.Kind() {
40+
case reflect.String:
41+
str = v.String()
42+
case reflect.Int:
43+
str = strconv.FormatInt(v.Int(), 10)
44+
default:
45+
panic(fmt.Sprintf("valueToStr: %v is of unexpected kind %q", v.Interface(), v.Kind()))
46+
}
47+
return
48+
}

0 commit comments

Comments
 (0)