diff --git a/src/common/config/config-loader.service.spec.ts b/src/common/config/config-loader.service.spec.ts index 729caf92..9f33789c 100644 --- a/src/common/config/config-loader.service.spec.ts +++ b/src/common/config/config-loader.service.spec.ts @@ -14,6 +14,25 @@ const DEFAULTS = { RPC_URL: 'some-rpc-url', RABBITMQ_URL: 'some-rabbit-url', RABBITMQ_LOGIN: 'some-rabbit-login', + KEYS_API_URL: 'keys-api', +}; + +const extractError = async ( + fn: Promise, +): Promise<[ValidationError[], T]> => { + try { + return [[], await fn]; + } catch (error: any) { + return [error as ValidationError[], undefined as unknown as T]; + } +}; + +const toHaveProblemWithRecords = ( + recordsKeys: string[], + errors: ValidationError[], +) => { + const errorKeys = errors.map((error) => error.property); + expect(recordsKeys.sort()).toEqual(errorKeys.sort()); }; describe('ConfigLoaderService base spec', () => { @@ -106,6 +125,96 @@ describe('ConfigLoaderService base spec', () => { }); }); + describe('kapi url config', () => { + test('all invariants are empty', async () => { + const prepConfig = plainToClass(InMemoryConfiguration, { + RABBITMQ_PASSCODE: 'some-rabbit-passcode', + ...DEFAULTS, + KEYS_API_URL: undefined, + }); + const [validationErrors] = await extractError( + configLoaderService.loadSecrets(prepConfig), + ); + + toHaveProblemWithRecords( + ['KEYS_API_URL', 'KEYS_API_PORT', 'KEYS_API_HOST'], + validationErrors, + ); + }); + + test('KEYS_API_URL is set and the rest is default', async () => { + const KEYS_API_URL = 'kapi-url'; + const KEYS_API_HOST = ''; + const KEYS_API_PORT = 0; + const prepConfig = plainToClass(InMemoryConfiguration, { + RABBITMQ_PASSCODE: 'some-rabbit-passcode', + ...DEFAULTS, + KEYS_API_URL, + }); + const [validationErrors, result] = await extractError( + configLoaderService.loadSecrets(prepConfig), + ); + expect(validationErrors).toHaveLength(0); + expect(result.KEYS_API_URL).toBe(KEYS_API_URL); + expect(result.KEYS_API_HOST).toBe(KEYS_API_HOST); + expect(result.KEYS_API_PORT).toBe(KEYS_API_PORT); + }); + + test('KEYS_API_URL is empty and the rest is set', async () => { + const KEYS_API_URL = undefined; + const KEYS_API_HOST = 'kapi-host'; + const KEYS_API_PORT = 2222; + const prepConfig = plainToClass(InMemoryConfiguration, { + RABBITMQ_PASSCODE: 'some-rabbit-passcode', + ...DEFAULTS, + KEYS_API_URL, + KEYS_API_HOST, + KEYS_API_PORT, + }); + const [validationErrors, result] = await extractError( + configLoaderService.loadSecrets(prepConfig), + ); + expect(validationErrors).toHaveLength(0); + expect(result.KEYS_API_URL).toBe(KEYS_API_URL); + expect(result.KEYS_API_HOST).toBe(KEYS_API_HOST); + expect(result.KEYS_API_PORT).toBe(KEYS_API_PORT); + }); + + test('KEYS_API_URL and KEYS_API_PORT are empty and the KEYS_API_HOST is set', async () => { + const KEYS_API_URL = undefined; + const KEYS_API_HOST = 'kapi-host'; + const KEYS_API_PORT = 0; + const prepConfig = plainToClass(InMemoryConfiguration, { + RABBITMQ_PASSCODE: 'some-rabbit-passcode', + ...DEFAULTS, + KEYS_API_URL, + KEYS_API_HOST, + KEYS_API_PORT, + }); + const [validationErrors] = await extractError( + configLoaderService.loadSecrets(prepConfig), + ); + toHaveProblemWithRecords(['KEYS_API_PORT'], validationErrors); + }); + + test('KEYS_API_URL and KEYS_API_HOST are empty and the KEYS_API_PORT is set', async () => { + const KEYS_API_URL = undefined; + const KEYS_API_HOST = ''; + const KEYS_API_PORT = 2222; + const prepConfig = plainToClass(InMemoryConfiguration, { + RABBITMQ_PASSCODE: 'some-rabbit-passcode', + ...DEFAULTS, + KEYS_API_URL, + KEYS_API_HOST, + KEYS_API_PORT, + }); + const [validationErrors] = await extractError( + configLoaderService.loadSecrets(prepConfig), + ); + toHaveProblemWithRecords(['KEYS_API_HOST'], validationErrors); + }); + }); + describe('wallet', () => { let configLoaderService: ConfigLoaderService; const DEFAULTS_WITH_RABBIT = { diff --git a/src/common/config/configuration.ts b/src/common/config/configuration.ts index 349a6f51..5539d95a 100644 --- a/src/common/config/configuration.ts +++ b/src/common/config/configuration.ts @@ -31,6 +31,7 @@ export interface Configuration { REGISTRY_KEYS_QUERY_CONCURRENCY: number; KEYS_API_PORT: number; KEYS_API_HOST: string; + KEYS_API_URL: string; LOCATOR_DEVNET_ADDRESS: string; WALLET_MIN_BALANCE: ethers.BigNumber; WALLET_CRITICAL_BALANCE: ethers.BigNumber; diff --git a/src/common/config/in-memory-configuration.ts b/src/common/config/in-memory-configuration.ts index e17dc2bf..b69809cd 100644 --- a/src/common/config/in-memory-configuration.ts +++ b/src/common/config/in-memory-configuration.ts @@ -128,15 +128,24 @@ export class InMemoryConfiguration implements Configuration { @Transform(({ value }) => parseInt(value, 10), { toClassOnly: true }) REGISTRY_KEYS_QUERY_CONCURRENCY = 5; + @ValidateIf((conf) => !conf.KEYS_API_URL) @IsNotEmpty() @IsNumber() @Min(1) @Transform(({ value }) => parseInt(value, 10), { toClassOnly: true }) - KEYS_API_PORT = 3001; + KEYS_API_PORT = 0; - @IsOptional() + @ValidateIf((conf) => !conf.KEYS_API_URL) + @IsNotEmpty() + @IsString() + KEYS_API_HOST = ''; + + @ValidateIf((conf) => { + return !conf.KEYS_API_PORT && !conf.KEYS_API_HOST; + }) + @IsNotEmpty() @IsString() - KEYS_API_HOST = 'http://localhost'; + KEYS_API_URL = ''; @IsOptional() @IsString() diff --git a/src/keys-api/keys-api.service.ts b/src/keys-api/keys-api.service.ts index e79931ad..e035cbca 100644 --- a/src/keys-api/keys-api.service.ts +++ b/src/keys-api/keys-api.service.ts @@ -16,6 +16,13 @@ export class KeysApiService { protected readonly fetchService: FetchService, ) {} + private getBaseUrl() { + const baseUrl = + this.config.KEYS_API_URL || + `${this.config.KEYS_API_HOST}:${this.config.KEYS_API_PORT}`; + return baseUrl; + } + protected async fetch(url: string, requestInit?: RequestInit) { const controller = new AbortController(); const { signal } = controller; @@ -24,8 +31,7 @@ export class KeysApiService { controller.abort(); }, FETCH_REQUEST_TIMEOUT); - const baseUrl = `${this.config.KEYS_API_HOST}:${this.config.KEYS_API_PORT}`; - + const baseUrl = this.getBaseUrl(); try { const res: Response = await this.fetchService.fetchJson( `${baseUrl}${url}`, @@ -34,9 +40,10 @@ export class KeysApiService { ...requestInit, }, ); + clearTimeout(timer); return res; - } catch (error) { + } catch (error: any) { clearTimeout(timer); throw error; }