Browse Source

Priceupdater-v0 (#23)

* First price-updater implementation

* Lint corrections

* Structs revision

* Read Write Mutex

* Review price updater and apply small changes

Co-authored-by: Toni Ramírez <toni@iden3.com>
Co-authored-by: Eduard S <eduard@iden3.io>
feature/sql-semaphore1
arnau 4 years ago
committed by GitHub
parent
commit
2c247bf9c3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 176 additions and 0 deletions
  1. +136
    -0
      priceupdater/priceupdater.go
  2. +40
    -0
      priceupdater/priceupdater_test.go

+ 136
- 0
priceupdater/priceupdater.go

@ -0,0 +1,136 @@
package priceupdater
import (
"errors"
"fmt"
"net/http"
"sync"
"time"
"github.com/dghubble/sling"
)
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: 10,
IdleConnTimeout: 10 * 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 {
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
}

+ 40
- 0
priceupdater/priceupdater_test.go

@ -0,0 +1,40 @@
package priceupdater
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCon(t *testing.T) {
config := ConfigPriceUpdater{
RecommendedFee: 1,
RecommendedCreateAccountFee: 1,
TokensList: []string{"ETH", "NEC"},
APIURL: "https://api-pub.bitfinex.com/v2/",
}
pud := NewPriceUpdater(config)
err := pud.UpdatePrices()
assert.Equal(t, err, nil)
info, _ := pud.Get("ETH")
assert.NotZero(t, info.Value)
info2, _ := pud.Get("NEC")
assert.NotZero(t, info2.Value)
info3, err := pud.Get("INVENTED")
if assert.Error(t, err) {
assert.Equal(t, ErrSymbolDoesNotExistInDatabase, err)
}
assert.Equal(t, info3.Value, float64(0))
prices := pud.GetPrices()
assert.Equal(t, prices["ETH"], info)
assert.Equal(t, prices["NEC"], info2)
}

Loading…
Cancel
Save