From 16ef4d27eeb9b030af064ee182c511f13f4bb1c1 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 23 Nov 2024 21:21:44 +0100 Subject: [PATCH] Set up Ghostfolio data provider --- .../ghostfolio/ghostfolio.service.ts | 64 +++++++++++++++---- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts b/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts index c07f3db61..fcd15907a 100644 --- a/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts +++ b/apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts @@ -15,7 +15,8 @@ import { PropertyService } from '@ghostfolio/api/services/property/property.serv import { PROPERTY_API_KEY_GHOSTFOLIO } from '@ghostfolio/common/config'; import { DataProviderInfo, - LookupResponse + LookupResponse, + QuotesResponse } from '@ghostfolio/common/interfaces'; import { Injectable, Logger } from '@nestjs/common'; @@ -84,11 +85,48 @@ export class GhostfolioService implements DataProviderInterface { return DataSource.GHOSTFOLIO; } - public async getQuotes({}: GetQuotesParams): Promise<{ + public async getQuotes({ + requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), + symbols + }: GetQuotesParams): Promise<{ [symbol: string]: IDataProviderResponse; }> { - // TODO - return {}; + let response: { [symbol: string]: IDataProviderResponse } = {}; + + if (symbols.length <= 0) { + return response; + } + + try { + const abortController = new AbortController(); + + setTimeout(() => { + abortController.abort(); + }, requestTimeout); + + const { quotes } = await got( + `${this.URL}/v1/data-providers/ghostfolio/quotes?symbols=${symbols.join(',')}`, + { + headers: this.getRequestHeaders(), + // @ts-ignore + signal: abortController.signal + } + ).json(); + + response = quotes; + } catch (error) { + let message = error; + + if (error?.code === 'ABORT_ERR') { + message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; + } + + Logger.error(message, 'GhostfolioService'); + } + + return response; } public getTestSymbol() { @@ -108,20 +146,18 @@ export class GhostfolioService implements DataProviderInterface { searchResult = await got( `${this.URL}/v1/data-providers/ghostfolio/lookup?query=${query}`, { - headers: { - Authorization: `Bearer ${this.apiKey}` - }, + headers: this.getRequestHeaders(), // @ts-ignore signal: abortController.signal } - ).json(); + ).json(); } 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`; + 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') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'GhostfolioService'); @@ -129,4 +165,10 @@ export class GhostfolioService implements DataProviderInterface { return searchResult; } + + private getRequestHeaders() { + return { + Authorization: `Bearer ${this.apiKey}` + }; + } }