mirror of https://github.com/ghostfolio/ghostfolio
5 changed files with 164 additions and 6 deletions
@ -0,0 +1,132 @@ |
|||
import { environment } from '@ghostfolio/api/environments/environment'; |
|||
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; |
|||
import { |
|||
DataProviderInterface, |
|||
GetDividendsParams, |
|||
GetHistoricalParams, |
|||
GetQuotesParams, |
|||
GetSearchParams |
|||
} from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; |
|||
import { |
|||
IDataProviderHistoricalResponse, |
|||
IDataProviderResponse |
|||
} from '@ghostfolio/api/services/interfaces/interfaces'; |
|||
import { PropertyService } from '@ghostfolio/api/services/property/property.service'; |
|||
import { PROPERTY_API_KEY_GHOSTFOLIO } from '@ghostfolio/common/config'; |
|||
import { |
|||
DataProviderInfo, |
|||
LookupResponse |
|||
} from '@ghostfolio/common/interfaces'; |
|||
|
|||
import { Injectable, Logger } from '@nestjs/common'; |
|||
import { DataSource, SymbolProfile } from '@prisma/client'; |
|||
import got from 'got'; |
|||
|
|||
@Injectable() |
|||
export class GhostfolioService implements DataProviderInterface { |
|||
private apiKey: string; |
|||
private readonly URL = environment.production |
|||
? 'https://ghostfol.io/api' |
|||
: `${this.configurationService.get('ROOT_URL')}/api`; |
|||
|
|||
public constructor( |
|||
private readonly configurationService: ConfigurationService, |
|||
private readonly propertyService: PropertyService |
|||
) { |
|||
void this.initialize(); |
|||
} |
|||
|
|||
public async initialize() { |
|||
this.apiKey = (await this.propertyService.getByKey( |
|||
PROPERTY_API_KEY_GHOSTFOLIO |
|||
)) as string; |
|||
} |
|||
|
|||
public canHandle() { |
|||
return true; |
|||
} |
|||
|
|||
public async getAssetProfile({ |
|||
symbol |
|||
}: { |
|||
symbol: string; |
|||
}): Promise<Partial<SymbolProfile>> { |
|||
return { |
|||
symbol, |
|||
dataSource: this.getName() |
|||
}; |
|||
} |
|||
|
|||
public getDataProviderInfo(): DataProviderInfo { |
|||
return { |
|||
isPremium: true, |
|||
name: 'Ghostfolio', |
|||
url: 'https://ghostfo.io' |
|||
}; |
|||
} |
|||
|
|||
public async getDividends({}: GetDividendsParams) { |
|||
return {}; |
|||
} |
|||
|
|||
public async getHistorical({}: GetHistoricalParams): Promise<{ |
|||
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; |
|||
}> { |
|||
// TODO
|
|||
return {}; |
|||
} |
|||
|
|||
public getMaxNumberOfSymbolsPerRequest() { |
|||
return 20; |
|||
} |
|||
|
|||
public getName(): DataSource { |
|||
return DataSource.GHOSTFOLIO; |
|||
} |
|||
|
|||
public async getQuotes({}: GetQuotesParams): Promise<{ |
|||
[symbol: string]: IDataProviderResponse; |
|||
}> { |
|||
// TODO
|
|||
return {}; |
|||
} |
|||
|
|||
public getTestSymbol() { |
|||
return 'AAPL.US'; |
|||
} |
|||
|
|||
public async search({ query }: GetSearchParams): Promise<LookupResponse> { |
|||
let searchResult: LookupResponse = { items: [] }; |
|||
|
|||
try { |
|||
const abortController = new AbortController(); |
|||
|
|||
setTimeout(() => { |
|||
abortController.abort(); |
|||
}, this.configurationService.get('REQUEST_TIMEOUT')); |
|||
|
|||
searchResult = await got( |
|||
`${this.URL}/v1/data-providers/ghostfolio/lookup?query=${query}`, |
|||
{ |
|||
headers: { |
|||
Authorization: `Bearer ${this.apiKey}` |
|||
}, |
|||
// @ts-ignore
|
|||
signal: abortController.signal |
|||
} |
|||
).json<any>(); |
|||
} catch (error) { |
|||
let message = error; |
|||
|
|||
if (error?.code === 'ABORT_ERR') { |
|||
message = `RequestError: The operation to search for ${query} was aborted because the request to the data provider took more than ${this.configurationService.get( |
|||
'REQUEST_TIMEOUT' |
|||
)}ms`;
|
|||
} |
|||
|
|||
Logger.error(message, 'GhostfolioService'); |
|||
} |
|||
|
|||
return searchResult; |
|||
} |
|||
} |
Loading…
Reference in new issue