262 lines
8.0 KiB
TypeScript
262 lines
8.0 KiB
TypeScript
|
import {IndicatorType, Stakeholder} from "../../../monitor/entities/stakeholder";
|
||
|
import axios from "axios";
|
||
|
import {IndicatorUtils} from "../indicator-utils";
|
||
|
import {Composer} from "../../../utils/email/composer";
|
||
|
import {properties} from "src/environments/environment";
|
||
|
|
||
|
|
||
|
export interface CacheItem {
|
||
|
reportId: string,
|
||
|
type: IndicatorType,
|
||
|
url: string
|
||
|
}
|
||
|
|
||
|
export class Report {
|
||
|
creator: string;
|
||
|
name: string;
|
||
|
success: number;
|
||
|
errors: {
|
||
|
url: string,
|
||
|
status: number
|
||
|
}[];
|
||
|
total: number;
|
||
|
completed: boolean;
|
||
|
percentage: number
|
||
|
|
||
|
constructor(total: number, name: string, creator: string) {
|
||
|
this.creator = creator;
|
||
|
this.name = name;
|
||
|
this.success = 0;
|
||
|
this.errors = [];
|
||
|
this.total = total;
|
||
|
this.completed = false;
|
||
|
}
|
||
|
|
||
|
setPercentage() {
|
||
|
this.percentage = Math.floor((this.success + this.errors.length) / this.total * 100);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export class CacheIndicators {
|
||
|
|
||
|
private static BATCH_SIZE = 10;
|
||
|
|
||
|
private reports: Map<string, Report> = new Map<string, Report>();
|
||
|
private queue: CacheItem[] = [];
|
||
|
private process: Promise<void>;
|
||
|
private isFinished: boolean = true;
|
||
|
|
||
|
stakeholderToCacheItems(stakeholder: Stakeholder) {
|
||
|
let cacheItems: CacheItem[] = [];
|
||
|
let indicatorUtils = new IndicatorUtils();
|
||
|
stakeholder.topics.forEach(topic => {
|
||
|
topic.categories.forEach(category => {
|
||
|
category.subCategories.forEach(subCategory => {
|
||
|
subCategory.numbers.forEach(section => {
|
||
|
section.indicators.forEach(indicator => {
|
||
|
indicator.indicatorPaths.forEach(indicatorPath => {
|
||
|
let url = indicatorUtils.getNumberUrl(indicatorPath.source, indicatorUtils.getFullUrl(stakeholder, indicatorPath));
|
||
|
cacheItems.push({
|
||
|
reportId: stakeholder._id,
|
||
|
type: 'number',
|
||
|
url: url
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
subCategory.charts.forEach(section => {
|
||
|
section.indicators.forEach(indicator => {
|
||
|
indicator.indicatorPaths.forEach(indicatorPath => {
|
||
|
let url = indicatorUtils.getChartUrl(indicatorPath.source, indicatorUtils.getFullUrl(stakeholder, indicatorPath));
|
||
|
cacheItems.push({
|
||
|
reportId: stakeholder._id,
|
||
|
type: 'chart',
|
||
|
url: url
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
return cacheItems;
|
||
|
}
|
||
|
|
||
|
public exists(id: string) {
|
||
|
return this.reports.has(id);
|
||
|
}
|
||
|
|
||
|
public completed(id: string) {
|
||
|
return !this.exists(id) || this.reports.get(id).completed;
|
||
|
}
|
||
|
|
||
|
public createReport(id: string, cacheItems: CacheItem[], name: string, creator: string) {
|
||
|
let report = new Report(cacheItems.length, name, creator);
|
||
|
this.reports.set(id, report);
|
||
|
this.addItemsToQueue(cacheItems);
|
||
|
return report;
|
||
|
}
|
||
|
|
||
|
public getReport(id: string) {
|
||
|
return this.reports.get(id);
|
||
|
}
|
||
|
|
||
|
private async processQueue() {
|
||
|
this.isFinished = false;
|
||
|
while (this.queue.length > 0) {
|
||
|
let batch = this.queue.splice(0, CacheIndicators.BATCH_SIZE);
|
||
|
await this.processBatch(batch);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private async processBatch(batch: CacheItem[]) {
|
||
|
let promises: Promise<any>[] = [];
|
||
|
let ids = new Set<string>();
|
||
|
batch.forEach(item => {
|
||
|
let promise;
|
||
|
ids.add(item.reportId);
|
||
|
if (item.type === 'chart') {
|
||
|
let [url, json] = item.url.split('?json=');
|
||
|
json = decodeURIComponent(json);
|
||
|
json = statsToolParser(JSON.parse(json));
|
||
|
promise = axios.post(url, json);
|
||
|
} else {
|
||
|
promise = axios.get(item.url);
|
||
|
}
|
||
|
promises.push(promise.then(response => {
|
||
|
let report = this.reports.get(item.reportId);
|
||
|
if (report) {
|
||
|
report.success++;
|
||
|
report.setPercentage();
|
||
|
}
|
||
|
return response;
|
||
|
}).catch(error => {
|
||
|
let report = this.reports.get(item.reportId);
|
||
|
if (report) {
|
||
|
report.errors.push({url: item.url, status: error.response.status});
|
||
|
report.setPercentage();
|
||
|
}
|
||
|
return error.response;
|
||
|
}));
|
||
|
});
|
||
|
await Promise.all(promises);
|
||
|
ids.forEach(id => {
|
||
|
let report = this.reports.get(id);
|
||
|
if (report?.percentage === 100) {
|
||
|
report.completed = true;
|
||
|
this.sendEmail(report);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
private addItemsToQueue(cacheItems: CacheItem[]) {
|
||
|
cacheItems.forEach(item => {
|
||
|
this.queue.push(item);
|
||
|
});
|
||
|
if (this.isFinished) {
|
||
|
this.processQueue().then(() => {
|
||
|
this.isFinished = true;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sendEmail(report: Report) {
|
||
|
let email = Composer.composeEmailToReportCachingProcess(report);
|
||
|
axios.post(properties.adminToolsAPIURL + "sendMail/", email).catch(error => {
|
||
|
console.error(error);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export function statsToolParser(dataJSONobj: any): any {
|
||
|
let RequestInfoObj = Object.assign({});
|
||
|
switch (dataJSONobj.library) {
|
||
|
case "GoogleCharts":
|
||
|
//Pass the Chart library to ChartDataFormatter
|
||
|
RequestInfoObj.library = dataJSONobj.library;
|
||
|
RequestInfoObj.orderBy = dataJSONobj.orderBy;
|
||
|
|
||
|
//Create ChartInfo Object Array
|
||
|
RequestInfoObj.chartsInfo = [];
|
||
|
//Create ChartInfo and pass the Chart data queries to ChartDataFormatter
|
||
|
//along with the requested Chart type
|
||
|
RequestInfoObj.chartsInfo = dataJSONobj.chartDescription.queriesInfo;
|
||
|
break;
|
||
|
case "eCharts":
|
||
|
//Pass the Chart library to ChartDataFormatter
|
||
|
RequestInfoObj.library = dataJSONobj.library;
|
||
|
RequestInfoObj.orderBy = dataJSONobj.orderBy;
|
||
|
|
||
|
//Create ChartInfo Object Array
|
||
|
RequestInfoObj.chartsInfo = [];
|
||
|
|
||
|
//Create ChartInfo and pass the Chart data queries to ChartDataFormatter
|
||
|
//along with the requested Chart type
|
||
|
for (let index = 0; index < dataJSONobj.chartDescription.queries.length; index++) {
|
||
|
let element = dataJSONobj.chartDescription.queries[index];
|
||
|
var ChartInfoObj = Object.assign({});
|
||
|
|
||
|
if (element.type === undefined)
|
||
|
ChartInfoObj.type = dataJSONobj.chartDescription.series[index].type;
|
||
|
else
|
||
|
ChartInfoObj.type = element.type;
|
||
|
|
||
|
if (element.name === undefined)
|
||
|
ChartInfoObj.name = null;
|
||
|
else
|
||
|
ChartInfoObj.name = element.name;
|
||
|
|
||
|
ChartInfoObj.query = element.query;
|
||
|
RequestInfoObj.chartsInfo.push(ChartInfoObj);
|
||
|
}
|
||
|
break;
|
||
|
case "HighCharts":
|
||
|
RequestInfoObj.library = dataJSONobj.library;
|
||
|
RequestInfoObj.orderBy = dataJSONobj.orderBy;
|
||
|
//Pass the Chart type to ChartDataFormatter
|
||
|
var defaultType = dataJSONobj.chartDescription.chart.type;
|
||
|
//Create ChartInfo Object Array
|
||
|
RequestInfoObj.chartsInfo = [];
|
||
|
//Create ChartInfo and pass the Chart data queries to ChartDataFormatter
|
||
|
//along with the requested Chart type
|
||
|
dataJSONobj.chartDescription.queries.forEach(element => {
|
||
|
var ChartInfoObj = Object.assign({});
|
||
|
|
||
|
if (element.type === undefined)
|
||
|
ChartInfoObj.type = defaultType;
|
||
|
else
|
||
|
ChartInfoObj.type = element.type;
|
||
|
|
||
|
if (element.name === undefined)
|
||
|
ChartInfoObj.name = null;
|
||
|
else
|
||
|
ChartInfoObj.name = element.name;
|
||
|
|
||
|
ChartInfoObj.query = element.query;
|
||
|
RequestInfoObj.chartsInfo.push(ChartInfoObj);
|
||
|
});
|
||
|
break;
|
||
|
case "HighMaps":
|
||
|
RequestInfoObj.library = dataJSONobj.library;
|
||
|
//Create ChartInfo Object Array
|
||
|
RequestInfoObj.chartsInfo = [];
|
||
|
|
||
|
//Create ChartInfo and pass the Chart data queries to ChartDataFormatter
|
||
|
dataJSONobj.mapDescription.queries.forEach(element => {
|
||
|
var ChartInfoObj = Object.assign({});
|
||
|
|
||
|
if (element.name === undefined)
|
||
|
ChartInfoObj.name = null;
|
||
|
else
|
||
|
ChartInfoObj.name = element.name;
|
||
|
|
||
|
ChartInfoObj.query = element.query;
|
||
|
RequestInfoObj.chartsInfo.push(ChartInfoObj);
|
||
|
});
|
||
|
break;
|
||
|
default:
|
||
|
console.log("Unsupported Library: " + dataJSONobj.library);
|
||
|
}
|
||
|
return RequestInfoObj;
|
||
|
}
|