From faabbfc8a664bebebddccf2eeb878472185f2bed Mon Sep 17 00:00:00 2001 From: Miguel Mota Date: Tue, 23 Feb 2021 00:05:34 -0800 Subject: [PATCH] Add max pages flag --- cmd/commands/root.go | 3 +++ cointop/cointop.go | 32 ++++++++++++++++++++++----- cointop/dominance.go | 2 +- cointop/price.go | 2 +- pkg/api/api.go | 7 ++++-- pkg/api/impl/coingecko/coingecko.go | 34 +++++++++++++++++++++++------ 6 files changed, 63 insertions(+), 17 deletions(-) diff --git a/cmd/commands/root.go b/cmd/commands/root.go index 71ff00d..98832ef 100644 --- a/cmd/commands/root.go +++ b/cmd/commands/root.go @@ -25,6 +25,7 @@ func RootCmd() *cobra.Command { var apiChoice string var colorscheme string var perPage = cointop.DefaultPerPage + var maxPages = cointop.DefaultMaxPages var cacheDir string var colorsDir string @@ -91,6 +92,7 @@ See git.io/cointop for more info.`, OnlyTable: onlyTable, RefreshRate: refreshRateP, PerPage: perPage, + MaxPages: maxPages, }) if err != nil { return err @@ -112,6 +114,7 @@ See git.io/cointop for more info.`, rootCmd.Flags().BoolVarP(&noCache, "no-cache", "", false, "No cache") rootCmd.Flags().UintVarP(&refreshRate, "refresh-rate", "r", 60, "Refresh rate in seconds. Set to 0 to not auto-refresh") rootCmd.Flags().UintVarP(&perPage, "per-page", "", perPage, "Per page") + rootCmd.Flags().UintVarP(&maxPages, "max-pages", "", maxPages, "Max number of pages") 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", "", "", "API choice. Available choices are \"coinmarketcap\" and \"coingecko\"") diff --git a/cointop/cointop.go b/cointop/cointop.go index 56428e3..d6efb0f 100644 --- a/cointop/cointop.go +++ b/cointop/cointop.go @@ -56,6 +56,7 @@ type State struct { keepRowFocusOnSort bool lastSelectedRowIndex int marketBarHeight int + maxPages int page int perPage int portfolio *Portfolio @@ -154,6 +155,7 @@ type Config struct { OnlyTable bool RefreshRate *uint PerPage uint + MaxPages uint } // APIKeys is api keys structure @@ -161,9 +163,21 @@ type APIKeys struct { cmc string } +// DefaultCurrency ... +var DefaultCurrency = "USD" + +// DefaultChartRange ... +var DefaultChartRange = "1Y" + +// DefaultSortBy ... +var DefaultSortBy = "rank" + // DefaultPerPage ... var DefaultPerPage uint = 100 +// MaxPages +var DefaultMaxPages uint = 35 + // DefaultColorscheme ... var DefaultColorscheme = "cointop" @@ -193,10 +207,15 @@ func NewCointop(config *Config) (*Cointop, error) { } perPage := DefaultPerPage - if config.PerPage != 0 { + if config.PerPage > 0 { perPage = config.PerPage } + maxPages := DefaultMaxPages + if config.MaxPages > 0 { + maxPages = config.MaxPages + } + ct := &Cointop{ // defaults apiChoice: CoinGecko, @@ -210,13 +229,13 @@ func NewCointop(config *Config) (*Cointop, error) { chartRanges: ChartRanges(), debug: debug, chartRangesMap: ChartRangesMap(), - limiter: time.Tick(2 * time.Second), + limiter: time.NewTicker(2 * time.Second).C, filecache: nil, State: &State{ allCoins: []*Coin{}, cacheDir: DefaultCacheDir, coinsTableColumns: DefaultCoinTableHeaders, - currencyConversion: "USD", + currencyConversion: DefaultCurrency, // DEPRECATED: favorites by 'symbol' is deprecated because of collisions. Kept for backward compatibility. favoritesBySymbol: make(map[string]bool), favorites: make(map[string]bool), @@ -226,11 +245,12 @@ func NewCointop(config *Config) (*Cointop, error) { hideStatusbar: config.HideStatusbar, keepRowFocusOnSort: false, marketBarHeight: 1, + maxPages: int(maxPages), onlyTable: config.OnlyTable, refreshRate: 60 * time.Second, - selectedChartRange: "1Y", + selectedChartRange: DefaultChartRange, shortcutKeys: DefaultShortcuts(), - sortBy: "rank", + sortBy: DefaultSortBy, page: 0, perPage: int(perPage), portfolio: &Portfolio{ @@ -346,7 +366,7 @@ func NewCointop(config *Config) (*Cointop, error) { if ct.apiChoice == CoinMarketCap { ct.api = api.NewCMC(ct.apiKeys.cmc) } else if ct.apiChoice == CoinGecko { - ct.api = api.NewCG() + ct.api = api.NewCG(perPage, maxPages) } else { return nil, ErrInvalidAPIChoice } diff --git a/cointop/dominance.go b/cointop/dominance.go index e400936..5fdea85 100644 --- a/cointop/dominance.go +++ b/cointop/dominance.go @@ -22,7 +22,7 @@ func PrintBitcoinDominance(config *DominanceConfig) error { if config.APIChoice == CoinMarketCap { coinAPI = api.NewCMC("") } else if config.APIChoice == CoinGecko { - coinAPI = api.NewCG() + coinAPI = api.NewCG(0, 0) } else { return ErrInvalidAPIChoice } diff --git a/cointop/price.go b/cointop/price.go index c24059a..2d43304 100644 --- a/cointop/price.go +++ b/cointop/price.go @@ -56,7 +56,7 @@ func GetCoinPrices(config *PricesConfig) ([]string, error) { if config.APIChoice == CoinMarketCap { priceAPI = api.NewCMC("") } else if config.APIChoice == CoinGecko { - priceAPI = api.NewCG() + priceAPI = api.NewCG(0, 0) } else { return nil, ErrInvalidAPIChoice } diff --git a/pkg/api/api.go b/pkg/api/api.go index b045efd..a561212 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -16,6 +16,9 @@ func NewCC() { } // NewCG new CoinGecko API -func NewCG() Interface { - return cg.NewCoinGecko() +func NewCG(perPage, maxPages uint) Interface { + return cg.NewCoinGecko(&cg.Config{ + PerPage: perPage, + MaxPages: maxPages, + }) } diff --git a/pkg/api/impl/coingecko/coingecko.go b/pkg/api/impl/coingecko/coingecko.go index 2aa3ecf..dba038a 100644 --- a/pkg/api/impl/coingecko/coingecko.go +++ b/pkg/api/impl/coingecko/coingecko.go @@ -3,6 +3,7 @@ package coingecko import ( "errors" "fmt" + "math" "strconv" "strings" "sync" @@ -20,21 +21,40 @@ var ErrPingFailed = errors.New("failed to ping") // ErrNotFound is the error when the target is not found var ErrNotFound = errors.New("not found") +// Config config +type Config struct { + PerPage uint + MaxPages uint +} + // Service service type Service struct { client *gecko.Client - maxResultsPerPage int - maxPages int + maxResultsPerPage uint + maxPages uint cacheMap sync.Map } // NewCoinGecko new service -func NewCoinGecko() *Service { +func NewCoinGecko(config *Config) *Service { + var maxResultsPerPage uint = 250 // absolute max + var maxResults uint = 0 + var maxPages uint = 10 + var perPage uint = 100 + if config.PerPage > 0 { + perPage = config.PerPage + } + if config.MaxPages > 0 { + maxPages = config.MaxPages + maxResults = perPage * maxPages + maxPages = uint(math.Ceil(math.Max(float64(maxResults)/float64(maxResultsPerPage), 1))) + } + client := gecko.NewClient(nil) svc := &Service{ client: client, - maxResultsPerPage: 250, // max is 250 - maxPages: 10, + maxResultsPerPage: uint(math.Min(float64(maxResults), float64(maxResultsPerPage))), + maxPages: maxPages, cacheMap: sync.Map{}, } svc.cacheCoinsIDList() @@ -55,7 +75,7 @@ func (s *Service) GetAllCoinData(convert string, ch chan []apitypes.Coin) error go func() { defer close(ch) - for i := 0; i < s.maxPages; i++ { + for i := 0; i < int(s.maxPages); i++ { if i > 0 { time.Sleep(1 * time.Second) } @@ -334,7 +354,7 @@ func (s *Service) getPaginatedCoinData(convert string, offset int, names []strin for i, name := range names { ids[i] = s.coinNameToID(name) } - list, err := s.client.CoinsMarket(convertTo, ids, order, s.maxResultsPerPage, page, sparkline, priceChangePercentage) + list, err := s.client.CoinsMarket(convertTo, ids, order, int(s.maxResultsPerPage), page, sparkline, priceChangePercentage) if err != nil { return nil, err }