go-ethereum/consensus/bor/rest.go

106 lines
2.1 KiB
Go

package bor
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path"
"time"
"github.com/maticnetwork/bor/log"
)
// ResponseWithHeight defines a response object type that wraps an original
// response with a height.
type ResponseWithHeight struct {
Height string `json:"height"`
Result json.RawMessage `json:"result"`
}
type IHeimdallClient interface {
Fetch(paths ...string) (*ResponseWithHeight, error)
FetchWithRetry(paths ...string) (*ResponseWithHeight, error)
}
type HeimdallClient struct {
urlString string
client http.Client
}
func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
h := &HeimdallClient{
urlString: urlString,
client: http.Client{
Timeout: time.Duration(5 * time.Second),
},
}
return h, nil
}
func (h *HeimdallClient) Fetch(paths ...string) (*ResponseWithHeight, error) {
u, err := url.Parse(h.urlString)
if err != nil {
return nil, err
}
for _, e := range paths {
if e != "" {
u.Path = path.Join(u.Path, e)
}
}
return h.internalFetch(u)
}
// FetchWithRetry returns data from heimdall with retry
func (h *HeimdallClient) FetchWithRetry(paths ...string) (*ResponseWithHeight, error) {
u, err := url.Parse(h.urlString)
if err != nil {
return nil, err
}
for _, e := range paths {
if e != "" {
u.Path = path.Join(u.Path, e)
}
}
for {
res, err := h.internalFetch(u)
if err == nil && res != nil {
return res, nil
}
log.Info("Retrying again in 5 seconds for next Heimdall span", "path", u.Path)
time.Sleep(5 * time.Second)
}
}
// internal fetch method
func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error) {
res, err := h.client.Get(u.String())
if err != nil {
return nil, err
}
defer res.Body.Close()
// check status code
if res.StatusCode != 200 {
return nil, fmt.Errorf("Error while fetching data from Heimdall")
}
// get response
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
// unmarshall data from buffer
var response ResponseWithHeight
if err := json.Unmarshal(body, &response); err != nil {
return nil, err
}
return &response, nil
}