@am92/securities-utility
Version:
A utility package for securities applications
153 lines (152 loc) • 6.54 kB
JavaScript
import { setCacheResponse, getCacheResponse, setCacheContentHash, checkIfContentHashIsSame, getContentHashFromHeaders } from '../Utils/Cache/UtilCache';
import { INDEXES_CREATED } from '../Constants/EVENTS';
import { SEC_SEGMENTS } from '../Constants/SECURITY_MASTER';
import { derivativesIndexHandler, isinCodeIndexHandler, scriptIdIndexHandler, searchStringIndexHandler } from './indexes';
import { STORE_KEYS } from '../Constants/STORE_KEYS';
/**
* Fetches the headers from the provided security master URL without retrieving the entire file.
*
* This function uses a 'HEAD' request to fetch only the headers of the file. It helps in
* checking if the file has been modified or not by comparing the content hash from the headers.
*
* @param secMasterURL The URL of the security master data.
* @returns The headers of the response, or null if an error occurs.
*/
export const fetchOnlyHeaders = async (secMasterURL) => {
try {
const response = await fetch(secMasterURL, {
method: 'HEAD',
mode: 'no-cors',
headers: {
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
Expires: '0'
}
});
if (response) {
return response?.headers;
}
}
catch (err) {
console.log(err, 'header errors');
}
return null;
};
/**
* Fetches the security master data from the provided URL, checks the file's content hash,
* and updates the cache if the file content has changed.
*
* If the content hash is the same and the response is already cached, it returns the cached response.
* Otherwise, it fetches the new data, updates the cache, creates indexes, and sends the data back to the main thread.
*
* @param secMasterURL The URL to fetch the security master data.
* @param config Configuration options for indexing and handling the data.
* @returns Void
*/
export const fetchSecurityMaster = async (secMasterURL, config) => {
const headers = await fetchOnlyHeaders(secMasterURL);
const contentHash = getContentHashFromHeaders(headers);
// NOTE: variable to check if the file content is updated or same
const isContentHashSame = await checkIfContentHashIsSame(contentHash);
// check if response is cached
const cacheResponse = await getCacheResponse(secMasterURL);
if (isContentHashSame && cacheResponse) {
generateIndexesAndPostMessage(cacheResponse, config);
return;
}
const response = await fetch(secMasterURL, {
method: 'GET'
});
const { headers: currentHeaders = {} } = response;
const currentContentHash = getContentHashFromHeaders(currentHeaders);
const SEC_MASTER_ARRAY = await response.json();
setCacheResponse(secMasterURL, SEC_MASTER_ARRAY);
setCacheContentHash(currentContentHash);
generateIndexesAndPostMessage(SEC_MASTER_ARRAY, config);
};
/**
* Generates indexes for the security master data and posts the data to the main thread.
*
* @param masterData The security master data to index.
* @param config Configuration options for indexing.
*/
function generateIndexesAndPostMessage(masterData, config) {
const indexes = createIndexes(masterData, config);
const dataToPost = {
[STORE_KEYS.MASTER_DATA]: masterData,
[STORE_KEYS.SCRIPT_ID_INDEX]: indexes.scriptIdIndex,
[STORE_KEYS.DERIVATIVES_INDEX]: indexes.derivativesIndex,
[STORE_KEYS.ISIN_CODE_INDEX]: indexes.isinCodeIndex,
[STORE_KEYS.SEARCH_STRING_INDEX]: indexes.searchStringIndex
};
self.postMessage({
action: INDEXES_CREATED,
data: dataToPost
});
}
/**
* Creates indexes for different segments of the security master data based on configuration options.
*
* This function creates various indexes like `scriptIdIndex`, `isinCodeIndex`, `derivativesIndex`,
* and optionally `searchStringIndex`, depending on the `requireSearchModule` flag in the configuration.
* It loops through the segments of the security master data, processes each item, and adds it to the corresponding index.
*
* @param masterData The security master data to index.
* @param options Configuration options for index creation.
* @returns An object containing the created indexes.
*/
const createIndexes = (masterData, options) => {
let indexHandlers = [
scriptIdIndexHandler(),
isinCodeIndexHandler(),
derivativesIndexHandler()
];
if (options && options.requireSearchModule) {
indexHandlers.push(searchStringIndexHandler());
}
for (const SEC_SEGMENT of SEC_SEGMENTS) {
const secMasterSegmentKey = SEC_SEGMENT.name;
const segmentData = masterData[secMasterSegmentKey];
if (!segmentData)
continue;
if (SEC_SEGMENT.type === 'FLAT_EQUITY' ||
SEC_SEGMENT.type === 'FLAT_UNDERLYING') {
const totalData = segmentData.length;
for (let itemIndex = 0; itemIndex < totalData; itemIndex++) {
const itemData = segmentData[itemIndex];
indexHandlers.map(indexHandler => indexHandler?.addRow(secMasterSegmentKey, itemIndex, itemData));
}
}
else {
const totalData = segmentData.length;
for (let itemIndex = 0; itemIndex < totalData; itemIndex++) {
const itemData = segmentData[itemIndex];
const derivativeItems = itemData[3];
const derivativeItemsLength = derivativeItems.length;
for (let derivativeItemIndex = 0; derivativeItemIndex < derivativeItemsLength; derivativeItemIndex++) {
const derivativeItem = derivativeItems[derivativeItemIndex];
indexHandlers.map(indexHandler => indexHandler?.addRow(secMasterSegmentKey, itemIndex, itemData, derivativeItemIndex, derivativeItem));
}
}
}
}
const indexesArray = indexHandlers.map(indexHandler => indexHandler?.getIndex());
const scriptIdIndex = indexesArray[0];
const isinCodeIndex = indexesArray[1];
const derivativesIndex = indexesArray[2];
const searchStringIndex = indexesArray[3];
const indexes = {
scriptIdIndex,
isinCodeIndex,
derivativesIndex,
searchStringIndex
};
return indexes;
};
self.onmessage = (event) => {
const { action, data } = event.data;
if (action === 'INIT') {
const { config, secMasterURL } = data;
fetchSecurityMaster(secMasterURL, config);
}
};