hermez-node/priceupdater/priceupdater.go
priceupdater/priceupdater.goRaw
1package priceupdater
2
3import (
4 "errors"
5 "fmt"
6 "net/http"
7 "sync"
8 "time"
9
10 "github.com/dghubble/sling"
11)
12
13var (
14 // ErrSymbolDoesNotExistInDatabase is used when trying to get a token that is not in the DB
15 ErrSymbolDoesNotExistInDatabase = errors.New("symbol does not exist in database")
16)
17
18// ConfigPriceUpdater contains the configuration set by the coordinator
19type ConfigPriceUpdater struct {
20 RecommendedFee uint64 // in dollars
21 RecommendedCreateAccountFee uint64 // in dollars
22 TokensList []string
23 APIURL string
24}
25
26// TokenInfo contains the updated value for the token
27type TokenInfo struct {
28 Symbol string
29 Value float64
30 LastUpdated time.Time
31}
32
33// PriceUpdater definition
34type PriceUpdater struct {
35 db map[string]TokenInfo
36 config ConfigPriceUpdater
37 mu sync.RWMutex
38}
39
40// NewPriceUpdater is the constructor for the updater
41func NewPriceUpdater(config ConfigPriceUpdater) PriceUpdater {
42
43 return PriceUpdater{
44 db: make(map[string]TokenInfo),
45 config: config,
46 }
47
48}
49
50// UpdatePrices is triggered by the Coordinator, and internally will update the token prices in the db
51func (p *PriceUpdater) UpdatePrices() error {
52
53 tr := &http.Transport{
54 MaxIdleConns: 10,
55 IdleConnTimeout: 10 * time.Second,
56 DisableCompression: true,
57 }
58 httpClient := &http.Client{Transport: tr}
59 client := sling.New().Base(p.config.APIURL).Client(httpClient)
60
61 state := [10]float64{}
62
63 for _, tokenSymbol := range p.config.TokensList {
64
65 resp, err := client.New().Get("ticker/t" + tokenSymbol + "USD").ReceiveSuccess(&state)
66 if err != nil {
67 return err
68 }
69 if resp.StatusCode != 200 {
70 return fmt.Errorf("Unexpected response status code: %v", resp.StatusCode)
71 }
72
73 tinfo := TokenInfo{
74 Symbol: tokenSymbol,
75 Value: state[6],
76 LastUpdated: time.Now(),
77 }
78
79 p.UpdateTokenInfo(tinfo)
80
81 }
82
83 return nil
84}
85
86// UpdateConfig allows to update the price-updater configuration
87func (p *PriceUpdater) UpdateConfig(config ConfigPriceUpdater) {
88
89 p.mu.Lock()
90 defer p.mu.Unlock()
91
92 p.config = config
93
94}
95
96// Get one token information
97func (p *PriceUpdater) Get(tokenSymbol string) (TokenInfo, error) {
98
99 var info TokenInfo
100
101 // Check if symbol exists in database
102 p.mu.RLock()
103 defer p.mu.RUnlock()
104
105 if info, ok := p.db[tokenSymbol]; ok {
106 return info, nil
107 }
108
109 return info, ErrSymbolDoesNotExistInDatabase
110
111}
112
113// GetPrices gets all the prices contained in the db
114func (p *PriceUpdater) GetPrices() map[string]TokenInfo {
115
116 var info = make(map[string]TokenInfo)
117
118 p.mu.RLock()
119 defer p.mu.RUnlock()
120
121 for key, value := range p.db {
122 info[key] = value
123 }
124
125 return info
126}
127
128// UpdateTokenInfo updates one token info
129func (p *PriceUpdater) UpdateTokenInfo(tokenInfo TokenInfo) {
130
131 p.mu.Lock()
132 defer p.mu.Unlock()
133
134 p.db[tokenInfo.Symbol] = tokenInfo
135
136}