Add coingecko api key option

master
Miguel Mota 2 months ago
parent fccbc3b63c
commit 409479636d
No known key found for this signature in database
GPG Key ID: 67EC1161588A00F9

@ -31,6 +31,7 @@ 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")
perPage := cointop.DefaultPerPage
maxPages := cointop.DefaultMaxPages
@ -102,6 +103,7 @@ See git.io/cointop for more info.`,
NoCache: noCache,
ConfigFilepath: config,
CoinMarketCapAPIKey: cmcAPIKey,
CoinGeckoAPIKey: coingeckoAPIKey,
APIChoice: apiChoice,
Colorscheme: colorscheme,
HideMarketbar: hideMarketbar,
@ -140,7 +142,8 @@ See git.io/cointop for more info.`,
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", config, fmt.Sprintf("Config filepath. (default %s)", cointop.DefaultConfigFilepath))
rootCmd.Flags().StringVarP(&cmcAPIKey, "coinmarketcap-api-key", "", cmcAPIKey, "Set the CoinMarketCap API key")
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(&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))

@ -169,6 +169,7 @@ type Config struct {
Colorscheme string
ConfigFilepath string
CoinMarketCapAPIKey string
CoinGeckoAPIKey string
NoPrompts bool
HideMarketbar bool
HideChart bool
@ -185,7 +186,8 @@ type Config struct {
// APIKeys is api keys structure
type APIKeys struct {
cmc string
cmc string
coingecko string
}
// DefaultCurrency ...
@ -383,6 +385,14 @@ 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 {
return nil, err
}
}
if config.Colorscheme != "" {
ct.colorschemeName = config.Colorscheme
}
@ -420,10 +430,34 @@ func NewCointop(config *Config) (*Cointop, error) {
}
}
if ct.apiChoice == CoinGecko && ct.apiKeys.coingecko == "" {
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.coingecko = apiKey
// }
} else {
ct.apiKeys.coingecko = 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(perPage, maxPages)
ct.api = api.NewCG(&api.CoinGeckoConfig{
PerPage: perPage,
MaxPages: maxPages,
ApiKey: ct.apiKeys.coingecko,
})
} else {
return nil, ErrInvalidAPIChoice
}

@ -44,6 +44,7 @@ type ConfigFileConfig struct {
DefaultView interface{} `toml:"default_view"`
DefaultChartRange interface{} `toml:"default_chart_range"`
CoinMarketCap map[string]interface{} `toml:"coinmarketcap"`
CoinGecko map[string]interface{} `toml:"coingecko"`
API interface{} `toml:"api"`
Colorscheme interface{} `toml:"colorscheme"`
RefreshRate interface{} `toml:"refresh_rate"`
@ -253,6 +254,10 @@ func (ct *Cointop) ConfigToToml() ([]byte, error) {
"pro_api_key": ct.apiKeys.cmc,
}
coingeckoIfc := map[string]interface{}{
"pro_api_key": ct.apiKeys.coingecko,
}
var priceAlertsIfc []interface{}
for _, priceAlert := range ct.State.priceAlerts.Entries {
if priceAlert.Expired {
@ -287,6 +292,7 @@ func (ct *Cointop) ConfigToToml() ([]byte, error) {
API: ct.apiChoice,
Colorscheme: ct.colorschemeName,
CoinMarketCap: cmcIfc,
CoinGecko: coingeckoIfc,
Currency: ct.State.currencyConversion,
DefaultView: ct.State.defaultView,
DefaultChartRange: ct.State.defaultChartRange,
@ -476,6 +482,12 @@ func (ct *Cointop) loadAPIKeysFromConfig() error {
ct.apiKeys.cmc = value.(string)
}
}
for key, value := range ct.config.CoinGecko {
k := strings.TrimSpace(strings.ToLower(key))
if k == "pro_api_key" {
ct.apiKeys.coingecko = value.(string)
}
}
return nil
}
@ -541,7 +553,7 @@ func (ct *Cointop) loadAltCoinLinkFromConfig() error {
// LoadAPIChoiceFromConfig loads API choices from config file to struct
func (ct *Cointop) loadAPIChoiceFromConfig() error {
log.Debug("loadAPIKeysFromConfig()")
log.Debug("loadAPIChoiceFromConfig()")
apiChoice, ok := ct.config.API.(string)
if ok {
apiChoice = strings.TrimSpace(strings.ToLower(apiChoice))

@ -2,6 +2,7 @@ package cointop
import (
"fmt"
"os"
"github.com/cointop-sh/cointop/pkg/api"
)
@ -22,7 +23,9 @@ func PrintBitcoinDominance(config *DominanceConfig) error {
if config.APIChoice == CoinMarketCap {
coinAPI = api.NewCMC("")
} else if config.APIChoice == CoinGecko {
coinAPI = api.NewCG(0, 0)
coinAPI = api.NewCG(&api.CoinGeckoConfig{
ApiKey: os.Getenv("COINGECKO_PRO_API_KEY"),
})
} else {
return ErrInvalidAPIChoice
}

@ -3,6 +3,7 @@ package cointop
import (
"fmt"
"math"
"os"
"strings"
"github.com/cointop-sh/cointop/pkg/api"
@ -57,7 +58,9 @@ func GetCoinPrices(config *PricesConfig) ([]string, error) {
if config.APIChoice == CoinMarketCap {
priceAPI = api.NewCMC("")
} else if config.APIChoice == CoinGecko {
priceAPI = api.NewCG(0, 0)
priceAPI = api.NewCG(&api.CoinGeckoConfig{
ApiKey: os.Getenv("COINGECKO_PRO_API_KEY"),
})
} else {
return nil, ErrInvalidAPIChoice
}

@ -122,6 +122,27 @@ draft: false
cointop --coinmarketcap-api-key=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```
## How do I add my CoinGecko Pro API key?
Add the API key in the cointop config file:
```toml
[coingecko]
pro_api_key = "CG-xxxxxxxxxxxxxxxxxxxxxxxx"
```
Alternatively, you can export the environment variable `COINGECKO_PRO_API_KEY` containing the API key in your `~/.bashrc`
```bash
export COINGECKO_PRO_API_KEY=CG-xxxxxxxxxxxxxxxxxxxxxxxx
```
You may also set the API key on start:
```bash
cointop --coingecko-api-key=CG-xxxxxxxxxxxxxxxxxxxxxxxx
```
## I can I add my own API to cointop?
Fork cointop and add the API that implements the API [interface](https://github.com/cointop-sh/cointop/blob/master/cointop/common/api/interface.go) to [`cointop/cointop/common/api/impl/`](https://github.com/cointop-sh/cointop/tree/master/cointop/common/api/impl). You can use the CoinGecko [implementation](https://github.com/cointop-sh/cointop/blob/master/cointop/common/api/impl/coingecko/coingecko.go) as reference.

@ -5,6 +5,12 @@ import (
cmc "github.com/cointop-sh/cointop/pkg/api/impl/coinmarketcap"
)
type CoinGeckoConfig struct {
PerPage uint
MaxPages uint
ApiKey string
}
// NewCMC new CoinMarketCap API
func NewCMC(apiKey string) Interface {
return cmc.NewCMC(apiKey)
@ -16,9 +22,10 @@ func NewCC() {
}
// NewCG new CoinGecko API
func NewCG(perPage, maxPages uint) Interface {
func NewCG(config *CoinGeckoConfig) Interface {
return cg.NewCoinGecko(&cg.Config{
PerPage: perPage,
MaxPages: maxPages,
PerPage: config.PerPage,
MaxPages: config.MaxPages,
ApiKey: config.ApiKey,
})
}

@ -26,6 +26,7 @@ var ErrNotFound = errors.New("not found")
type Config struct {
PerPage uint
MaxPages uint
ApiKey string
}
// Service service
@ -52,7 +53,7 @@ func NewCoinGecko(config *Config) *Service {
maxPages = uint(math.Ceil(math.Max(float64(maxResults)/float64(maxResultsPerPage), 1)))
}
client := gecko.NewClient(nil)
client := gecko.NewClient(nil, config.ApiKey)
svc := &Service{
client: client,
maxResultsPerPage: uint(math.Min(float64(maxResults), float64(maxResultsPerPage))),

@ -16,19 +16,18 @@ import (
log "github.com/sirupsen/logrus"
)
var baseURL = "https://api.coingecko.com/api/v3"
// Client struct
type Client struct {
httpClient *http.Client
apiKey string
}
// NewClient create new client object
func NewClient(httpClient *http.Client) *Client {
func NewClient(httpClient *http.Client, apiKey string) *Client {
if httpClient == nil {
httpClient = http.DefaultClient
}
return &Client{httpClient: httpClient}
return &Client{httpClient: httpClient, apiKey: apiKey}
}
// helper
@ -48,7 +47,7 @@ func doReq(req *http.Request, client *http.Client) ([]byte, error) {
if err != nil {
return nil, err
}
if 200 != resp.StatusCode {
if resp.StatusCode != 200 {
if debugHttp {
log.Warnf("doReq Got Status '%s' from %s %s", resp.Status, req.Method, req.URL)
log.Debugf("doReq Got Body: %s", body)
@ -58,6 +57,20 @@ func doReq(req *http.Request, client *http.Client) ([]byte, error) {
return body, nil
}
func (c *Client) getApiUrl(path string, params *url.Values) string {
urlParams := url.Values{}
subdomain := "api"
if params != nil {
urlParams = *params
}
if c.apiKey != "" {
subdomain = "pro-api"
urlParams.Add("x_cg_pro_api_key", c.apiKey)
}
url := fmt.Sprintf("https://%s.coingecko.com/api/v3%s?%s", subdomain, path, urlParams.Encode())
return url
}
// MakeReq HTTP request helper
func (c *Client) MakeReq(url string) ([]byte, error) {
req, err := http.NewRequest("GET", url, nil)
@ -76,7 +89,7 @@ func (c *Client) MakeReq(url string) ([]byte, error) {
// Ping /ping endpoint
func (c *Client) Ping() (*types.Ping, error) {
url := fmt.Sprintf("%s/ping", baseURL)
url := c.getApiUrl("/ping", nil)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -105,14 +118,14 @@ func (c *Client) SimpleSinglePrice(id string, vsCurrency string) (*types.SimpleS
// SimplePrice /simple/price Multiple ID and Currency (ids, vs_currencies)
func (c *Client) SimplePrice(ids []string, vsCurrencies []string) (*map[string]map[string]float32, error) {
params := url.Values{}
params := &url.Values{}
idsParam := strings.Join(ids[:], ",")
vsCurrenciesParam := strings.Join(vsCurrencies[:], ",")
params.Add("ids", idsParam)
params.Add("vs_currencies", vsCurrenciesParam)
url := fmt.Sprintf("%s/simple/price?%s", baseURL, params.Encode())
url := c.getApiUrl("/simple/price", params)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -129,7 +142,7 @@ func (c *Client) SimplePrice(ids []string, vsCurrencies []string) (*map[string]m
// SimpleSupportedVSCurrencies /simple/supported_vs_currencies
func (c *Client) SimpleSupportedVSCurrencies() (*types.SimpleSupportedVSCurrencies, error) {
url := fmt.Sprintf("%s/simple/supported_vs_currencies", baseURL)
url := c.getApiUrl("/simple/supported_vs_currencies", nil)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -145,7 +158,7 @@ func (c *Client) SimpleSupportedVSCurrencies() (*types.SimpleSupportedVSCurrenci
// CoinsList /coins/list
func (c *Client) CoinsList() (*types.CoinList, error) {
url := fmt.Sprintf("%s/coins/list", baseURL)
url := c.getApiUrl("/coins/list", nil)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -164,7 +177,7 @@ func (c *Client) CoinsMarket(vsCurrency string, ids []string, order string, perP
if len(vsCurrency) == 0 {
return nil, fmt.Errorf("vsCurrency is required")
}
params := url.Values{}
params := &url.Values{}
// vsCurrency
params.Add("vs_currency", vsCurrency)
// order
@ -190,7 +203,7 @@ func (c *Client) CoinsMarket(vsCurrency string, ids []string, order string, perP
priceChangePercentageParam := strings.Join(priceChangePercentage[:], ",")
params.Add("price_change_percentage", priceChangePercentageParam)
}
url := fmt.Sprintf("%s/coins/markets?%s", baseURL, params.Encode())
url := c.getApiUrl("/coins/markets", params)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -209,14 +222,14 @@ func (c *Client) CoinsID(id string, localization bool, tickers bool, marketData
if len(id) == 0 {
return nil, fmt.Errorf("id is required")
}
params := url.Values{}
params := &url.Values{}
params.Add("localization", format.Bool2String(localization))
params.Add("tickers", format.Bool2String(tickers))
params.Add("market_data", format.Bool2String(marketData))
params.Add("community_data", format.Bool2String(communityData))
params.Add("developer_data", format.Bool2String(developerData))
params.Add("sparkline", format.Bool2String(sparkline))
url := fmt.Sprintf("%s/coins/%s?%s", baseURL, id, params.Encode())
url := c.getApiUrl(fmt.Sprintf("/coins/%s", id), params)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -235,11 +248,11 @@ func (c *Client) CoinsIDTickers(id string, page int) (*types.CoinsIDTickers, err
if len(id) == 0 {
return nil, fmt.Errorf("id is required")
}
params := url.Values{}
params := &url.Values{}
if page > 0 {
params.Add("page", format.Int2String(page))
}
url := fmt.Sprintf("%s/coins/%s/tickers?%s", baseURL, id, params.Encode())
url := c.getApiUrl(fmt.Sprintf("/coins/%s/tickers", id), params)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -257,11 +270,11 @@ func (c *Client) CoinsIDHistory(id string, date string, localization bool) (*typ
if len(id) == 0 || len(date) == 0 {
return nil, fmt.Errorf("id and date is required")
}
params := url.Values{}
params := &url.Values{}
params.Add("date", date)
params.Add("localization", format.Bool2String(localization))
url := fmt.Sprintf("%s/coins/%s/history?%s", baseURL, id, params.Encode())
url := c.getApiUrl(fmt.Sprintf("/coins/%s/history", id), params)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -280,11 +293,11 @@ func (c *Client) CoinsIDMarketChart(id string, vsCurrency string, days string) (
return nil, fmt.Errorf("id, vsCurrency, and days is required")
}
params := url.Values{}
params := &url.Values{}
params.Add("vs_currency", vsCurrency)
params.Add("days", days)
url := fmt.Sprintf("%s/coins/%s/market_chart?%s", baseURL, id, params.Encode())
url := c.getApiUrl(fmt.Sprintf("/coins/%s/market_chart", id), params)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -303,7 +316,7 @@ func (c *Client) CoinsIDMarketChart(id string, vsCurrency string, days string) (
// CoinsIDContractAddress https://api.coingecko.com/api/v3/coins/{id}/contract/{contract_address}
// func CoinsIDContractAddress(id string, address string) (nil, error) {
// url := fmt.Sprintf("%s/coins/%s/contract/%s", baseURL, id, address)
// url := c.getApiUrl(fmt.Sprintf("/coins/%s/contract/%s", id, address), nil)
// resp, err := request.MakeReq(url)
// if err != nil {
// return nil, err
@ -312,7 +325,7 @@ func (c *Client) CoinsIDMarketChart(id string, vsCurrency string, days string) (
// EventsCountries https://api.coingecko.com/api/v3/events/countries
func (c *Client) EventsCountries() ([]types.EventCountryItem, error) {
url := fmt.Sprintf("%s/events/countries", baseURL)
url := c.getApiUrl("/events/countries", nil)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -328,7 +341,7 @@ func (c *Client) EventsCountries() ([]types.EventCountryItem, error) {
// EventsTypes https://api.coingecko.com/api/v3/events/types
func (c *Client) EventsTypes() (*types.EventsTypes, error) {
url := fmt.Sprintf("%s/events/types", baseURL)
url := c.getApiUrl("/events/types", nil)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -344,7 +357,7 @@ func (c *Client) EventsTypes() (*types.EventsTypes, error) {
// ExchangeRates https://api.coingecko.com/api/v3/exchange_rates
func (c *Client) ExchangeRates() (*types.ExchangeRatesItem, error) {
url := fmt.Sprintf("%s/exchange_rates", baseURL)
url := c.getApiUrl("/exchange_rates", nil)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err
@ -359,7 +372,7 @@ func (c *Client) ExchangeRates() (*types.ExchangeRatesItem, error) {
// Global https://api.coingecko.com/api/v3/global
func (c *Client) Global() (*types.Global, error) {
url := fmt.Sprintf("%s/global", baseURL)
url := c.getApiUrl("/global", nil)
resp, err := c.MakeReq(url)
if err != nil {
return nil, err

Loading…
Cancel
Save