Skip to content

Commit

Permalink
feature: use ITH_GLOBAL_* if available, introduce poc for Simple Cach…
Browse files Browse the repository at this point in the history
…ing Module
  • Loading branch information
newbreedofgeek committed Nov 11, 2024
1 parent f449a5b commit b214ba7
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 15 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@itheum/sdk-mx-data-nft",
"version": "3.8.0-alpha.2",
"version": "3.8.0-alpha.3",
"description": "SDK for Itheum's Data NFT Technology on MultiversX Blockchain",
"main": "out/index.js",
"types": "out/index.d.js",
Expand Down
47 changes: 47 additions & 0 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -600,3 +600,50 @@ export function checkStatus(response: Response) {
throw new ErrFetch(response.status, response.statusText);
}
}

/*
Simple Caching Module helps throttle frequently used calls to RPC that fetch data
this helps speed up the client side app and also reduces calls to the RPC
we allow consumer to set a custom TTL in MS for how long data is stored in cache
*/
const sessionCache: Record<any, any> = {};

export function getDataFromClientSessionCache(cacheKey: string) {
const cacheObject = sessionCache[cacheKey];

if (!cacheObject) {
console.log('getDataFromClientSessionCache: not found');
return false;
} else {
// did it expire? is so, delete it from the cache
if (cacheObject.addedOn - Date.now() > cacheObject.expireAfter) {
console.log('getDataFromClientSessionCache: expired');
delete sessionCache[cacheKey]; // remove it from cache as its expired
return false;
} else {
console.log('getDataFromClientSessionCache: available');
return cacheObject.payload;
}
}
}

export function setDataToClientSessionCache(
cacheKey: string,
jsonData: any,
ttlInMs?: number
) {
const howManyMsToCacheFor = ttlInMs || 120000; // 120000 is 2 min default TTL

sessionCache[cacheKey] = {
payload: jsonData,
addedOn: Date.now(),
expireAfter: howManyMsToCacheFor
};

console.log(
'setDataToClientSessionCache: cached for ms ',
howManyMsToCacheFor
);

return true;
}
44 changes: 38 additions & 6 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/*
Host apps like the data dex or explorer, when the MVX dappProvider in initialized (very early in the page)
it calls a utility method that loads the best RPC to use in the ITH_GLOBAL_MVX_RPC_API_SESSION global variable
so we aim to use that if available so this SDK uses the same RPC as the host to talk to the MVX chain
*/
declare const window: {
ITH_GLOBAL_MVX_RPC_API_SESSION: string;
} & Window;

export enum EnvironmentsEnum {
devnet = 'devnet',
testnet = 'testnet',
Expand All @@ -9,19 +18,31 @@ export interface Config {
networkProvider: string;
}

// note that in all rpc check methods below we check if window === 'undefined' as this is need for tests to pass
const devnetNetworkConfig: Config = {
chainID: 'D',
networkProvider: 'https://devnet-api.multiversx.com'
networkProvider:
typeof window === 'undefined'
? 'https://devnet-api.multiversx.com'
: window.ITH_GLOBAL_MVX_RPC_API_SESSION ||
'https://devnet-api.multiversx.com'
};

const mainnetNetworkConfig: Config = {
chainID: '1',
networkProvider: 'https://api.multiversx.com'
networkProvider:
typeof window === 'undefined'
? 'https://api.multiversx.com'
: window.ITH_GLOBAL_MVX_RPC_API_SESSION || 'https://api.multiversx.com'
};

const testnetNetworkConfig: Config = {
chainID: 'T',
networkProvider: 'https://testnet-api.multiversx.com'
networkProvider:
typeof window === 'undefined'
? 'https://testnet-api.multiversx.com'
: window.ITH_GLOBAL_MVX_RPC_API_SESSION ||
'https://testnet-api.multiversx.com'
};

export const itheumTokenIdentifier: { [key in EnvironmentsEnum]: string } = {
Expand Down Expand Up @@ -64,9 +85,20 @@ export const livelinessStakeContractAddress: {
};

export const apiConfiguration: { [key in EnvironmentsEnum]: string } = {
devnet: 'https://devnet-api.multiversx.com',
mainnet: 'https://api.multiversx.com',
testnet: 'https://testnet-api.multiversx.com'
devnet:
typeof window === 'undefined'
? 'https://devnet-api.multiversx.com'
: window.ITH_GLOBAL_MVX_RPC_API_SESSION ||
'https://devnet-api.multiversx.com',
mainnet:
typeof window === 'undefined'
? 'https://api.multiversx.com'
: window.ITH_GLOBAL_MVX_RPC_API_SESSION || 'https://api.multiversx.com',
testnet:
typeof window === 'undefined'
? 'https://testnet-api.multiversx.com'
: window.ITH_GLOBAL_MVX_RPC_API_SESSION ||
'https://testnet-api.multiversx.com'
};

export const networkConfiguration: { [key in EnvironmentsEnum]: Config } = {
Expand Down
35 changes: 27 additions & 8 deletions src/datanft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {
numberToPaddedHex,
overrideMarshalUrl,
parseDataNft,
validateSpecificParamsViewData
validateSpecificParamsViewData,
getDataFromClientSessionCache,
setDataToClientSessionCache
} from './common/utils';
import {
Config,
Expand Down Expand Up @@ -163,15 +165,32 @@ export class DataNft implements DataNftType {
if (identifiers.length > MAX_ITEMS) {
throw new ErrTooManyItems();
}
const response = await fetch(
`${this.apiConfiguration}/nfts?identifiers=${identifiers.join(
','
)}&withSupply=true&size=${identifiers.length}`
);

checkStatus(response);
// lets not make the call if not needed
if (identifiers.length === 0) {
return [];
}

const fetchUrl = `${
this.apiConfiguration
}/nfts?identifiers=${identifiers.join(',')}&withSupply=true&size=${
identifiers.length
}`;

// check if its in session cache
let jsonDataPayload = null;
const getFromSessionCache = getDataFromClientSessionCache(fetchUrl);

if (!getFromSessionCache) {
const response = await fetch(fetchUrl);
checkStatus(response);
jsonDataPayload = await response.json();
setDataToClientSessionCache(fetchUrl, jsonDataPayload, 5 * 60 * 1000);
} else {
jsonDataPayload = getFromSessionCache;
}

const data: NftType[] = await response.json();
const data: NftType[] = jsonDataPayload;

try {
const dataNfts = data.map((value) => parseDataNft(value));
Expand Down
4 changes: 4 additions & 0 deletions tests/environment.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
declare const window: {
ITH_GLOBAL_MVX_RPC_API_SESSION: string;
} & Window;

import { ApiNetworkProvider } from '@multiversx/sdk-core/out';
import { DataNftMarket, SftMinter } from '../src/index';

Expand Down

0 comments on commit b214ba7

Please sign in to comment.