Feature/Add Coingecko api keys support (#2827)

* Add CoinGecko API keys support

* Update changelog
pull/2835/head
Tanguy Herbron 11 months ago committed by GitHub
parent af71274ea9
commit d91f947ab0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Added
- Added support to set a _CoinGecko_ Demo API key via environment variable (`API_KEY_COINGECKO_DEMO`)
- Added support to set a _CoinGecko_ Pro API key via environment variable (`API_KEY_COINGECKO_PRO`)
### Changed ### Changed
- Removed the `AccountType` enum - Removed the `AccountType` enum

@ -87,20 +87,22 @@ We provide official container images hosted on [Docker Hub](https://hub.docker.c
### Supported Environment Variables ### Supported Environment Variables
| Name | Default Value | Description | | Name | Default Value | Description |
| ------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | ------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `ACCESS_TOKEN_SALT` | | A random string used as salt for access tokens | | `ACCESS_TOKEN_SALT` | | A random string used as salt for access tokens |
| `DATABASE_URL` | | The database connection URL, e.g. `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer` | | `API_KEY_COINGECKO_DEMO` |   | The _CoinGecko_ Demo API key |
| `HOST` | `0.0.0.0` | The host where the Ghostfolio application will run on | | `API_KEY_COINGECKO_PRO` |   | The _CoinGecko_ Pro API |
| `JWT_SECRET_KEY` | | A random string used for _JSON Web Tokens_ (JWT) | | `DATABASE_URL` | | The database connection URL, e.g. `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer` |
| `PORT` | `3333` | The port where the Ghostfolio application will run on | | `HOST` | `0.0.0.0` | The host where the Ghostfolio application will run on |
| `POSTGRES_DB` | | The name of the _PostgreSQL_ database | | `JWT_SECRET_KEY` | | A random string used for _JSON Web Tokens_ (JWT) |
| `POSTGRES_PASSWORD` | | The password of the _PostgreSQL_ database | | `PORT` | `3333` | The port where the Ghostfolio application will run on |
| `POSTGRES_USER` | | The user of the _PostgreSQL_ database | | `POSTGRES_DB` | | The name of the _PostgreSQL_ database |
| `REDIS_HOST` | | The host where _Redis_ is running | | `POSTGRES_PASSWORD` | | The password of the _PostgreSQL_ database |
| `REDIS_PASSWORD` | | The password of _Redis_ | | `POSTGRES_USER` | | The user of the _PostgreSQL_ database |
| `REDIS_PORT` | | The port where _Redis_ is running | | `REDIS_HOST` | | The host where _Redis_ is running |
| `REQUEST_TIMEOUT` | `2000` | The timeout of network requests to data providers in milliseconds | | `REDIS_PASSWORD` | | The password of _Redis_ |
| `REDIS_PORT` | | The port where _Redis_ is running |
| `REQUEST_TIMEOUT` | `2000` | The timeout of network requests to data providers in milliseconds |
### Run with Docker Compose ### Run with Docker Compose

@ -12,6 +12,8 @@ export class ConfigurationService {
this.environmentConfiguration = cleanEnv(process.env, { this.environmentConfiguration = cleanEnv(process.env, {
ACCESS_TOKEN_SALT: str(), ACCESS_TOKEN_SALT: str(),
ALPHA_VANTAGE_API_KEY: str({ default: '' }), ALPHA_VANTAGE_API_KEY: str({ default: '' }),
API_KEY_COINGECKO_DEMO: str({ default: '' }),
API_KEY_COINGECKO_PRO: str({ default: '' }),
BETTER_UPTIME_API_KEY: str({ default: '' }), BETTER_UPTIME_API_KEY: str({ default: '' }),
CACHE_QUOTES_TTL: num({ default: 1 }), CACHE_QUOTES_TTL: num({ default: 1 }),
CACHE_TTL: num({ default: 1 }), CACHE_TTL: num({ default: 1 }),

@ -17,15 +17,30 @@ import {
SymbolProfile SymbolProfile
} from '@prisma/client'; } from '@prisma/client';
import { format, fromUnixTime, getUnixTime } from 'date-fns'; import { format, fromUnixTime, getUnixTime } from 'date-fns';
import got from 'got'; import got, { Headers } from 'got';
@Injectable() @Injectable()
export class CoinGeckoService implements DataProviderInterface { export class CoinGeckoService implements DataProviderInterface {
private readonly URL = 'https://api.coingecko.com/api/v3'; private readonly apiUrl: string;
private readonly headers: Headers = {};
public constructor( public constructor(
private readonly configurationService: ConfigurationService private readonly configurationService: ConfigurationService
) {} ) {
const apiKeyDemo = this.configurationService.get('API_KEY_COINGECKO_DEMO');
const apiKeyPro = this.configurationService.get('API_KEY_COINGECKO_PRO');
this.apiUrl = 'https://api.coingecko.com/api/v3';
if (apiKeyDemo) {
this.headers['x-cg-demo-api-key'] = apiKeyDemo;
}
if (apiKeyPro) {
this.apiUrl = 'https://pro-api.coingecko.com/api/v3';
this.headers['x-cg-pro-api-key'] = apiKeyPro;
}
}
public canHandle(symbol: string) { public canHandle(symbol: string) {
return true; return true;
@ -49,7 +64,8 @@ export class CoinGeckoService implements DataProviderInterface {
abortController.abort(); abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT')); }, this.configurationService.get('REQUEST_TIMEOUT'));
const { name } = await got(`${this.URL}/coins/${aSymbol}`, { const { name } = await got(`${this.apiUrl}/coins/${aSymbol}`, {
headers: this.headers,
// @ts-ignore // @ts-ignore
signal: abortController.signal signal: abortController.signal
}).json<any>(); }).json<any>();
@ -101,11 +117,12 @@ export class CoinGeckoService implements DataProviderInterface {
const { prices } = await got( const { prices } = await got(
`${ `${
this.URL this.apiUrl
}/coins/${aSymbol}/market_chart/range?vs_currency=${DEFAULT_CURRENCY.toLowerCase()}&from=${getUnixTime( }/coins/${aSymbol}/market_chart/range?vs_currency=${DEFAULT_CURRENCY.toLowerCase()}&from=${getUnixTime(
from from
)}&to=${getUnixTime(to)}`, )}&to=${getUnixTime(to)}`,
{ {
headers: this.headers,
// @ts-ignore // @ts-ignore
signal: abortController.signal signal: abortController.signal
} }
@ -163,10 +180,11 @@ export class CoinGeckoService implements DataProviderInterface {
}, requestTimeout); }, requestTimeout);
const quotes = await got( const quotes = await got(
`${this.URL}/simple/price?ids=${symbols.join( `${this.apiUrl}/simple/price?ids=${symbols.join(
',' ','
)}&vs_currencies=${DEFAULT_CURRENCY.toLowerCase()}`, )}&vs_currencies=${DEFAULT_CURRENCY.toLowerCase()}`,
{ {
headers: this.headers,
// @ts-ignore // @ts-ignore
signal: abortController.signal signal: abortController.signal
} }
@ -216,7 +234,8 @@ export class CoinGeckoService implements DataProviderInterface {
abortController.abort(); abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT')); }, this.configurationService.get('REQUEST_TIMEOUT'));
const { coins } = await got(`${this.URL}/search?query=${query}`, { const { coins } = await got(`${this.apiUrl}/search?query=${query}`, {
headers: this.headers,
// @ts-ignore // @ts-ignore
signal: abortController.signal signal: abortController.signal
}).json<any>(); }).json<any>();

@ -3,6 +3,8 @@ import { CleanedEnvAccessors } from 'envalid';
export interface Environment extends CleanedEnvAccessors { export interface Environment extends CleanedEnvAccessors {
ACCESS_TOKEN_SALT: string; ACCESS_TOKEN_SALT: string;
ALPHA_VANTAGE_API_KEY: string; ALPHA_VANTAGE_API_KEY: string;
API_KEY_COINGECKO_DEMO: string;
API_KEY_COINGECKO_PRO: string;
BETTER_UPTIME_API_KEY: string; BETTER_UPTIME_API_KEY: string;
CACHE_QUOTES_TTL: number; CACHE_QUOTES_TTL: number;
CACHE_TTL: number; CACHE_TTL: number;

Loading…
Cancel
Save