Former-commit-id: 70acc67450cc1b1f33bf24dcd9b55067dd601e08 [formerly 70acc67450cc1b1f33bf24dcd9b55067dd601e08 [formerly e21e905f55331dd7065e546bb41cb09cb70f9c9e [formerly bb60145fad704b7ff79ce2b9d0c96e7cddf99e61]]]
Former-commit-id: 5b315791e4e1104894aaaae41abb1c41d5683f84
Former-commit-id: 7ee3f06ae54278620ca8b76846fa9015bd28c68e [formerly c3c89d40300b7a5a7fa354f9aff76f4ccc24fd80]
Former-commit-id: 72585f33661de190e503ba42ba5591ad7100bb68
pull/15/head
Miguel Mota 6 years ago
parent 86e5b15991
commit c0fffae086

@ -1,54 +0,0 @@
package cointop
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
func (ct *Cointop) writeHardCache(data interface{}, filename string) error {
b, err := json.Marshal(data)
if err != nil {
return err
}
path := fmt.Sprintf("%s/.%s", ct.hardCachePath(), filename)
of, err := os.Create(path)
defer of.Close()
if err != nil {
return err
}
_, err = of.Write(b)
if err != nil {
return err
}
return nil
}
func (ct *Cointop) readHardCache(i interface{}, filename string) (interface{}, bool, error) {
path := fmt.Sprintf("%s/.%s", ct.hardCachePath(), filename)
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, false, err
}
err = json.Unmarshal(b, &i)
if err != nil {
return nil, false, err
}
return i, true, nil
}
func (ct *Cointop) hardCachePath() string {
return fmt.Sprintf("%v%v", ct.configDirPath(), "/.cache")
}
func (ct *Cointop) createCacheDir() error {
path := ct.hardCachePath()
if _, err := os.Stat(path); os.IsNotExist(err) {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
return err
}
}
return nil
}

@ -6,6 +6,7 @@ import (
"time"
"github.com/miguelmota/cointop/pkg/color"
"github.com/miguelmota/cointop/pkg/fcache"
"github.com/miguelmota/cointop/pkg/termui"
)
@ -46,32 +47,42 @@ func (ct *Cointop) chartPoints(maxX int, coin string) error {
end := secs
var data []float64
filename := strings.ToLower(coin)
if filename == "" {
filename = "globaldata"
cachekey := strings.ToLower(coin)
if cachekey == "" {
cachekey = "globaldata"
}
if coin == "" {
graphData, err := ct.api.GetGlobalMarketGraphData(start, end)
if err != nil {
return nil
}
for i := range graphData.MarketCapByAvailableSupply {
data = append(data, graphData.MarketCapByAvailableSupply[i][1]/1E9)
}
} else {
graphData, err := ct.api.GetCoinGraphData(coin, start, end)
if err != nil {
return nil
}
for i := range graphData.PriceUSD {
data = append(data, graphData.PriceUSD[i][1])
}
cached, found := ct.cache.Get(cachekey)
if found {
// cache hit
data, _ = cached.([]float64)
ct.debuglog("soft cache hit")
}
go func() {
_ = ct.writeHardCache(data, filename)
}()
if len(data) == 0 {
if coin == "" {
graphData, err := ct.api.GetGlobalMarketGraphData(start, end)
if err != nil {
return nil
}
for i := range graphData.MarketCapByAvailableSupply {
data = append(data, graphData.MarketCapByAvailableSupply[i][1]/1E9)
}
} else {
graphData, err := ct.api.GetCoinGraphData(coin, start, end)
if err != nil {
return nil
}
for i := range graphData.PriceUSD {
data = append(data, graphData.PriceUSD[i][1])
}
}
ct.cache.Set(cachekey, data, 10*time.Second)
go func() {
_ = fcache.Set(cachekey, data, 24*time.Hour)
}()
}
chart.Data = data
termui.Body = termui.NewGrid()

@ -72,10 +72,6 @@ func Run() {
if err != nil {
log.Fatal(err)
}
err = ct.createCacheDir()
if err != nil {
log.Fatal(err)
}
g, err := gocui.NewGui(gocui.Output256)
if err != nil {
log.Fatalf("new gocui: %v", err)

@ -4,6 +4,7 @@ import (
"time"
types "github.com/miguelmota/cointop/pkg/api/types"
"github.com/miguelmota/cointop/pkg/fcache"
)
func (ct *Cointop) updateCoins() error {
@ -28,7 +29,7 @@ func (ct *Cointop) updateCoins() error {
}
ct.cache.Set(cachekey, allcoinsmap, 10*time.Second)
go func() {
_ = ct.writeHardCache(allcoinsmap, "allcoinsmap")
_ = fcache.Set(cachekey, allcoinsmap, 24*time.Hour)
}()
}

@ -2,21 +2,41 @@ package cointop
import (
"fmt"
"time"
types "github.com/miguelmota/cointop/pkg/api/types"
"github.com/miguelmota/cointop/pkg/color"
"github.com/miguelmota/cointop/pkg/fcache"
"github.com/miguelmota/cointop/pkg/humanize"
"github.com/miguelmota/cointop/pkg/pad"
)
func (ct *Cointop) updateMarketbar() error {
maxX := ct.width()
market, err := ct.api.GetGlobalMarketData()
if err != nil {
return err
var market types.GlobalMarketData
var err error
cachekey := "market"
cached, found := ct.cache.Get(cachekey)
if found {
// cache hit
var ok bool
market, ok = cached.(types.GlobalMarketData)
if ok {
ct.debuglog("soft cache hit")
}
} else {
market, err = ct.api.GetGlobalMarketData()
if err != nil {
return err
}
ct.cache.Set(cachekey, market, 10*time.Second)
go func() {
_ = fcache.Set(cachekey, market, 24*time.Hour)
}()
}
go func() {
_ = ct.writeHardCache(market, "market")
}()
timeframe := "7 Day"
chartname := ct.selectedCoinName()
if chartname == "" {

@ -0,0 +1,130 @@
package fcache
import (
"bytes"
"encoding/gob"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync"
"time"
)
const cachedir = "/tmp"
// Set writes item to cache
func Set(key string, data interface{}, expire time.Duration) error {
key = regexp.MustCompile("[^a-zA-Z0-9_-]").ReplaceAllLiteralString(key, "")
file := fmt.Sprintf("fcache.%s.%v", key, strconv.FormatInt(time.Now().Add(expire).Unix(), 10))
fpath := filepath.Join(cachedir, file)
clean(key)
serialized, err := serialize(data)
if err != nil {
return err
}
var fmutex sync.RWMutex
fmutex.Lock()
defer fmutex.Unlock()
fp, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer fp.Close()
if _, err = fp.Write(serialized); err != nil {
return err
}
return nil
}
// Get reads item from cache
func Get(key string, dst interface{}) error {
key = regexp.MustCompile("[^a-zA-Z0-9_-]").ReplaceAllLiteralString(key, "")
pattern := filepath.Join(cachedir, fmt.Sprintf("fcache.%s.*", key))
files, err := filepath.Glob(pattern)
if len(files) < 1 || err != nil {
return errors.New("fcache: no cache file found")
}
if _, err = os.Stat(files[0]); err != nil {
return err
}
fp, err := os.OpenFile(files[0], os.O_RDONLY, 0400)
if err != nil {
return err
}
defer fp.Close()
var serialized []byte
buf := make([]byte, 1024)
for {
var n int
n, err = fp.Read(buf)
serialized = append(serialized, buf[0:n]...)
if err != nil || err == io.EOF {
break
}
}
if err = deserialize(serialized, dst); err != nil {
return err
}
for _, file := range files {
exptime, err := strconv.ParseInt(strings.Split(file, ".")[2], 10, 64)
if err != nil {
return err
}
if exptime < time.Now().Unix() {
if _, err = os.Stat(file); err == nil {
os.Remove(file)
}
}
}
return nil
}
// clean removes item from cache
func clean(key string) error {
pattern := filepath.Join(cachedir, fmt.Sprintf("fcache.%s.*", key))
files, _ := filepath.Glob(pattern)
for _, file := range files {
if _, err := os.Stat(file); err == nil {
os.Remove(file)
}
}
return nil
}
// serialize encodes a value using binary
func serialize(src interface{}) ([]byte, error) {
buf := new(bytes.Buffer)
if err := gob.NewEncoder(buf).Encode(src); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// deserialize decodes a value using binary
func deserialize(src []byte, dst interface{}) error {
buf := bytes.NewReader(src)
if err := gob.NewDecoder(buf).Decode(dst); err != nil {
return err
}
return nil
}
Loading…
Cancel
Save