|
|
package priceupdater
import ( "errors" "fmt" "net/http" "sync" "time"
"github.com/dghubble/sling" )
const ( defaultMaxIdleConns = 10 defaultIdleConnTimeout = 10 )
var ( // ErrSymbolDoesNotExistInDatabase is used when trying to get a token that is not in the DB
ErrSymbolDoesNotExistInDatabase = errors.New("symbol does not exist in database") )
// ConfigPriceUpdater contains the configuration set by the coordinator
type ConfigPriceUpdater struct { RecommendedFee uint64 // in dollars
RecommendedCreateAccountFee uint64 // in dollars
TokensList []string APIURL string }
// TokenInfo contains the updated value for the token
type TokenInfo struct { Symbol string Value float64 LastUpdated time.Time }
// PriceUpdater definition
type PriceUpdater struct { db map[string]TokenInfo config ConfigPriceUpdater mu sync.RWMutex }
// NewPriceUpdater is the constructor for the updater
func NewPriceUpdater(config ConfigPriceUpdater) PriceUpdater { return PriceUpdater{ db: make(map[string]TokenInfo), config: config, } }
// UpdatePrices is triggered by the Coordinator, and internally will update the token prices in the db
func (p *PriceUpdater) UpdatePrices() error { tr := &http.Transport{ MaxIdleConns: defaultMaxIdleConns, IdleConnTimeout: defaultIdleConnTimeout * time.Second, DisableCompression: true, } httpClient := &http.Client{Transport: tr} client := sling.New().Base(p.config.APIURL).Client(httpClient)
state := [10]float64{}
for _, tokenSymbol := range p.config.TokensList { resp, err := client.New().Get("ticker/t" + tokenSymbol + "USD").ReceiveSuccess(&state) if err != nil { return err } // if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK { return fmt.Errorf("Unexpected response status code: %v", resp.StatusCode) }
tinfo := TokenInfo{ Symbol: tokenSymbol, Value: state[6], LastUpdated: time.Now(), }
p.UpdateTokenInfo(tinfo) }
return nil }
// UpdateConfig allows to update the price-updater configuration
func (p *PriceUpdater) UpdateConfig(config ConfigPriceUpdater) { p.mu.Lock() defer p.mu.Unlock()
p.config = config }
// Get one token information
func (p *PriceUpdater) Get(tokenSymbol string) (TokenInfo, error) { var info TokenInfo
// Check if symbol exists in database
p.mu.RLock() defer p.mu.RUnlock()
if info, ok := p.db[tokenSymbol]; ok { return info, nil }
return info, ErrSymbolDoesNotExistInDatabase }
// GetPrices gets all the prices contained in the db
func (p *PriceUpdater) GetPrices() map[string]TokenInfo { var info = make(map[string]TokenInfo)
p.mu.RLock() defer p.mu.RUnlock()
for key, value := range p.db { info[key] = value }
return info }
// UpdateTokenInfo updates one token info
func (p *PriceUpdater) UpdateTokenInfo(tokenInfo TokenInfo) { p.mu.Lock() defer p.mu.Unlock()
p.db[tokenInfo.Symbol] = tokenInfo }
|