Use sync.Map for maintaining map of all coins

pull/42/head
Miguel Mota 5 years ago
parent 2e36bdb773
commit db3cb70696
No known key found for this signature in database
GPG Key ID: 67EC1161588A00F9

@ -41,7 +41,7 @@ type Views struct {
// State is the state preferences of cointop
type State struct {
allCoins []*Coin
allCoinsSlugMap map[string]*Coin
allCoinsSlugMap sync.Map
coins []*Coin
chartPoints [][]termui.Cell
currencyConversion string
@ -165,7 +165,6 @@ func NewCointop(config *Config) (*Cointop, error) {
chartRangesMap: chartRangesMap(),
limiter: time.Tick(2 * time.Second),
State: &State{
allCoinsSlugMap: make(map[string]*Coin),
allCoins: []*Coin{},
currencyConversion: "USD",
// DEPRECATED: favorites by 'symbol' is deprecated because of collisions. Kept for backward compatibility.
@ -272,12 +271,21 @@ func NewCointop(config *Config) (*Cointop, error) {
return nil, ErrInvalidAPIChoice
}
allCoinsSlugMap := make(map[string]*Coin)
coinscachekey := ct.cacheKey("allCoinsSlugMap")
filecache.Get(coinscachekey, &ct.State.allCoinsSlugMap)
filecache.Get(coinscachekey, &allCoinsSlugMap)
for k := range ct.State.allCoinsSlugMap {
ct.State.allCoins = append(ct.State.allCoins, ct.State.allCoinsSlugMap[k])
for k, v := range allCoinsSlugMap {
ct.State.allCoinsSlugMap.Store(k, v)
}
ct.State.allCoinsSlugMap.Range(func(key, value interface{}) bool {
if coin, ok := value.(*Coin); ok {
ct.State.allCoins = append(ct.State.allCoins, coin)
}
return true
})
if len(ct.State.allCoins) > 1 {
max := len(ct.State.allCoins)
if max > 100 {
@ -289,15 +297,18 @@ func NewCointop(config *Config) (*Cointop, error) {
// DEPRECATED: favorites by 'symbol' is deprecated because of collisions. Kept for backward compatibility.
// Here we're doing a lookup based on symbol and setting the favorite to the coin name instead of coin symbol.
for i := range ct.State.allCoinsSlugMap {
coin := ct.State.allCoinsSlugMap[i]
for k := range ct.State.favoritesBySymbol {
if coin.Symbol == k {
ct.State.favorites[coin.Name] = true
delete(ct.State.favoritesBySymbol, k)
ct.State.allCoinsSlugMap.Range(func(key, value interface{}) bool {
if coin, ok := value.(*Coin); ok {
for k := range ct.State.favoritesBySymbol {
if coin.Symbol == k {
ct.State.favorites[coin.Name] = true
delete(ct.State.favoritesBySymbol, k)
}
}
}
}
return true
})
var globaldata []float64
chartcachekey := ct.cacheKey(fmt.Sprintf("%s_%s", "globaldata", strings.Replace(ct.State.selectedChartRange, " ", "", -1)))

@ -58,14 +58,20 @@ func (ct *Cointop) processCoins(coins []types.Coin) {
updatecoinsmux.Lock()
defer updatecoinsmux.Unlock()
allCoinsSlugMap := make(map[string]*Coin)
ct.State.allCoinsSlugMap.Range(func(key, value interface{}) bool {
allCoinsSlugMap[key.(string)] = value.(*Coin)
return true
})
cachekey := ct.cacheKey("allCoinsSlugMap")
ct.cache.Set(cachekey, ct.State.allCoinsSlugMap, 10*time.Second)
filecache.Set(cachekey, ct.State.allCoinsSlugMap, 24*time.Hour)
ct.cache.Set(cachekey, allCoinsSlugMap, 10*time.Second)
filecache.Set(cachekey, allCoinsSlugMap, 24*time.Hour)
for _, v := range coins {
k := v.Name
last := ct.State.allCoinsSlugMap[k]
ct.State.allCoinsSlugMap[k] = &Coin{
ilast, _ := ct.State.allCoinsSlugMap.Load(k)
ct.State.allCoinsSlugMap.Store(k, &Coin{
ID: v.ID,
Name: v.Name,
Symbol: v.Symbol,
@ -79,23 +85,38 @@ func (ct *Cointop) processCoins(coins []types.Coin) {
PercentChange24H: v.PercentChange24H,
PercentChange7D: v.PercentChange7D,
LastUpdated: v.LastUpdated,
}
if last != nil {
ct.State.allCoinsSlugMap[k].Favorite = last.Favorite
})
if ilast != nil {
last, _ := ilast.(*Coin)
if last != nil {
ivalue, _ := ct.State.allCoinsSlugMap.Load(k)
l, _ := ivalue.(*Coin)
l.Favorite = last.Favorite
ct.State.allCoinsSlugMap.Store(k, l)
}
}
}
if len(ct.State.allCoins) < len(ct.State.allCoinsSlugMap) {
size := 0
// NOTE: there's no Len method on sync.Map so need to manually count
ct.State.allCoinsSlugMap.Range(func(key, value interface{}) bool {
size++
return true
})
if len(ct.State.allCoins) < size {
list := []*Coin{}
for _, v := range coins {
k := v.Name
coin := ct.State.allCoinsSlugMap[k]
icoin, _ := ct.State.allCoinsSlugMap.Load(k)
coin, _ := icoin.(*Coin)
list = append(list, coin)
}
ct.State.allCoins = append(ct.State.allCoins, list...)
} else {
// update list in place without changing order
for i := range ct.State.allCoinsSlugMap {
cm := ct.State.allCoinsSlugMap[i]
ct.State.allCoinsSlugMap.Range(func(key, value interface{}) bool {
cm, _ := value.(*Coin)
for k := range ct.State.allCoins {
c := ct.State.allCoins[k]
if c.ID == cm.ID {
@ -116,7 +137,9 @@ func (ct *Cointop) processCoins(coins []types.Coin) {
c.Favorite = cm.Favorite
}
}
}
return true
})
}
time.AfterFunc(10*time.Millisecond, func() {

@ -168,7 +168,9 @@ func (ct *Cointop) PortfolioEntry(c *Coin) (*PortfolioEntry, bool) {
}
func (ct *Cointop) setPortfolioEntry(coin string, holdings float64) {
c, _ := ct.State.allCoinsSlugMap[strings.ToLower(coin)]
ic, _ := ct.State.allCoinsSlugMap.Load(strings.ToLower(coin))
c, _ := ic.(*Coin)
p, isNew := ct.PortfolioEntry(c)
if isNew {
key := strings.ToLower(coin)

@ -203,12 +203,16 @@ func (ct *Cointop) RefreshTable() error {
func (ct *Cointop) updateTable() error {
sliced := []*Coin{}
for i := range ct.State.allCoinsSlugMap {
v := ct.State.allCoinsSlugMap[i]
if ct.State.favorites[v.Name] {
v.Favorite = true
ct.State.allCoinsSlugMap.Range(func(key, value interface{}) bool {
k := key.(string)
if v, ok := value.(*Coin); ok {
if ct.State.favorites[v.Name] {
v.Favorite = true
ct.State.allCoinsSlugMap.Store(k, v)
}
}
}
return true
})
if ct.State.filterByFavorites {
for i := range ct.State.allCoins {

Loading…
Cancel
Save