diff --git a/package-lock.json b/package-lock.json index 92751501c..4e3d08bfb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "class-validator": "^0.14.0", "config": "^3.3.7", "cookie-parser": "^1.4.6", + "dataloader": "^2.2.2", "express": "^4.18.1", "graphql": "^16.5.0", "graphql-redis-subscriptions": "^2.4.2", @@ -7626,6 +7627,11 @@ "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==" }, + "node_modules/dataloader": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", + "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==" + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -22430,6 +22436,11 @@ "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==" }, + "dataloader": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", + "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==" + }, "date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", diff --git a/package.json b/package.json index 6438e1306..111481e5b 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "class-validator": "^0.14.0", "config": "^3.3.7", "cookie-parser": "^1.4.6", + "dataloader": "^2.2.2", "express": "^4.18.1", "graphql": "^16.5.0", "graphql-redis-subscriptions": "^2.4.2", diff --git a/src/modules/farm/base-module/farm.resolver.ts b/src/modules/farm/base-module/farm.resolver.ts index 25a75b12d..a1b78894f 100644 --- a/src/modules/farm/base-module/farm.resolver.ts +++ b/src/modules/farm/base-module/farm.resolver.ts @@ -1,13 +1,17 @@ import { Resolver, ResolveField, Parent } from '@nestjs/graphql'; import { BaseFarmModel } from '../models/farm.model'; import { PairModel } from '../../pair/models/pair.model'; -import { LockedAssetModel } from '../../locked-asset-factory/models/locked-asset.model'; import { EsdtToken } from '../../tokens/models/esdtToken.model'; import { NftCollection } from '../../tokens/models/nftCollection.model'; import { Address } from '@multiversx/sdk-core'; import { FarmAbiService } from './services/farm.abi.service'; import { FarmServiceBase } from './services/farm.base.service'; import { FarmComputeService } from './services/farm.compute.service'; +import { Inject } from '@nestjs/common'; +import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; +import { Logger } from 'winston'; +import { FarmAbiLoader } from './services/farm.abi.loader'; +import { FarmComputeLoader } from './services/farm.compute.loader'; @Resolver(() => BaseFarmModel) export class FarmResolver { @@ -15,103 +19,122 @@ export class FarmResolver { protected readonly farmAbi: FarmAbiService, protected readonly farmService: FarmServiceBase, protected readonly farmCompute: FarmComputeService, + protected readonly farmAbiLoader: FarmAbiLoader, + protected readonly farmComputeLoader: FarmComputeLoader, + @Inject(WINSTON_MODULE_PROVIDER) protected readonly logger: Logger, ) {} @ResolveField() async farmedToken(@Parent() parent: BaseFarmModel): Promise { - return this.farmService.getFarmedToken(parent.address); + return this.farmAbiLoader.farmedTokenLoader.load(parent.address); } @ResolveField() async farmToken(@Parent() parent: BaseFarmModel): Promise { - return this.farmService.getFarmToken(parent.address); + return this.farmAbiLoader.farmTokenLoader.load(parent.address); } @ResolveField() async farmingToken(@Parent() parent: BaseFarmModel): Promise { - return this.farmService.getFarmingToken(parent.address); + return this.farmAbiLoader.farmingTokenLoader.load(parent.address); } @ResolveField() async produceRewardsEnabled( @Parent() parent: BaseFarmModel, ): Promise { - return this.farmAbi.produceRewardsEnabled(parent.address); + return this.farmAbiLoader.produceRewardsEnabledLoader.load( + parent.address, + ); } @ResolveField() async perBlockRewards(@Parent() parent: BaseFarmModel): Promise { - return this.farmAbi.rewardsPerBlock(parent.address); + return this.farmAbiLoader.perBlockRewardsLoader.load(parent.address); } @ResolveField() async farmTokenSupply(@Parent() parent: BaseFarmModel): Promise { - return this.farmAbi.farmTokenSupply(parent.address); + return this.farmAbiLoader.farmTokenSupplyLoader.load(parent.address); } @ResolveField() async farmedTokenPriceUSD( @Parent() parent: BaseFarmModel, ): Promise { - return this.farmCompute.farmedTokenPriceUSD(parent.address); + return this.farmComputeLoader.farmedTokenPriceUSDLoader.load( + parent.address, + ); } @ResolveField() async farmTokenPriceUSD(@Parent() parent: BaseFarmModel): Promise { - return this.farmCompute.farmTokenPriceUSD(parent.address); + return this.farmComputeLoader.farmTokenPriceUSDLoader.load( + parent.address, + ); } @ResolveField() async farmingTokenPriceUSD( @Parent() parent: BaseFarmModel, ): Promise { - return this.farmCompute.farmingTokenPriceUSD(parent.address); + return this.farmComputeLoader.farmingTokenPriceUSDLoader.load( + parent.address, + ); } @ResolveField() async penaltyPercent(@Parent() parent: BaseFarmModel): Promise { - return this.farmAbi.penaltyPercent(parent.address); + return this.farmAbiLoader.penaltyPercentLoader.load(parent.address); } @ResolveField() async minimumFarmingEpochs( @Parent() parent: BaseFarmModel, ): Promise { - return this.farmAbi.minimumFarmingEpochs(parent.address); + return this.farmAbiLoader.minimumFarmingEpochsLoader.load( + parent.address, + ); } @ResolveField() async rewardPerShare(@Parent() parent: BaseFarmModel): Promise { - return this.farmAbi.rewardPerShare(parent.address); + return this.farmAbiLoader.rewardPerShareLoader.load(parent.address); } @ResolveField() async rewardReserve(@Parent() parent: BaseFarmModel): Promise { - return this.farmAbi.rewardReserve(parent.address); + return this.farmAbiLoader.rewardReserveLoader.load(parent.address); } @ResolveField() async lastRewardBlockNonce( @Parent() parent: BaseFarmModel, ): Promise { - return this.farmAbi.lastRewardBlockNonce(parent.address); + return this.farmAbiLoader.lastRewardBlockNonceLoader.load( + parent.address, + ); } @ResolveField() async divisionSafetyConstant( @Parent() parent: BaseFarmModel, ): Promise { - return this.farmAbi.divisionSafetyConstant(parent.address); + return this.farmAbiLoader.divisionSafetyConstantLoader.load( + parent.address, + ); } @ResolveField() async totalValueLockedUSD(parent: BaseFarmModel): Promise { - return this.farmCompute.farmLockedValueUSD(parent.address); + return this.farmComputeLoader.farmLockedValueUSDLoader.load( + parent.address, + ); } @ResolveField() async state(@Parent() parent: BaseFarmModel): Promise { - return this.farmAbi.state(parent.address); + return this.farmAbiLoader.stateLoader.load(parent.address); } @ResolveField() diff --git a/src/modules/farm/base-module/services/farm.abi.loader.ts b/src/modules/farm/base-module/services/farm.abi.loader.ts new file mode 100644 index 000000000..93b81955a --- /dev/null +++ b/src/modules/farm/base-module/services/farm.abi.loader.ts @@ -0,0 +1,149 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmServiceBase } from './farm.base.service'; +import DataLoader from 'dataloader'; +import { EsdtToken } from 'src/modules/tokens/models/esdtToken.model'; +import { NftCollection } from 'src/modules/tokens/models/nftCollection.model'; +import { FarmAbiService } from './farm.abi.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; +import { getAllKeys } from 'src/utils/get.many.utils'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmAbiLoader { + constructor( + protected readonly farmAbi: FarmAbiService, + protected readonly farmService: FarmServiceBase, + protected readonly cacheService: CacheService, + ) {} + + public readonly farmedTokenLoader = new DataLoader( + async (addresses: string[]) => { + return await this.farmService.getAllFarmedTokens(addresses); + }, + ); + + public readonly farmTokenLoader = new DataLoader( + async (addresses: string[]) => { + return await this.farmService.getAllFarmTokens(addresses); + }, + ); + + public readonly farmingTokenLoader = new DataLoader( + async (addresses: string[]) => { + return await this.farmService.getAllFarmingTokens(addresses); + }, + ); + + public readonly produceRewardsEnabledLoader = new DataLoader< + string, + boolean + >(async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.produceRewardsEnabled', + this.farmAbi.produceRewardsEnabled.bind(this.farmAbi), + ); + }); + + public readonly perBlockRewardsLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.perBlockRewards', + this.farmAbi.rewardsPerBlock.bind(this.farmAbi), + ); + }, + ); + + public readonly farmTokenSupplyLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.farmTokenSupply', + this.farmAbi.farmTokenSupply.bind(this.farmAbi), + ); + }, + ); + + public readonly penaltyPercentLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.penaltyPercent', + this.farmAbi.penaltyPercent.bind(this.farmAbi), + ); + }, + ); + + public readonly minimumFarmingEpochsLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.minimumFarmingEpochs', + this.farmAbi.minimumFarmingEpochs.bind(this.farmAbi), + ); + }, + ); + + public readonly rewardPerShareLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.rewardPerShare', + this.farmAbi.rewardPerShare.bind(this.farmAbi), + ); + }, + ); + + public readonly rewardReserveLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.rewardReserve', + this.farmAbi.rewardReserve.bind(this.farmAbi), + ); + }, + ); + + public readonly lastRewardBlockNonceLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.lastRewardBlockNonce', + this.farmAbi.lastRewardBlockNonce.bind(this.farmAbi), + ); + }, + ); + + public readonly divisionSafetyConstantLoader = new DataLoader< + string, + string + >(async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.divisionSafetyConstant', + this.farmAbi.divisionSafetyConstant.bind(this.farmAbi), + ); + }); + + public readonly stateLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.state', + this.farmAbi.state.bind(this.farmAbi), + ); + }, + ); +} diff --git a/src/modules/farm/base-module/services/farm.abi.service.ts b/src/modules/farm/base-module/services/farm.abi.service.ts index 9e87c3a6c..846380ad5 100644 --- a/src/modules/farm/base-module/services/farm.abi.service.ts +++ b/src/modules/farm/base-module/services/farm.abi.service.ts @@ -14,6 +14,7 @@ import { CacheTtlInfo } from 'src/services/caching/cache.ttl.info'; import { Constants } from '@multiversx/sdk-nestjs-common'; import { MXApiService } from 'src/services/multiversx-communication/mx.api.service'; import { IFarmAbiService } from './interfaces'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; export class FarmAbiService extends GenericAbiService @@ -23,6 +24,7 @@ export class FarmAbiService protected readonly mxProxy: MXProxyService, protected readonly gatewayService: MXGatewayService, protected readonly apiService: MXApiService, + protected readonly cacheService: CacheService, ) { super(mxProxy); } diff --git a/src/modules/farm/base-module/services/farm.base.service.ts b/src/modules/farm/base-module/services/farm.base.service.ts index 12d695594..e9faf590a 100644 --- a/src/modules/farm/base-module/services/farm.base.service.ts +++ b/src/modules/farm/base-module/services/farm.base.service.ts @@ -16,6 +16,7 @@ import { EsdtToken } from 'src/modules/tokens/models/esdtToken.model'; import { NftCollection } from 'src/modules/tokens/models/nftCollection.model'; import { Inject, forwardRef } from '@nestjs/common'; import { TokenService } from 'src/modules/tokens/services/token.service'; +import { getAllKeys } from 'src/utils/get.many.utils'; export abstract class FarmServiceBase { constructor( @@ -32,16 +33,46 @@ export abstract class FarmServiceBase { return this.tokenService.tokenMetadata(farmedTokenID); } + async getAllFarmedTokens(farmAddresses: string[]): Promise { + const farmedTokenIDs = await getAllKeys( + this.cachingService, + farmAddresses, + 'farm.farmedTokenID', + this.farmAbi.farmedTokenID.bind(this.farmAbi), + ); + return this.tokenService.getAllTokensMetadata(farmedTokenIDs); + } + async getFarmToken(farmAddress: string): Promise { const farmTokenID = await this.farmAbi.farmTokenID(farmAddress); return this.tokenService.getNftCollectionMetadata(farmTokenID); } + async getAllFarmTokens(farmAddresses: string[]): Promise { + const farmTokenIDs = await getAllKeys( + this.cachingService, + farmAddresses, + 'farm.farmTokenID', + this.farmAbi.farmTokenID.bind(this.farmAbi), + ); + return this.tokenService.getAllNftsCollectionMetadata(farmTokenIDs); + } + async getFarmingToken(farmAddress: string): Promise { const farmingTokenID = await this.farmAbi.farmingTokenID(farmAddress); return this.tokenService.tokenMetadata(farmingTokenID); } + async getAllFarmingTokens(farmAddresses: string[]): Promise { + const farmingTokenIDs = await getAllKeys( + this.cachingService, + farmAddresses, + 'farm.farmingTokenID', + this.farmAbi.farmingTokenID.bind(this.farmAbi), + ); + return this.tokenService.getAllTokensMetadata(farmingTokenIDs); + } + protected async getRemainingFarmingEpochs( farmAddress: string, enteringEpoch: number, diff --git a/src/modules/farm/base-module/services/farm.compute.loader.ts b/src/modules/farm/base-module/services/farm.compute.loader.ts new file mode 100644 index 000000000..8cce1139a --- /dev/null +++ b/src/modules/farm/base-module/services/farm.compute.loader.ts @@ -0,0 +1,59 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmComputeService } from './farm.compute.service'; +import DataLoader from 'dataloader'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; +import { getAllKeys } from 'src/utils/get.many.utils'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmComputeLoader { + constructor( + protected readonly farmCompute: FarmComputeService, + protected readonly cacheService: CacheService, + ) {} + + public readonly farmLockedValueUSDLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.farmLockedValueUSD', + this.farmCompute.farmLockedValueUSD.bind(this.farmCompute), + ); + }, + ); + + public readonly farmedTokenPriceUSDLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.farmedTokenPriceUSD', + this.farmCompute.farmedTokenPriceUSD.bind(this.farmCompute), + ); + }, + ); + + public readonly farmTokenPriceUSDLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.farmTokenPriceUSD', + this.farmCompute.farmTokenPriceUSD.bind(this.farmCompute), + ); + }, + ); + + public readonly farmingTokenPriceUSDLoader = new DataLoader( + async (addresses: string[]) => { + return await getAllKeys( + this.cacheService, + addresses, + 'farm.farmingTokenPriceUSD', + this.farmCompute.farmingTokenPriceUSD.bind(this.farmCompute), + ); + }, + ); +} diff --git a/src/modules/farm/base-module/services/farm.compute.service.ts b/src/modules/farm/base-module/services/farm.compute.service.ts index aedf6600b..718d61b4b 100644 --- a/src/modules/farm/base-module/services/farm.compute.service.ts +++ b/src/modules/farm/base-module/services/farm.compute.service.ts @@ -13,6 +13,7 @@ import { CacheTtlInfo } from 'src/services/caching/cache.ttl.info'; import { FarmServiceBase } from './farm.base.service'; import { Inject, forwardRef } from '@nestjs/common'; import { IFarmComputeService } from './interfaces'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; export abstract class FarmComputeService implements IFarmComputeService { constructor( @@ -23,6 +24,7 @@ export abstract class FarmComputeService implements IFarmComputeService { protected readonly pairCompute: PairComputeService, protected readonly contextGetter: ContextGetterService, protected readonly tokenCompute: TokenComputeService, + protected readonly cacheService: CacheService, ) {} @ErrorLoggerAsync({ diff --git a/src/modules/farm/custom/farm.custom.module.ts b/src/modules/farm/custom/farm.custom.module.ts index b99d552c4..1c5d581b4 100644 --- a/src/modules/farm/custom/farm.custom.module.ts +++ b/src/modules/farm/custom/farm.custom.module.ts @@ -8,6 +8,8 @@ import { FarmCustomTransactionService } from './services/farm.custom.transaction import { FarmCustomComputeService } from './services/farm.custom.compute.service'; import { ContextModule } from 'src/services/context/context.module'; import { FarmCustomService } from './services/farm.custom.service'; +import { FarmCustomAbiLoader } from './services/farm.custom.abi.loader'; +import { FarmCustomComputeLoader } from './services/farm.custom.compute.loader'; @Module({ imports: [ @@ -17,6 +19,8 @@ import { FarmCustomService } from './services/farm.custom.service'; forwardRef(() => PairModule), ], providers: [ + FarmCustomAbiLoader, + FarmCustomComputeLoader, FarmCustomService, FarmCustomAbiService, FarmCustomComputeService, diff --git a/src/modules/farm/custom/farm.custom.resolver.ts b/src/modules/farm/custom/farm.custom.resolver.ts index 6bac8de37..08fc4d58b 100644 --- a/src/modules/farm/custom/farm.custom.resolver.ts +++ b/src/modules/farm/custom/farm.custom.resolver.ts @@ -4,6 +4,11 @@ import { FarmCustomModel } from '../models/farm.custom.model'; import { FarmCustomAbiService } from './services/farm.custom.abi.service'; import { FarmCustomComputeService } from './services/farm.custom.compute.service'; import { FarmCustomService } from './services/farm.custom.service'; +import { Inject } from '@nestjs/common'; +import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; +import { Logger } from 'winston'; +import { FarmCustomAbiLoader } from './services/farm.custom.abi.loader'; +import { FarmCustomComputeLoader } from './services/farm.custom.compute.loader'; @Resolver(() => FarmCustomModel) export class FarmCustomResolver extends FarmResolver { @@ -11,8 +16,18 @@ export class FarmCustomResolver extends FarmResolver { protected readonly farmAbi: FarmCustomAbiService, protected readonly farmService: FarmCustomService, protected readonly farmCompute: FarmCustomComputeService, + protected readonly farmAbiLoader: FarmCustomAbiLoader, + protected readonly farmComputeLoader: FarmCustomComputeLoader, + @Inject(WINSTON_MODULE_PROVIDER) protected readonly logger: Logger, ) { - super(farmAbi, farmService, farmCompute); + super( + farmAbi, + farmService, + farmCompute, + farmAbiLoader, + farmComputeLoader, + logger, + ); } @ResolveField() diff --git a/src/modules/farm/custom/services/farm.custom.abi.loader.ts b/src/modules/farm/custom/services/farm.custom.abi.loader.ts new file mode 100644 index 000000000..3c0b09b5d --- /dev/null +++ b/src/modules/farm/custom/services/farm.custom.abi.loader.ts @@ -0,0 +1,18 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmAbiLoader } from '../../base-module/services/farm.abi.loader'; +import { FarmCustomService } from './farm.custom.service'; +import { FarmCustomAbiService } from './farm.custom.abi.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmCustomAbiLoader extends FarmAbiLoader { + constructor( + protected readonly farmAbi: FarmCustomAbiService, + protected readonly farmService: FarmCustomService, + protected readonly cacheService: CacheService, + ) { + super(farmAbi, farmService, cacheService); + } +} diff --git a/src/modules/farm/custom/services/farm.custom.compute.loader.ts b/src/modules/farm/custom/services/farm.custom.compute.loader.ts new file mode 100644 index 000000000..13bbca222 --- /dev/null +++ b/src/modules/farm/custom/services/farm.custom.compute.loader.ts @@ -0,0 +1,16 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmComputeLoader } from '../../base-module/services/farm.compute.loader'; +import { FarmCustomComputeService } from './farm.custom.compute.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmCustomComputeLoader extends FarmComputeLoader { + constructor( + protected readonly farmCompute: FarmCustomComputeService, + protected readonly cacheService: CacheService, + ) { + super(farmCompute, cacheService); + } +} diff --git a/src/modules/farm/custom/services/farm.custom.compute.service.ts b/src/modules/farm/custom/services/farm.custom.compute.service.ts index 70f2fdba3..06e0fa1f7 100644 --- a/src/modules/farm/custom/services/farm.custom.compute.service.ts +++ b/src/modules/farm/custom/services/farm.custom.compute.service.ts @@ -6,6 +6,7 @@ import { PairComputeService } from 'src/modules/pair/services/pair.compute.servi import { ContextGetterService } from 'src/services/context/context.getter.service'; import { TokenComputeService } from 'src/modules/tokens/services/token.compute.service'; import { FarmCustomService } from './farm.custom.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; @Injectable() export class FarmCustomComputeService extends FarmComputeService { @@ -17,6 +18,7 @@ export class FarmCustomComputeService extends FarmComputeService { protected readonly pairCompute: PairComputeService, protected readonly contextGetter: ContextGetterService, protected readonly tokenCompute: TokenComputeService, + protected readonly cacheService: CacheService, ) { super( farmAbi, @@ -25,6 +27,7 @@ export class FarmCustomComputeService extends FarmComputeService { pairCompute, contextGetter, tokenCompute, + cacheService, ); } } diff --git a/src/modules/farm/v1.2/farm.v1.2.module.ts b/src/modules/farm/v1.2/farm.v1.2.module.ts index 3ee74b8d6..667410340 100644 --- a/src/modules/farm/v1.2/farm.v1.2.module.ts +++ b/src/modules/farm/v1.2/farm.v1.2.module.ts @@ -10,6 +10,8 @@ import { FarmTransactionServiceV1_2 } from './services/farm.v1.2.transaction.ser import { FarmServiceV1_2 } from './services/farm.v1.2.service'; import { FarmSetterService } from '../base-module/services/farm.setter.service'; import { FarmSetterServiceV1_2 } from './services/farm.v1.2.setter.service'; +import { FarmAbiLoaderV1_2 } from './services/farm.v1.2.abi.loader'; +import { FarmComputeLoaderV1_2 } from './services/farm.v1.2.compute.loader'; @Module({ imports: [ @@ -19,6 +21,8 @@ import { FarmSetterServiceV1_2 } from './services/farm.v1.2.setter.service'; forwardRef(() => PairModule), ], providers: [ + FarmAbiLoaderV1_2, + FarmComputeLoaderV1_2, FarmServiceV1_2, FarmAbiServiceV1_2, { diff --git a/src/modules/farm/v1.2/farm.v1.2.resolver.ts b/src/modules/farm/v1.2/farm.v1.2.resolver.ts index f2008a921..2cd68336d 100644 --- a/src/modules/farm/v1.2/farm.v1.2.resolver.ts +++ b/src/modules/farm/v1.2/farm.v1.2.resolver.ts @@ -6,6 +6,11 @@ import { FarmAbiServiceV1_2 } from './services/farm.v1.2.abi.service'; import { FarmServiceV1_2 } from './services/farm.v1.2.service'; import { FarmComputeServiceV1_2 } from './services/farm.v1.2.compute.service'; import { LockedAssetModel } from 'src/modules/locked-asset-factory/models/locked-asset.model'; +import { Logger } from 'winston'; +import { Inject } from '@nestjs/common'; +import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; +import { FarmAbiLoaderV1_2 } from './services/farm.v1.2.abi.loader'; +import { FarmComputeLoaderV1_2 } from './services/farm.v1.2.compute.loader'; @Resolver(() => FarmModelV1_2) export class FarmResolverV1_2 extends FarmResolver { @@ -13,8 +18,18 @@ export class FarmResolverV1_2 extends FarmResolver { protected readonly farmAbi: FarmAbiServiceV1_2, protected readonly farmService: FarmServiceV1_2, protected readonly farmCompute: FarmComputeServiceV1_2, + protected readonly farmAbiLoader: FarmAbiLoaderV1_2, + protected readonly farmComputeLoader: FarmComputeLoaderV1_2, + @Inject(WINSTON_MODULE_PROVIDER) protected readonly logger: Logger, ) { - super(farmAbi, farmService, farmCompute); + super( + farmAbi, + farmService, + farmCompute, + farmAbiLoader, + farmComputeLoader, + logger, + ); } @ResolveField() diff --git a/src/modules/farm/v1.2/services/farm.v1.2.abi.loader.ts b/src/modules/farm/v1.2/services/farm.v1.2.abi.loader.ts new file mode 100644 index 000000000..ba3606895 --- /dev/null +++ b/src/modules/farm/v1.2/services/farm.v1.2.abi.loader.ts @@ -0,0 +1,18 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmAbiLoader } from '../../base-module/services/farm.abi.loader'; +import { FarmServiceV1_2 } from './farm.v1.2.service'; +import { FarmAbiServiceV1_2 } from './farm.v1.2.abi.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmAbiLoaderV1_2 extends FarmAbiLoader { + constructor( + protected readonly farmAbi: FarmAbiServiceV1_2, + protected readonly farmService: FarmServiceV1_2, + protected readonly cacheService: CacheService, + ) { + super(farmAbi, farmService, cacheService); + } +} diff --git a/src/modules/farm/v1.2/services/farm.v1.2.abi.service.ts b/src/modules/farm/v1.2/services/farm.v1.2.abi.service.ts index 529091ad6..99fe3956d 100644 --- a/src/modules/farm/v1.2/services/farm.v1.2.abi.service.ts +++ b/src/modules/farm/v1.2/services/farm.v1.2.abi.service.ts @@ -10,6 +10,7 @@ import { GetOrSetCache } from 'src/helpers/decorators/caching.decorator'; import { CacheTtlInfo } from 'src/services/caching/cache.ttl.info'; import { Constants } from '@multiversx/sdk-nestjs-common'; import { IFarmAbiServiceV1_2 } from './interfaces'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; @Injectable() export class FarmAbiServiceV1_2 @@ -20,8 +21,9 @@ export class FarmAbiServiceV1_2 protected readonly mxProxy: MXProxyService, protected readonly gatewayService: MXGatewayService, protected readonly mxApi: MXApiService, + protected readonly cacheService: CacheService, ) { - super(mxProxy, gatewayService, mxApi); + super(mxProxy, gatewayService, mxApi, cacheService); } @ErrorLoggerAsync({ diff --git a/src/modules/farm/v1.2/services/farm.v1.2.compute.loader.ts b/src/modules/farm/v1.2/services/farm.v1.2.compute.loader.ts new file mode 100644 index 000000000..b20a41177 --- /dev/null +++ b/src/modules/farm/v1.2/services/farm.v1.2.compute.loader.ts @@ -0,0 +1,16 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmComputeLoader } from '../../base-module/services/farm.compute.loader'; +import { FarmComputeServiceV1_2 } from './farm.v1.2.compute.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmComputeLoaderV1_2 extends FarmComputeLoader { + constructor( + protected readonly farmCompute: FarmComputeServiceV1_2, + protected readonly cacheService: CacheService, + ) { + super(farmCompute, cacheService); + } +} diff --git a/src/modules/farm/v1.2/services/farm.v1.2.compute.service.ts b/src/modules/farm/v1.2/services/farm.v1.2.compute.service.ts index 52a4e4441..6424185e2 100644 --- a/src/modules/farm/v1.2/services/farm.v1.2.compute.service.ts +++ b/src/modules/farm/v1.2/services/farm.v1.2.compute.service.ts @@ -13,6 +13,7 @@ import { ErrorLoggerAsync } from '@multiversx/sdk-nestjs-common'; import { GetOrSetCache } from 'src/helpers/decorators/caching.decorator'; import { CacheTtlInfo } from 'src/services/caching/cache.ttl.info'; import { IFarmComputeServiceV1_2 } from './interfaces'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; @Injectable() export class FarmComputeServiceV1_2 @@ -27,6 +28,7 @@ export class FarmComputeServiceV1_2 protected readonly pairCompute: PairComputeService, protected readonly contextGetter: ContextGetterService, protected readonly tokenCompute: TokenComputeService, + protected readonly cacheService: CacheService, ) { super( farmAbi, @@ -35,6 +37,7 @@ export class FarmComputeServiceV1_2 pairCompute, contextGetter, tokenCompute, + cacheService, ); } diff --git a/src/modules/farm/v1.3/farm.v1.3.module.ts b/src/modules/farm/v1.3/farm.v1.3.module.ts index c3cc110a1..f95acc3ed 100644 --- a/src/modules/farm/v1.3/farm.v1.3.module.ts +++ b/src/modules/farm/v1.3/farm.v1.3.module.ts @@ -10,6 +10,8 @@ import { FarmTransactionServiceV1_3 } from './services/farm.v1.3.transaction.ser import { FarmServiceV1_3 } from './services/farm.v1.3.service'; import { FarmSetterService } from '../base-module/services/farm.setter.service'; import { FarmSetterServiceV1_3 } from './services/farm.v1.3.setter.service'; +import { FarmAbiLoaderV1_3 } from './services/farm.v1.3.abi.loader'; +import { FarmComputeLoaderV1_3 } from './services/farm.v1.3.compute.loader'; @Module({ imports: [ @@ -19,6 +21,8 @@ import { FarmSetterServiceV1_3 } from './services/farm.v1.3.setter.service'; forwardRef(() => PairModule), ], providers: [ + FarmAbiLoaderV1_3, + FarmComputeLoaderV1_3, FarmServiceV1_3, FarmAbiServiceV1_3, { diff --git a/src/modules/farm/v1.3/farm.v1.3.resolver.ts b/src/modules/farm/v1.3/farm.v1.3.resolver.ts index 8f6b1a25d..739a756e9 100644 --- a/src/modules/farm/v1.3/farm.v1.3.resolver.ts +++ b/src/modules/farm/v1.3/farm.v1.3.resolver.ts @@ -5,6 +5,11 @@ import { FarmServiceV1_3 } from './services/farm.v1.3.service'; import { FarmComputeServiceV1_3 } from './services/farm.v1.3.compute.service'; import { FarmAbiServiceV1_3 } from './services/farm.v1.3.abi.service'; import { LockedAssetModel } from 'src/modules/locked-asset-factory/models/locked-asset.model'; +import { Logger } from 'winston'; +import { Inject } from '@nestjs/common'; +import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; +import { FarmAbiLoaderV1_3 } from './services/farm.v1.3.abi.loader'; +import { FarmComputeLoaderV1_3 } from './services/farm.v1.3.compute.loader'; @Resolver(FarmModelV1_3) export class FarmResolverV1_3 extends FarmResolver { @@ -12,8 +17,18 @@ export class FarmResolverV1_3 extends FarmResolver { protected readonly farmAbi: FarmAbiServiceV1_3, protected readonly farmService: FarmServiceV1_3, protected readonly farmCompute: FarmComputeServiceV1_3, + protected readonly farmAbiLoader: FarmAbiLoaderV1_3, + protected readonly farmComputeLoader: FarmComputeLoaderV1_3, + @Inject(WINSTON_MODULE_PROVIDER) protected readonly logger: Logger, ) { - super(farmAbi, farmService, farmCompute); + super( + farmAbi, + farmService, + farmCompute, + farmAbiLoader, + farmComputeLoader, + logger, + ); } @ResolveField() diff --git a/src/modules/farm/v1.3/services/farm.v1.3.abi.loader.ts b/src/modules/farm/v1.3/services/farm.v1.3.abi.loader.ts new file mode 100644 index 000000000..79037bbee --- /dev/null +++ b/src/modules/farm/v1.3/services/farm.v1.3.abi.loader.ts @@ -0,0 +1,18 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmAbiLoader } from '../../base-module/services/farm.abi.loader'; +import { FarmServiceV1_3 } from './farm.v1.3.service'; +import { FarmAbiServiceV1_3 } from './farm.v1.3.abi.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmAbiLoaderV1_3 extends FarmAbiLoader { + constructor( + protected readonly farmAbi: FarmAbiServiceV1_3, + protected readonly farmService: FarmServiceV1_3, + protected readonly cacheService: CacheService, + ) { + super(farmAbi, farmService, cacheService); + } +} diff --git a/src/modules/farm/v1.3/services/farm.v1.3.abi.service.ts b/src/modules/farm/v1.3/services/farm.v1.3.abi.service.ts index fcaf4cc59..673d47755 100644 --- a/src/modules/farm/v1.3/services/farm.v1.3.abi.service.ts +++ b/src/modules/farm/v1.3/services/farm.v1.3.abi.service.ts @@ -10,6 +10,7 @@ import { GetOrSetCache } from 'src/helpers/decorators/caching.decorator'; import { Constants } from '@multiversx/sdk-nestjs-common'; import { IFarmAbiServiceV1_3 } from './interfaces'; import { CacheTtlInfo } from 'src/services/caching/cache.ttl.info'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; @Injectable() export class FarmAbiServiceV1_3 @@ -20,8 +21,9 @@ export class FarmAbiServiceV1_3 protected readonly mxProxy: MXProxyService, protected readonly gatewayService: MXGatewayService, protected readonly mxApi: MXApiService, + protected readonly cacheService: CacheService, ) { - super(mxProxy, gatewayService, mxApi); + super(mxProxy, gatewayService, mxApi, cacheService); } @ErrorLoggerAsync({ diff --git a/src/modules/farm/v1.3/services/farm.v1.3.compute.loader.ts b/src/modules/farm/v1.3/services/farm.v1.3.compute.loader.ts new file mode 100644 index 000000000..1676282a2 --- /dev/null +++ b/src/modules/farm/v1.3/services/farm.v1.3.compute.loader.ts @@ -0,0 +1,16 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmComputeLoader } from '../../base-module/services/farm.compute.loader'; +import { FarmComputeServiceV1_3 } from './farm.v1.3.compute.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmComputeLoaderV1_3 extends FarmComputeLoader { + constructor( + protected readonly farmCompute: FarmComputeServiceV1_3, + protected readonly cacheService: CacheService, + ) { + super(farmCompute, cacheService); + } +} diff --git a/src/modules/farm/v1.3/services/farm.v1.3.compute.service.ts b/src/modules/farm/v1.3/services/farm.v1.3.compute.service.ts index 3c1b5d046..1e13487fe 100644 --- a/src/modules/farm/v1.3/services/farm.v1.3.compute.service.ts +++ b/src/modules/farm/v1.3/services/farm.v1.3.compute.service.ts @@ -13,6 +13,7 @@ import { ErrorLoggerAsync } from '@multiversx/sdk-nestjs-common'; import { GetOrSetCache } from 'src/helpers/decorators/caching.decorator'; import { Constants } from '@multiversx/sdk-nestjs-common'; import { IFarmComputeServiceV1_3 } from './interfaces'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; @Injectable() export class FarmComputeServiceV1_3 @@ -27,6 +28,7 @@ export class FarmComputeServiceV1_3 protected readonly pairCompute: PairComputeService, protected readonly contextGetter: ContextGetterService, protected readonly tokenCompute: TokenComputeService, + protected readonly cacheService: CacheService, ) { super( farmAbi, @@ -35,6 +37,7 @@ export class FarmComputeServiceV1_3 pairCompute, contextGetter, tokenCompute, + cacheService, ); } diff --git a/src/modules/farm/v2/farm.v2.module.ts b/src/modules/farm/v2/farm.v2.module.ts index af164ee71..48e182872 100644 --- a/src/modules/farm/v2/farm.v2.module.ts +++ b/src/modules/farm/v2/farm.v2.module.ts @@ -13,6 +13,8 @@ import { WeekTimekeepingModule } from '../../../submodules/week-timekeeping/week import { WeeklyRewardsSplittingModule } from '../../../submodules/weekly-rewards-splitting/weekly-rewards-splitting.module'; import { EnergyModule } from '../../energy/energy.module'; import { FarmTransactionResolverV2 } from './farm.v2.transaction.resolver'; +import { FarmAbiLoaderV2 } from './services/farm.v2.abi.loader'; +import { FarmComputeLoaderV2 } from './services/farm.v2.compute.loader'; @Module({ imports: [ @@ -25,6 +27,8 @@ import { FarmTransactionResolverV2 } from './farm.v2.transaction.resolver'; forwardRef(() => WeeklyRewardsSplittingModule), ], providers: [ + FarmAbiLoaderV2, + FarmComputeLoaderV2, FarmServiceV2, FarmAbiServiceV2, FarmSetterServiceV2, diff --git a/src/modules/farm/v2/farm.v2.resolver.ts b/src/modules/farm/v2/farm.v2.resolver.ts index 7f8625610..78dce345c 100644 --- a/src/modules/farm/v2/farm.v2.resolver.ts +++ b/src/modules/farm/v2/farm.v2.resolver.ts @@ -9,7 +9,7 @@ import { constantsConfig } from '../../../config'; import { WeekTimekeepingAbiService } from 'src/submodules/week-timekeeping/services/week-timekeeping.abi.service'; import { WeeklyRewardsSplittingAbiService } from 'src/submodules/weekly-rewards-splitting/services/weekly-rewards-splitting.abi.service'; import { FarmAbiServiceV2 } from './services/farm.v2.abi.service'; -import { UseGuards } from '@nestjs/common'; +import { Inject, UseGuards } from '@nestjs/common'; import { JwtOrNativeAuthGuard } from 'src/modules/auth/jwt.or.native.auth.guard'; import { UserAuthResult } from 'src/modules/auth/user.auth.result'; import { AuthUser } from 'src/modules/auth/auth.user'; @@ -21,6 +21,10 @@ import { } from '../models/farm.model'; import { GraphQLError } from 'graphql'; import { ApolloServerErrorCode } from '@apollo/server/errors'; +import { Logger } from 'winston'; +import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; +import { FarmAbiLoaderV2 } from './services/farm.v2.abi.loader'; +import { FarmComputeLoaderV2 } from './services/farm.v2.compute.loader'; @Resolver(() => FarmModelV2) export class FarmResolverV2 extends FarmResolver { @@ -28,10 +32,20 @@ export class FarmResolverV2 extends FarmResolver { protected readonly farmAbi: FarmAbiServiceV2, protected readonly farmService: FarmServiceV2, protected readonly farmCompute: FarmComputeServiceV2, + protected readonly farmAbiLoader: FarmAbiLoaderV2, + protected readonly farmComputeLoader: FarmComputeLoaderV2, + @Inject(WINSTON_MODULE_PROVIDER) protected readonly logger: Logger, private readonly weekTimekeepingAbi: WeekTimekeepingAbiService, private readonly weeklyRewardsSplittingAbi: WeeklyRewardsSplittingAbiService, ) { - super(farmAbi, farmService, farmCompute); + super( + farmAbi, + farmService, + farmCompute, + farmAbiLoader, + farmComputeLoader, + logger, + ); } @ResolveField() diff --git a/src/modules/farm/v2/services/farm.v2.abi.loader.ts b/src/modules/farm/v2/services/farm.v2.abi.loader.ts new file mode 100644 index 000000000..73a897fc3 --- /dev/null +++ b/src/modules/farm/v2/services/farm.v2.abi.loader.ts @@ -0,0 +1,18 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmAbiLoader } from '../../base-module/services/farm.abi.loader'; +import { FarmServiceV2 } from './farm.v2.service'; +import { FarmAbiServiceV2 } from './farm.v2.abi.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmAbiLoaderV2 extends FarmAbiLoader { + constructor( + protected readonly farmAbi: FarmAbiServiceV2, + protected readonly farmService: FarmServiceV2, + protected readonly cacheService: CacheService, + ) { + super(farmAbi, farmService, cacheService); + } +} diff --git a/src/modules/farm/v2/services/farm.v2.abi.service.ts b/src/modules/farm/v2/services/farm.v2.abi.service.ts index e7f49130f..ad35b541f 100644 --- a/src/modules/farm/v2/services/farm.v2.abi.service.ts +++ b/src/modules/farm/v2/services/farm.v2.abi.service.ts @@ -29,6 +29,7 @@ import { ErrorLoggerAsync } from '@multiversx/sdk-nestjs-common'; import { GetOrSetCache } from 'src/helpers/decorators/caching.decorator'; import { CacheTtlInfo } from 'src/services/caching/cache.ttl.info'; import { IFarmAbiServiceV2 } from './interfaces'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; @Injectable() export class FarmAbiServiceV2 @@ -39,8 +40,9 @@ export class FarmAbiServiceV2 protected readonly mxProxy: MXProxyService, protected readonly gatewayService: MXGatewayService, protected readonly mxApi: MXApiService, + protected readonly cacheService: CacheService, ) { - super(mxProxy, gatewayService, mxApi); + super(mxProxy, gatewayService, mxApi, cacheService); } async getLastErrorMessageRaw(farmAddress: string): Promise { diff --git a/src/modules/farm/v2/services/farm.v2.compute.loader.ts b/src/modules/farm/v2/services/farm.v2.compute.loader.ts new file mode 100644 index 000000000..ce72e395b --- /dev/null +++ b/src/modules/farm/v2/services/farm.v2.compute.loader.ts @@ -0,0 +1,16 @@ +import { Injectable, Scope } from '@nestjs/common'; +import { FarmComputeLoader } from '../../base-module/services/farm.compute.loader'; +import { FarmComputeServiceV2 } from './farm.v2.compute.service'; +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +@Injectable({ + scope: Scope.REQUEST, +}) +export class FarmComputeLoaderV2 extends FarmComputeLoader { + constructor( + protected readonly farmCompute: FarmComputeServiceV2, + protected readonly cacheService: CacheService, + ) { + super(farmCompute, cacheService); + } +} diff --git a/src/modules/farm/v2/services/farm.v2.compute.service.ts b/src/modules/farm/v2/services/farm.v2.compute.service.ts index cbdffa1f3..70558ed5c 100644 --- a/src/modules/farm/v2/services/farm.v2.compute.service.ts +++ b/src/modules/farm/v2/services/farm.v2.compute.service.ts @@ -35,10 +35,10 @@ export class FarmComputeServiceV2 protected readonly pairCompute: PairComputeService, protected readonly contextGetter: ContextGetterService, protected readonly tokenCompute: TokenComputeService, + protected readonly cachingService: CacheService, private readonly weekTimekeepingCompute: WeekTimekeepingComputeService, private readonly weeklyRewardsSplittingAbi: WeeklyRewardsSplittingAbiService, private readonly weeklyRewardsSplittingCompute: WeeklyRewardsSplittingComputeService, - private readonly cachingService: CacheService, ) { super( farmAbi, @@ -47,6 +47,7 @@ export class FarmComputeServiceV2 pairCompute, contextGetter, tokenCompute, + cachingService, ); } diff --git a/src/modules/tokens/services/token.service.ts b/src/modules/tokens/services/token.service.ts index 407a3d172..6020f318a 100644 --- a/src/modules/tokens/services/token.service.ts +++ b/src/modules/tokens/services/token.service.ts @@ -122,45 +122,73 @@ export class TokenService { localTtl: CacheTtlInfo.Token.localTtl, }) async tokenMetadata(tokenID: string): Promise { - return await this.tokenMetadataRaw(tokenID); + return this.tokenMetadataRaw(tokenID); + } + + async getAllTokensMetadata(tokenIDs: string[]): Promise { + const keys = tokenIDs.map( + (tokenID) => `token.tokenMetadata.${tokenID}`, + ); + const values = await this.cachingService.getMany(keys); + + const missingIndexes: number[] = []; + values.forEach((value, index) => { + if (!value) { + missingIndexes.push(index); + } + }); + + for (const missingIndex of missingIndexes) { + const token = await this.tokenMetadata(tokenIDs[missingIndex]); + values[missingIndex] = token; + } + return values; } async tokenMetadataRaw(tokenID: string): Promise { - return await this.apiService.getToken(tokenID); + return this.apiService.getToken(tokenID); } + @ErrorLoggerAsync({ + logArgs: true, + }) + @GetOrSetCache({ + baseKey: 'token', + remoteTtl: CacheTtlInfo.Token.remoteTtl, + localTtl: CacheTtlInfo.Token.localTtl, + }) async getNftCollectionMetadata(collection: string): Promise { - if (collection === undefined) { - return undefined; - } - const cacheKey = `token.${collection}`; - const cachedToken = await this.cachingService.get( - cacheKey, + return this.getNftCollectionMetadataRaw(collection); + } + + async getAllNftsCollectionMetadata( + collections: string[], + ): Promise { + const keys = collections.map( + (collection) => `token.getNftCollectionMetadata.${collection}`, ); - if (cachedToken && cachedToken !== undefined) { - await this.cachingService.set( - cacheKey, - cachedToken, - CacheTtlInfo.Token.remoteTtl, - CacheTtlInfo.Token.localTtl, - ); - return cachedToken; - } + const values = await this.cachingService.getMany(keys); - const token = await this.apiService.getNftCollection(collection); + const missingIndexes: number[] = []; + values.forEach((value, index) => { + if (!value) { + missingIndexes.push(index); + } + }); - if (token !== undefined) { - await this.cachingService.set( - cacheKey, - token, - CacheTtlInfo.Token.remoteTtl, - CacheTtlInfo.Token.localTtl, + for (const missingIndex of missingIndexes) { + const token = await this.getNftCollectionMetadata( + collections[missingIndex], ); - - return token; + values[missingIndex] = token; } + return values; + } - return undefined; + async getNftCollectionMetadataRaw( + collection: string, + ): Promise { + return this.apiService.getNftCollection(collection); } async getUniqueTokenIDs(activePool: boolean): Promise { diff --git a/src/services/caching/cache.ttl.info.ts b/src/services/caching/cache.ttl.info.ts index 6f541c57e..e9e8a01f5 100644 --- a/src/services/caching/cache.ttl.info.ts +++ b/src/services/caching/cache.ttl.info.ts @@ -36,7 +36,7 @@ export class CacheTtlInfo { static Price: CacheTtlInfo = new CacheTtlInfo( Constants.oneMinute(), - Constants.oneSecond() * 30, + Constants.oneSecond() * 45, ); static Analytics: CacheTtlInfo = new CacheTtlInfo( diff --git a/src/utils/get.many.utils.ts b/src/utils/get.many.utils.ts new file mode 100644 index 000000000..4dab13185 --- /dev/null +++ b/src/utils/get.many.utils.ts @@ -0,0 +1,56 @@ +import { CacheService } from '@multiversx/sdk-nestjs-cache'; + +async function getMany( + cacheService: CacheService, + keys: string[], +): Promise<(T | undefined)[]> { + const values = await cacheService.getManyLocal(keys); + + const missingIndexes: number[] = []; + values.forEach((value, index) => { + if (!value) { + missingIndexes.push(index); + } + }); + + const missingKeys: string[] = []; + for (const missingIndex of missingIndexes) { + missingKeys.push(keys[missingIndex]); + } + + if (missingKeys.length === 0) { + return values; + } + + const remoteValues = await cacheService.getManyRemote(missingKeys); + + for (const [index, missingIndex] of missingIndexes.entries()) { + const remoteValue = remoteValues[index]; + values[missingIndex] = remoteValue ? remoteValue : undefined; + } + + return values; +} + +export async function getAllKeys( + cacheService: CacheService, + tokenIDs: string[], + baseKey: string, + getterMethod: (address: string) => Promise, +): Promise { + const keys = tokenIDs.map((tokenID) => `${baseKey}.${tokenID}`); + const values = await getMany(cacheService, keys); + + const missingIndexes: number[] = []; + values.forEach((value, index) => { + if (!value) { + missingIndexes.push(index); + } + }); + + for (const missingIndex of missingIndexes) { + const tokenID = await getterMethod(tokenIDs[missingIndex]); + values[missingIndex] = tokenID; + } + return values; +}