From cbe355701546a181e77ff536371813161ad5b5ac Mon Sep 17 00:00:00 2001 From: Miguel Mota Date: Sun, 7 Apr 2024 15:34:11 -0700 Subject: [PATCH] Add option for coingecko demo api key --- cmd/commands/root.go | 7 +++-- cointop/cointop.go | 45 ++++++++++++++++++++++++----- cointop/config.go | 8 +++-- cointop/price.go | 3 +- docs/content/config.md | 3 ++ docs/content/faq.md | 27 +++++++++++++++-- pkg/api/api.go | 14 +++++---- pkg/api/impl/coingecko/coingecko.go | 9 +++--- pkg/api/vendors/coingecko/v3/v3.go | 10 +++++-- 9 files changed, 97 insertions(+), 29 deletions(-) diff --git a/cmd/commands/root.go b/cmd/commands/root.go index fe01669..6967eac 100644 --- a/cmd/commands/root.go +++ b/cmd/commands/root.go @@ -31,7 +31,8 @@ func RootCmd() *cobra.Command { config := os.Getenv("COINTOP_CONFIG") apiChoice := os.Getenv("COINTOP_API") cmcAPIKey := os.Getenv("CMC_PRO_API_KEY") - coingeckoAPIKey := os.Getenv("COINGECKO_PRO_API_KEY") + coingeckoAPIKey := os.Getenv("COINGECKO_API_KEY") + coingeckoProAPIKey := os.Getenv("COINGECKO_PRO_API_KEY") perPage := cointop.DefaultPerPage maxPages := cointop.DefaultMaxPages @@ -104,6 +105,7 @@ See git.io/cointop for more info.`, ConfigFilepath: config, CoinMarketCapAPIKey: cmcAPIKey, CoinGeckoAPIKey: coingeckoAPIKey, + CoinGeckoProAPIKey: coingeckoProAPIKey, APIChoice: apiChoice, Colorscheme: colorscheme, HideMarketbar: hideMarketbar, @@ -143,7 +145,8 @@ See git.io/cointop for more info.`, rootCmd.Flags().UintVarP(&maxPages, "max-pages", "", maxPages, "Max number of pages") rootCmd.Flags().StringVarP(&config, "config", "c", config, fmt.Sprintf("Config filepath. (default %s)", cointop.DefaultConfigFilepath)) rootCmd.Flags().StringVarP(&cmcAPIKey, "coinmarketcap-api-key", "", cmcAPIKey, "Set the CoinMarketCap Pro API key") - rootCmd.Flags().StringVarP(&coingeckoAPIKey, "coingecko-api-key", "", coingeckoAPIKey, "Set the CoinGecko Pro API key") + rootCmd.Flags().StringVarP(&coingeckoAPIKey, "coingecko-api-key", "", coingeckoAPIKey, "Set the CoinGecko Demo API key") + rootCmd.Flags().StringVarP(&coingeckoProAPIKey, "coingecko-pro-api-key", "", coingeckoProAPIKey, "Set the CoinGecko Pro API key") rootCmd.Flags().StringVarP(&apiChoice, "api", "", apiChoice, "API choice. Available choices are \"coinmarketcap\" and \"coingecko\"") rootCmd.Flags().StringVarP(&colorscheme, "colorscheme", "", colorscheme, fmt.Sprintf("Colorscheme to use (default \"cointop\").\n%s", cointop.ColorschemeHelpString())) rootCmd.Flags().StringVarP(&cacheDir, "cache-dir", "", cacheDir, fmt.Sprintf("Cache directory (default %s)", cointop.DefaultCacheDir)) diff --git a/cointop/cointop.go b/cointop/cointop.go index bcb1b79..72dd871 100644 --- a/cointop/cointop.go +++ b/cointop/cointop.go @@ -170,6 +170,7 @@ type Config struct { ConfigFilepath string CoinMarketCapAPIKey string CoinGeckoAPIKey string + CoinGeckoProAPIKey string NoPrompts bool HideMarketbar bool HideChart bool @@ -186,8 +187,9 @@ type Config struct { // APIKeys is api keys structure type APIKeys struct { - cmc string - coingecko string + cmc string + coingecko string + coingeckoPro string } // DefaultCurrency ... @@ -385,7 +387,6 @@ func NewCointop(config *Config) (*Cointop, error) { } } - // prompt for CoinGecko api key if not found if config.CoinGeckoAPIKey != "" { ct.apiKeys.coingecko = config.CoinGeckoAPIKey if err := ct.SaveConfig(); err != nil { @@ -393,6 +394,13 @@ func NewCointop(config *Config) (*Cointop, error) { } } + if config.CoinGeckoProAPIKey != "" { + ct.apiKeys.coingeckoPro = config.CoinGeckoProAPIKey + if err := ct.SaveConfig(); err != nil { + return nil, err + } + } + if config.Colorscheme != "" { ct.colorschemeName = config.Colorscheme } @@ -431,10 +439,10 @@ func NewCointop(config *Config) (*Cointop, error) { } if ct.apiChoice == CoinGecko && ct.apiKeys.coingecko == "" { - apiKey := os.Getenv("COINGECKO_PRO_API_KEY") + apiKey := os.Getenv("COINGECKO_API_KEY") if apiKey == "" { // if !config.NoPrompts { - // apiKey, err = ct.ReadAPIKeyFromStdin("CoinGecko Pro") + // apiKey, err = ct.ReadAPIKeyFromStdin("CoinGecko") // if err != nil { // return nil, err // } @@ -450,13 +458,34 @@ func NewCointop(config *Config) (*Cointop, error) { } } + if ct.apiChoice == CoinGecko && ct.apiKeys.coingeckoPro == "" { + apiKey := os.Getenv("COINGECKO_PRO_API_KEY") + if apiKey == "" { + // if !config.NoPrompts { + // apiKey, err = ct.ReadAPIKeyFromStdin("CoinGecko Pro") + // if err != nil { + // return nil, err + // } + + // ct.apiKeys.coingeckoPro = apiKey + // } + } else { + ct.apiKeys.coingeckoPro = apiKey + } + + if err := ct.SaveConfig(); err != nil { + return nil, err + } + } + if ct.apiChoice == CoinMarketCap { ct.api = api.NewCMC(ct.apiKeys.cmc) } else if ct.apiChoice == CoinGecko { ct.api = api.NewCG(&api.CoinGeckoConfig{ - PerPage: perPage, - MaxPages: maxPages, - ApiKey: ct.apiKeys.coingecko, + PerPage: perPage, + MaxPages: maxPages, + ApiKey: ct.apiKeys.coingecko, + ProApiKey: ct.apiKeys.coingeckoPro, }) } else { return nil, ErrInvalidAPIChoice diff --git a/cointop/config.go b/cointop/config.go index 5297d84..c201c89 100644 --- a/cointop/config.go +++ b/cointop/config.go @@ -255,7 +255,8 @@ func (ct *Cointop) ConfigToToml() ([]byte, error) { } coingeckoIfc := map[string]interface{}{ - "pro_api_key": ct.apiKeys.coingecko, + "api_key": ct.apiKeys.coingecko, + "pro_api_key": ct.apiKeys.coingeckoPro, } var priceAlertsIfc []interface{} @@ -484,9 +485,12 @@ func (ct *Cointop) loadAPIKeysFromConfig() error { } for key, value := range ct.config.CoinGecko { k := strings.TrimSpace(strings.ToLower(key)) - if k == "pro_api_key" { + if k == "api_key" { ct.apiKeys.coingecko = value.(string) } + if k == "pro_api_key" { + ct.apiKeys.coingeckoPro = value.(string) + } } return nil } diff --git a/cointop/price.go b/cointop/price.go index 540b86b..ae6ba6c 100644 --- a/cointop/price.go +++ b/cointop/price.go @@ -59,7 +59,8 @@ func GetCoinPrices(config *PricesConfig) ([]string, error) { priceAPI = api.NewCMC("") } else if config.APIChoice == CoinGecko { priceAPI = api.NewCG(&api.CoinGeckoConfig{ - ApiKey: os.Getenv("COINGECKO_PRO_API_KEY"), + ApiKey: os.Getenv("COINGECKO_API_KEY"), + ProApiKey: os.Getenv("COINGECKO_PRO_API_KEY"), }) } else { return nil, ErrInvalidAPIChoice diff --git a/docs/content/config.md b/docs/content/config.md index 8570449..3466bf9 100644 --- a/docs/content/config.md +++ b/docs/content/config.md @@ -123,6 +123,9 @@ refresh_rate = 60 [coinmarketcap] pro_api_key = "" + +[coingecko] + pro_api_key = "" ``` ## List of actions diff --git a/docs/content/faq.md b/docs/content/faq.md index f835ec6..dc253f7 100644 --- a/docs/content/faq.md +++ b/docs/content/faq.md @@ -97,7 +97,7 @@ draft: false Run cointop with the `--clean` flag to delete the cache. If you're still not seeing any data, then please [submit an issue](https://github.com/cointop-sh/cointop/issues/new). -## How do I get a CoinMarketCap Pro API key? +## How do I get a CoinMarketCap Pro (Paid) API key? Create an account on [CoinMarketCap](https://pro.coinmarketcap.com/signup) and visit the [Account](https://pro.coinmarketcap.com/account) page to copy your Pro API key. @@ -122,7 +122,28 @@ draft: false cointop --coinmarketcap-api-key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ``` -## How do I add my CoinGecko Pro API key? +## How do I add my CoinGecko Demo (Free) API key? + + Add the API key in the cointop config file: + + ```toml + [coingecko] + api_key = "CG-xxxxxxxxxxxxxxxxxxxxxxxx" + ``` + + Alternatively, you can export the environment variable `COINGECKO_API_KEY` containing the API key in your `~/.bashrc` + + ```bash + export COINGECKO_API_KEY=CG-xxxxxxxxxxxxxxxxxxxxxxxx + ``` + + You may also set the API key on start: + + ```bash + cointop --coingecko-api-key=CG-xxxxxxxxxxxxxxxxxxxxxxxx + ``` + +## How do I add my CoinGecko Pro (Paid) API key? Add the API key in the cointop config file: @@ -140,7 +161,7 @@ draft: false You may also set the API key on start: ```bash - cointop --coingecko-api-key=CG-xxxxxxxxxxxxxxxxxxxxxxxx + cointop --coingecko-pro-api-key=CG-xxxxxxxxxxxxxxxxxxxxxxxx ``` ## I can I add my own API to cointop? diff --git a/pkg/api/api.go b/pkg/api/api.go index 7b192ff..fa14c99 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -6,9 +6,10 @@ import ( ) type CoinGeckoConfig struct { - PerPage uint - MaxPages uint - ApiKey string + PerPage uint + MaxPages uint + ApiKey string + ProApiKey string } // NewCMC new CoinMarketCap API @@ -24,8 +25,9 @@ func NewCC() { // NewCG new CoinGecko API func NewCG(config *CoinGeckoConfig) Interface { return cg.NewCoinGecko(&cg.Config{ - PerPage: config.PerPage, - MaxPages: config.MaxPages, - ApiKey: config.ApiKey, + PerPage: config.PerPage, + MaxPages: config.MaxPages, + ApiKey: config.ApiKey, + ProApiKey: config.ProApiKey, }) } diff --git a/pkg/api/impl/coingecko/coingecko.go b/pkg/api/impl/coingecko/coingecko.go index 268daf6..ef08613 100644 --- a/pkg/api/impl/coingecko/coingecko.go +++ b/pkg/api/impl/coingecko/coingecko.go @@ -24,9 +24,10 @@ var ErrNotFound = errors.New("not found") // Config config type Config struct { - PerPage uint - MaxPages uint - ApiKey string + PerPage uint + MaxPages uint + ApiKey string + ProApiKey string } // Service service @@ -53,7 +54,7 @@ func NewCoinGecko(config *Config) *Service { maxPages = uint(math.Ceil(math.Max(float64(maxResults)/float64(maxResultsPerPage), 1))) } - client := gecko.NewClient(nil, config.ApiKey) + client := gecko.NewClient(nil, config.ApiKey, config.ProApiKey) svc := &Service{ client: client, maxResultsPerPage: uint(math.Min(float64(maxResults), float64(maxResultsPerPage))), diff --git a/pkg/api/vendors/coingecko/v3/v3.go b/pkg/api/vendors/coingecko/v3/v3.go index 57f556e..8c35b5e 100644 --- a/pkg/api/vendors/coingecko/v3/v3.go +++ b/pkg/api/vendors/coingecko/v3/v3.go @@ -20,14 +20,15 @@ import ( type Client struct { httpClient *http.Client apiKey string + proApiKey string } // NewClient create new client object -func NewClient(httpClient *http.Client, apiKey string) *Client { +func NewClient(httpClient *http.Client, apiKey string, proApiKey string) *Client { if httpClient == nil { httpClient = http.DefaultClient } - return &Client{httpClient: httpClient, apiKey: apiKey} + return &Client{httpClient: httpClient, apiKey: apiKey, proApiKey: proApiKey} } // helper @@ -64,8 +65,11 @@ func (c *Client) getApiUrl(path string, params *url.Values) string { urlParams = *params } if c.apiKey != "" { + urlParams.Add("x_cg_demo_api_key", c.apiKey) + } + if c.proApiKey != "" { subdomain = "pro-api" - urlParams.Add("x_cg_pro_api_key", c.apiKey) + urlParams.Add("x_cg_pro_api_key", c.proApiKey) } url := fmt.Sprintf("https://%s.coingecko.com/api/v3%s?%s", subdomain, path, urlParams.Encode()) return url