/
groupedexplorers.go
137 lines (124 loc) · 3.58 KB
/
groupedexplorers.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
package explorer
import (
"errors"
"net"
"github.com/threefoldtech/rivine/modules"
"github.com/threefoldtech/rivine/pkg/api"
"github.com/threefoldtech/rivine/types"
)
var (
// ErrNoHealthyExplorers is returned if all explorers in the group fail to respond in time
ErrNoHealthyExplorers = errors.New("No explorer could statisfy the request")
)
// GroupedExplorer is a Backend which can call multiple explorers, calling another explorer if one is down
type GroupedExplorer struct {
explorers []*Explorer
}
// NewGroupedExplorer creates a new GroupedExplorer from existing regular Explorers
func NewGroupedExplorer(explorers ...*Explorer) *GroupedExplorer {
return &GroupedExplorer{explorers: explorers}
}
// CheckAddress returns all interesting transactions and blocks related to a given unlockhash
func (e *GroupedExplorer) CheckAddress(addr types.UnlockHash) ([]api.ExplorerBlock, []api.ExplorerTransaction, error) {
for _, explorer := range e.explorers {
blocks, transactions, err := explorer.CheckAddress(addr)
if err, ok := err.(net.Error); ok && err.Timeout() {
continue
}
return blocks, transactions, err
}
return nil, nil, ErrNoHealthyExplorers
}
// CurrentHeight returns the current chain height
func (e *GroupedExplorer) CurrentHeight() (types.BlockHeight, error) {
for _, explorer := range e.explorers {
height, err := explorer.CurrentHeight()
if err, ok := err.(net.Error); ok && err.Timeout() {
continue
}
return height, err
}
return 0, ErrNoHealthyExplorers
}
// SendTxn sends a txn to the backend to ultimately include it in the transactionpool
func (e *GroupedExplorer) SendTxn(tx types.Transaction) (types.TransactionID, error) {
for _, explorer := range e.explorers {
txID, err := explorer.SendTxn(tx)
if err, ok := err.(net.Error); ok && err.Timeout() {
continue
}
return txID, err
}
return types.TransactionID{}, ErrNoHealthyExplorers
}
// GetChainConstants gets the currently active chain constants for this backend
func (e *GroupedExplorer) GetChainConstants() (modules.DaemonConstants, error) {
for _, explorer := range e.explorers {
cts, err := explorer.GetChainConstants()
if err, ok := err.(net.Error); ok && err.Timeout() {
continue
}
return cts, err
}
return modules.DaemonConstants{}, ErrNoHealthyExplorers
}
func (e *GroupedExplorer) Get(endpoint string) error {
var (
nerr net.Error
err error
ok bool
)
for _, explorer := range e.explorers {
err = explorer.Get(endpoint)
if nerr, ok = err.(net.Error); ok && nerr.Timeout() {
continue
}
return err
}
return ErrNoHealthyExplorers
}
func (e *GroupedExplorer) GetWithResponse(endpoint string, responseBody interface{}) error {
var (
nerr net.Error
err error
ok bool
)
for _, explorer := range e.explorers {
err = explorer.GetWithResponse(endpoint, responseBody)
if nerr, ok = err.(net.Error); ok && nerr.Timeout() {
continue
}
return err
}
return ErrNoHealthyExplorers
}
func (e *GroupedExplorer) Post(endpoint, data string) error {
var (
nerr net.Error
err error
ok bool
)
for _, explorer := range e.explorers {
err = explorer.Post(endpoint, data)
if nerr, ok = err.(net.Error); ok && nerr.Timeout() {
continue
}
return err
}
return ErrNoHealthyExplorers
}
func (e *GroupedExplorer) PostWithResponse(endpoint, data string, responseBody interface{}) error {
var (
nerr net.Error
err error
ok bool
)
for _, explorer := range e.explorers {
err = explorer.PostWithResponse(endpoint, data, responseBody)
if nerr, ok = err.(net.Error); ok && nerr.Timeout() {
continue
}
return err
}
return ErrNoHealthyExplorers
}