Implement api interface for selective coin data

pull/58/head
Miguel Mota 4 years ago
parent 97facbe48d
commit 3ee33586e5

@ -988,6 +988,7 @@ Frequently asked questions:
- A: Cointop does not do any kind of mining.
- Q: How can I run the cointop SSH server on port 22?
- A: Port 22 is a privileged port so you need to run with `sudo`:
@ -996,6 +997,14 @@ Frequently asked questions:
sudo cointop server -p 22
```
- Q: Why doesn't the version number work when I install with `go get`?
- A: The version number is read from the git tag during the build process but this requires the `GO111MODULE` environment variable to be set in order for Go to read the build information:
```bash
GO111MODULE=on go get github.com/miguelmota/cointop
```
## Mentioned in
Cointop has been mentioned in:

@ -19,7 +19,6 @@ func HoldingsCmd() *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
ct, err := cointop.NewCointop(&cointop.Config{
ConfigFilepath: config,
APIChoice: cointop.CoinGecko,
CacheDir: cointop.DefaultCacheDir,
})
if err != nil {

@ -100,7 +100,7 @@ See git.io/cointop for more info.`,
rootCmd.Flags().UintVarP(&perPage, "per-page", "", perPage, "Per page")
rootCmd.Flags().StringVarP(&config, "config", "c", "", fmt.Sprintf("Config filepath. (default %s)", cointop.DefaultConfigFilepath))
rootCmd.Flags().StringVarP(&cmcAPIKey, "coinmarketcap-api-key", "", "", "Set the CoinMarketCap API key")
rootCmd.Flags().StringVarP(&apiChoice, "api", "", cointop.CoinGecko, "API choice. Available choices are \"coinmarketcap\" and \"coingecko\"")
rootCmd.Flags().StringVarP(&apiChoice, "api", "", "", "API choice. Available choices are \"coinmarketcap\" and \"coingecko\"")
rootCmd.Flags().StringVarP(&colorscheme, "colorscheme", "", "", "Colorscheme to use (default \"cointop\"). To install standard themes, do:\n\ngit clone git@github.com:cointop-sh/colors.git ~/.config/cointop/colors\n\nSee git.io/cointop#colorschemes for more info.")
rootCmd.Flags().StringVarP(&cacheDir, "cache-dir", "", cacheDir, "Cache directory")

@ -507,13 +507,6 @@ func Reset(config *ResetConfig) error {
configDeleted := false
possibleConfigPaths := []string{
"~/.config/cointop/config.toml",
"~/.config/cointop/config",
"~/.cointop/config",
"~/.cointop/config.toml",
}
for _, configPath := range possibleConfigPaths {
normalizedPath := pathutil.NormalizePath(configPath)
if _, err := os.Stat(normalizedPath); !os.IsNotExist(err) {

@ -45,9 +45,8 @@ func (s *Service) Ping() error {
return nil
}
func (s *Service) getLimitedCoinData(convert string, offset int) ([]apitypes.Coin, error) {
func (s *Service) getPaginatedCoinData(convert string, offset int, names []string) ([]apitypes.Coin, error) {
var ret []apitypes.Coin
ids := []string{}
page := offset
sparkline := false
pcp := geckoTypes.PriceChangePercentageObject
@ -57,6 +56,12 @@ func (s *Service) getLimitedCoinData(convert string, offset int) ([]apitypes.Coi
if convertTo == "" {
convertTo = "usd"
}
ids := make([]string, len(names))
for i, name := range names {
slug := util.NameToSlug(name)
ids[i] = slug
}
list, err := s.client.CoinsMarket(convertTo, ids, order, s.maxResultsPerPage, page, sparkline, priceChangePercentage)
if err != nil {
return nil, err
@ -124,7 +129,7 @@ func (s *Service) GetAllCoinData(convert string, ch chan []apitypes.Coin) error
time.Sleep(1 * time.Second)
}
coins, err := s.getLimitedCoinData(convert, i)
coins, err := s.getPaginatedCoinData(convert, i, []string{})
if err != nil {
return
}
@ -135,6 +140,27 @@ func (s *Service) GetAllCoinData(convert string, ch chan []apitypes.Coin) error
return nil
}
// GetCoinData gets all data of a coin.
func (s *Service) GetCoinData(name string, convert string) (apitypes.Coin, error) {
ret := apitypes.Coin{}
ids := []string{name}
coins, err := s.getPaginatedCoinData(convert, 0, ids)
if err != nil {
return ret, err
}
if len(coins) > 0 {
ret = coins[0]
}
return ret, nil
}
// GetCoinDataBatch gets all data of specified coins.
func (s *Service) GetCoinDataBatch(names []string, convert string) ([]apitypes.Coin, error) {
return s.getPaginatedCoinData(convert, 0, names)
}
// GetCoinGraphData gets coin graph data
func (s *Service) GetCoinGraphData(convert, symbol, name string, start, end int64) (apitypes.CoinGraph, error) {
ret := apitypes.CoinGraph{}

@ -51,7 +51,7 @@ func (s *Service) Ping() error {
return nil
}
func (s *Service) getLimitedCoinData(convert string, offset int) ([]apitypes.Coin, error) {
func (s *Service) getPaginatedCoinData(convert string, offset int) ([]apitypes.Coin, error) {
var ret []apitypes.Coin
max := 100
@ -98,7 +98,7 @@ func (s *Service) GetAllCoinData(convert string, ch chan []apitypes.Coin) error
time.Sleep(1 * time.Second)
}
coins, err := s.getLimitedCoinData(convert, i)
coins, err := s.getPaginatedCoinData(convert, i)
if err != nil {
return
}
@ -109,6 +109,43 @@ func (s *Service) GetAllCoinData(convert string, ch chan []apitypes.Coin) error
return nil
}
// GetCoinData gets all data of a coin.
func (s *Service) GetCoinData(name string, convert string) (apitypes.Coin, error) {
ret := apitypes.Coin{}
coins, err := s.getPaginatedCoinData(convert, 0)
if err != nil {
return ret, err
}
for _, coin := range coins {
if coin.Name == name {
return coin, nil
}
}
return ret, nil
}
// GetCoinDataBatch gets all data of specified coins.
func (s *Service) GetCoinDataBatch(names []string, convert string) ([]apitypes.Coin, error) {
ret := []apitypes.Coin{}
coins, err := s.getPaginatedCoinData(convert, 0)
if err != nil {
return ret, err
}
for _, coin := range coins {
for _, name := range names {
if coin.Name == name {
ret = append(ret, coin)
break
}
}
}
return ret, nil
}
// GetCoinGraphData gets coin graph data
func (s *Service) GetCoinGraphData(convert, symbol string, name string, start int64, end int64) (apitypes.CoinGraph, error) {
ret := apitypes.CoinGraph{}

@ -11,7 +11,8 @@ type Interface interface {
GetCoinGraphData(convert string, symbol string, name string, start int64, end int64) (types.CoinGraph, error)
GetGlobalMarketGraphData(convert string, start int64, end int64) (types.MarketGraph, error)
GetGlobalMarketData(convert string) (types.GlobalMarketData, error)
//GetCoinData(coin string) (types.Coin, error)
GetCoinData(name string, convert string) (types.Coin, error)
GetCoinDataBatch(names []string, convert string) ([]types.Coin, error)
//GetAltcoinMarketGraphData(start int64, end int64) (types.MarketGraph, error)
//GetCoinPriceUSD(coin string) (float64, error)
//GetCoinMarkets(coin string) ([]types.Market, error)

@ -15,6 +15,14 @@ import (
var fileperm = os.FileMode(0644)
// NOTE: this is to support previous default config filepaths
var possibleConfigPaths = []string{
"~/.config/cointop/config.toml",
"~/.config/cointop/config",
"~/.cointop/config",
"~/.cointop/config.toml",
}
type config struct {
Shortcuts map[string]interface{} `toml:"shortcuts"`
Favorites map[string][]interface{} `toml:"favorites"`
@ -42,9 +50,6 @@ func (ct *Cointop) SetupConfig() error {
if err := ct.loadFavoritesFromConfig(); err != nil {
return err
}
if err := ct.loadPortfolioFromConfig(); err != nil {
return err
}
if err := ct.loadCurrencyFromConfig(); err != nil {
return err
}
@ -63,6 +68,9 @@ func (ct *Cointop) SetupConfig() error {
if err := ct.loadRefreshRateFromConfig(); err != nil {
return err
}
if err := ct.loadPortfolioFromConfig(); err != nil {
return err
}
return nil
}
@ -71,14 +79,8 @@ func (ct *Cointop) SetupConfig() error {
func (ct *Cointop) CreateConfigIfNotExists() error {
ct.debuglog("createConfigIfNotExists()")
// NOTE: this is to support previous default config filepaths
previousDefaultConfigPaths := []string{
"~/.cointop/config",
"~/.cointop/config.toml",
}
for _, previousConfigFilepath := range previousDefaultConfigPaths {
normalizedPath := pathutil.NormalizePath(previousConfigFilepath)
for _, configPath := range possibleConfigPaths {
normalizedPath := pathutil.NormalizePath(configPath)
if _, err := os.Stat(normalizedPath); err == nil {
ct.configFilepath = normalizedPath
return nil
@ -218,8 +220,8 @@ func (ct *Cointop) configToToml() ([]byte, error) {
cmcIfc := map[string]interface{}{
"pro_api_key": ct.apiKeys.cmc,
}
var apiChoiceIfc interface{} = ct.apiChoice
var apiChoiceIfc interface{} = ct.apiChoice
var inputs = &config{
API: apiChoiceIfc,
Colorscheme: colorschemeIfc,

@ -184,7 +184,7 @@ func (ct *Cointop) SetPortfolioHoldings() error {
// PortfolioEntry returns a portfolio entry
func (ct *Cointop) PortfolioEntry(c *Coin) (*PortfolioEntry, bool) {
//ct.debuglog("portfolioEntry()")
//ct.debuglog("portfolioEntry()") // too many
if c == nil {
return &PortfolioEntry{}, true
}
@ -297,20 +297,28 @@ func (ct *Cointop) GetPortfolioTotal() float64 {
return total
}
// NormalizeFloatString normalizes a float as a string
func normalizeFloatString(input string) string {
re := regexp.MustCompile(`(\d+\.\d+|\.\d+|\d+)`)
result := re.FindStringSubmatch(input)
if len(result) > 0 {
return result[0]
// RefreshPortfolioCoins refreshes portfolio entry coin data
func (ct *Cointop) RefreshPortfolioCoins() error {
ct.debuglog("refreshPortfolioCoins()")
holdings := ct.GetPortfolioSlice()
holdingCoins := make([]string, len(holdings))
for i, entry := range holdings {
holdingCoins[i] = entry.Name
}
return ""
coins, err := ct.api.GetCoinDataBatch(holdingCoins, ct.State.currencyConversion)
ct.processCoins(coins)
if err != nil {
return err
}
return nil
}
// PrintHoldingsTable prints the holdings in an ASCII table
func (ct *Cointop) PrintHoldingsTable() error {
ct.UpdateCoins() // fetches latest data
ct.debuglog("printHoldingsTable()")
ct.RefreshPortfolioCoins()
holdings := ct.GetPortfolioSlice()
total := ct.GetPortfolioTotal()
data := make([][]string, len(holdings))
@ -347,10 +355,22 @@ func (ct *Cointop) PrintHoldingsTable() error {
// PrintTotalHoldings prints the total holdings amount
func (ct *Cointop) PrintTotalHoldings() error {
ct.UpdateCoins() // fetches latest data
ct.debuglog("printTotalHoldings()")
ct.RefreshPortfolioCoins()
total := ct.GetPortfolioTotal()
symbol := ct.CurrencySymbol()
fmt.Fprintf(os.Stdout, "%s%s\n", symbol, humanize.Commaf(total))
return nil
}
// NormalizeFloatString normalizes a float as a string
func normalizeFloatString(input string) string {
re := regexp.MustCompile(`(\d+\.\d+|\.\d+|\d+)`)
result := re.FindStringSubmatch(input)
if len(result) > 0 {
return result[0]
}
return ""
}

Loading…
Cancel
Save