Files
gtav-src/tools_ng/web/prod/shared/js/ReportRequest.js
T
2025-09-29 00:52:08 +02:00

755 lines
24 KiB
JavaScript
Executable File

/**
* Class ReportRequest
*
* Handles all the functionality of querying a reusable report end-point.
* Requires JQuery
*
* @restUrl - the url of the endpoint
* @dataFormat - default data format (xml or json); may be overridden
*
* Author: Michael Kontogiannis (michael.kontogiannis@rockstarnorth.com)
*/
var ReportRequest = function(restUrl, dataFormat, asyncRestUrl, asyncQueryUrl) {
var xmlFormat = "xml",
jsonContentType = "application/json",
asyncInterval = 500; // in millisecs
var _restUrl = restUrl,
_dataFormat = dataFormat,
_asyncRestUrl = asyncRestUrl,
_asyncQueryUrl = asyncQueryUrl;
/**
* Function sendSingleRequest
*
* A single function for implementing all the data flow process.
*
* @pValues - the object with the values for populating the available parameters once they have been retrieved,
* check respective populateParams functions inside the class
* @callback - the callback function for the retrieved data
* @onComplete - function to call on complete of the second ajax call (optional)
* @dataFormat - override the default dataformat (optional)
*/
function sendSingleRequest(pValues, callback, onComplete, dataFormat) {
var _dF = ((dataFormat) ? dataFormat : _dataFormat);
$.ajax({
url: _restUrl,
type: "GET",
dataType: _dF,
data: {},
async: true,
success: function(params, textStatus, jqXHR) {
params = ((_dF == xmlFormat) ? populateXmlParams(params, pValues) : populateJsonParams(params, pValues));
var reqData = ((_dF == xmlFormat) ? new XMLSerializer().serializeToString(params) : JSON.stringify(params));
var contentType = ((_dF == xmlFormat) ? xmlFormat : jsonContentType);
$.ajax({
url: _restUrl,
type: "POST",
dataType: _dF,
contentType: contentType,
data: reqData,
async: true,
success: function(result, textStatus, jqXHR) {
callback(result);
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {
if (onComplete)
onComplete();
}
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
}
});
}
/**
* Function sendSingleAsyncRequest
*
* A single function for implementing all the data flow process in async endpoint and track the progress.
*
* @pValues - the object with the values for populating the available parameters once they have been retrieved,
* check respective populateParams functions inside the class
* @callback - the callback function for the retrieved data
*
*/
function sendSingleAsyncRequest(pValues, callback, returnedDataType) {
$.ajax({
url: _restUrl,
type: "GET",
dataType: _dataFormat,
data: {},
async: true,
success: function(params, textStatus, jqXHR) {
params = ((_dataFormat == xmlFormat) ? populateXmlParams(params, pValues) : populateJsonParams(params, pValues));
var reqData = ((_dataFormat == xmlFormat) ? new XMLSerializer().serializeToString(params) : JSON.stringify(params));
var contentType = ((_dataFormat == xmlFormat) ? xmlFormat : jsonContentType);
// hack for the endpoints that can't return json
if (returnedDataType)
_dataFormat = returnedDataType;
// Place the request and to get the task identifier
$.ajax({
url: _asyncRestUrl,
type: "POST",
dataType: _dataFormat,
contentType: contentType,
data: reqData,
async: true,
success: function(result, textStatus, jqXHR) {
// Start querying the service for progress updates and results
showProgressbar();
var Progress, Result, TaskIdentifier;
if (_dataFormat == xmlFormat) {
Progress = Number($(result).find("Progress").text());
Result = $(result).find("Result");
TaskIdentifier = $(result).find("TaskIdentifier").text();
}
else {
Progress = result.Progress;
Result = result.Result;
TaskIdentifier = result.TaskIdentifier;
}
if (Progress == 1.0) {
if (Result != null) {
callback(Result);
}
hideProgressbar();
}
else {
querySingleAsyncProcess(TaskIdentifier, callback);
}
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {}
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
}
});
}
/**
* Function querySingleAsyncProcess
*
* A function for querying the status of an asynchronous request on the server and passing the result to
* callback function when it has finished
*
* @taskIdentifier - the id of the asynchronous request on the server
* @callback - the callback function for the retrieved data
*/
function querySingleAsyncProcess(taskIdentifier, callback) {
// If cancel is checked then stop the process
if ($("#cancel-request").is(":checked")) {
hideProgressbar();
// Uncheck for future requests
$("#cancel-request").prop("checked", false);
return;
}
$.ajax({
url: _asyncQueryUrl,
type: "GET",
dataType: _dataFormat,
async: true,
data: {guid: taskIdentifier},
cache: false,
success: function(result, textStatus, jqXHR) {
updateProgressbar(result.Progress * 100);
if (_dataFormat == xmlFormat) {
Progress = Number($(result).find("Progress").text());
Result = $(result).find("Result");
TaskIdentifier = $(result).find("TaskIdentifier").text();
}
else {
Progress = result.Progress;
Result = result.Result;
TaskIdentifier = result.TaskIdentifier;
}
if (Progress == 1.0) {
if (Result != null) {
callback(Result);
}
else {
Sexy.alert(config.asyncRequestFailTxt);
}
hideProgressbar();
}
else
setTimeout(function() {querySingleAsyncProcess(TaskIdentifier, callback);}, asyncInterval);
},
error: function (xhr, ajaxOptions, thrownError) {
hideProgressbar();
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError );
}
});
}
/**
* Function sendMultipleAsyncRequest
*
* Helper function for choosing between different methods of querying the server.
* Check sendMultipleAsyncRequestConcurrently and queryMultipleAsyncProcessesSequentially for more info
*
* @endpointsAndParamValues - Array of objects for each endpoint, each object has the format of:
* {
* restUrl: Value,
* restAsyncUrl: Value,
* pValues: [ Array of pValue objects ]
* }
*
* @callback - the callback function for the retrieved data
*/
function sendMultipleAsyncRequest(endpointsAndParamValues, callback) {
//sendMultipleAsyncRequestConcurrently(endpointsAndParamValues, callback);
sendMultipleAsyncRequestSequentially(endpointsAndParamValues, callback);
}
/**
* Function sendMultipleAsyncRequestConcurrently
*
* A function for implementing all the data flow process in multiple async requests in many endpoints
* and track their progress.
*
* This one sends the all the requests together to the server and queries all of them periodically
*
* @endpointsAndParamValues - Array of objects for each endpoint, each object has the format of:
* {
* restUrl: Value,
* restAsyncUrl: Value,
* pValues: [ Array of pValue objects ]
* }
*
* @callback - the callback function for the retrieved data
*/
function sendMultipleAsyncRequestConcurrently(endpointsAndParamValues, callback) {
showProgressbar();
// Create an array to monitor the processes of each endpoint
var monitoredProcesses = new Array(endpointsAndParamValues.length);
// For each endpoint
$.each(endpointsAndParamValues, function(i, endpoint) {
// get the endpoint parameters
$.ajax({
url: endpoint.restUrl,
type: "GET",
dataType: _dataFormat,
data: {},
async: false,
success: function(params, textStatus, jqXHR) {
//var contentType = ((_dataFormat == xmlFormat) ? xmlFormat : jsonContentType);
// for monitoring each request of the current endpoint
monitoredProcesses[i] = new Array(endpoint.pValues.length);
// make the request and monitor it via its guid
$.each(endpoint.pValues, function(j, pValue) {
var reqParams = ((_dataFormat == xmlFormat) ? populateXmlParams(params, pValue)
: populateJsonParams(params, pValue));
var reqData = ((_dataFormat == xmlFormat) ? new XMLSerializer().serializeToString(reqParams)
: JSON.stringify(reqParams));
monitoredProcesses[i][j] = placeAsyncProcess({asyncUrl: endpoint.restAsyncUrl, reqData: reqData});
/*
$.ajax({
url: endpoint.restAsyncUrl,
type: "POST",
dataType: _dataFormat,
contentType: contentType,
data: reqData,
async: false,
success: function(result, textStatus, jqXHR) {
monitoredProcesses[i][j] = {guid: result.TaskIdentifier, response: null};
},
error: function (xhr, ajaxOptions, thrownError) {
monitoredProcesses[i][j] = {guid: null, response: config.asyncRequestFailTxt};
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
},
complete: function() {}
});
*/
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
}
}); // End of Ajax
}); //End of each endpoint
// Query the status of all the requests until they have all finished
queryMultipleAsyncProcessesConcurrently(monitoredProcesses, callback);
}
/**
* Function queryMultipleAsyncProcessesConcurrently
*
* A function for querying the status of many asynchronous requests on the server concurrently and passing the result to
* callback function when it has finished
*
* @monitoredProcesses - a multidimensional array with the requests of each endpoint
* @callback - the callback function for the retrieved data
*/
function queryMultipleAsyncProcessesConcurrently(monitoredProcesses, callback) {
var completed = 0,
progressPercent = 0.0,
totalProcesses = 0;
$.each(monitoredProcesses, function(i, endpointProcesses) {
totalProcesses += endpointProcesses.length;
});
//console.log("Total Processes: " + totalProcesses);
// Loop through the monitored processes
$.each(monitoredProcesses, function(i, endpointProcesses) {
$.each(endpointProcesses, function(j, process) {
// If the current loop process is finished add the counter and update the progress var
if (process.response) {
completed++;
progressPercent += (100.0 / totalProcesses)
}
// Else query for it's status
else {
$.ajax({
url: _asyncQueryUrl,
type: "GET",
dataType: _dataFormat,
async: false,
data: {guid: process.guid},
cache: false,
success: function(info, textStatus, jqXHR) {
// On success update the progress
progressPercent += ((info.Progress * 100.0) / totalProcesses)
// If it's completed ...
if (info.Progress == 1.0) {
// Save the result or set the respective text if it has failed
//console.log(info);
if (info.Result != null)
process.response = info.Result;
else
process.response = config.asyncRequestFailTxt;
completed++;
}
// else pass for the next round
},
error: function (xhr, ajaxOptions, thrownError) {
// on failure update the progress as completed and set the response to the predefined failure text
progressPercent += (100.0 / totalProcesses)
process.response = config.asyncRequestFailTxt;
completed++;
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError );
}
}); // end $.ajax();
} // end else
}); // end internal $.each();
}); // end external $.each();
// update the final calculated progress
updateProgressbar(progressPercent);
// If all the processes are finished then check if there were failed ones and call the callback function
if (completed == totalProcesses) {
var failed = countFailedRequests(monitoredProcesses);
hideProgressbar();
if (failed == totalProcesses)
return;
callback(monitoredProcesses);
}
else
setTimeout(function() {queryMultipleAsyncProcessesConcurrently(monitoredProcesses, callback); }, asyncInterval);
}
/**
* Function sendMultipleAsyncRequestSequentially
*
* A function for implementing all the data flow process in multiple async requests in many endpoints
* and track their progress.
*
* This one sends the requests sequentially and only one at a time to server
*
* @endpointsAndParamValues - Array of objects for each endpoint, each object has the format of:
* {
* restUrl: Value,
* restAsyncUrl: Value,
* pValues: [ Array of pValue objects ]
* }
*
* @callback - the callback function for the retrieved data
*/
function sendMultipleAsyncRequestSequentially(endpointsAndParamValues, callback) {
showProgressbar();
// Create an array to monitor the processes of each endpoint
var monitoredProcesses = new Array(endpointsAndParamValues.length);
// For each endpoint
$.each(endpointsAndParamValues, function(i, endpoint) {
// get the endpoint parameters
$.ajax({
url: endpoint.restUrl,
type: "GET",
dataType: _dataFormat,
data: {},
async: false,
success: function(params, textStatus, jqXHR) {
// for monitoring each request of the current endpoint
monitoredProcesses[i] = new Array(endpoint.pValues.length);
// make the request and monitor it via its guid
$.each(endpoint.pValues, function(j, pValue) {
var reqParams = ((_dataFormat == xmlFormat) ? populateXmlParams(params, pValue)
: populateJsonParams(params, pValue));
var reqData = ((_dataFormat == xmlFormat) ? new XMLSerializer().serializeToString(reqParams)
: JSON.stringify(reqParams));
// construct the monitored process object
monitoredProcesses[i][j] = {asyncUrl: endpoint.restAsyncUrl,
progress: 0,
reqData: reqData,
guid: null,
response: null};
});
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
}
}); // End of Ajax
}); //End of each endpoint
// Make and query the status of all the requests sequentially until they have all finished
queryMultipleAsyncProcessesSequentially(monitoredProcesses, callback);
}
/**
* Function queryMultipleAsyncProcessesSequentially
*
* A function for querying the status of many asynchronous requests on the server sequentially and passing the result to
* callback function when it has finished
*
* @monitoredProcesses - a multidimensional array with the requests of each endpoint
* @callback - the callback function for the retrieved data
*/
function queryMultipleAsyncProcessesSequentially(monitoredProcesses, callback) {
var completed = 0,
progressPercent = 0.0,
totalProcesses = 0;
$.each(monitoredProcesses, function(i, endpointProcesses) {
totalProcesses += endpointProcesses.length;
});
//console.log("Total Processes: " + totalProcesses);
// Loop through the monitored processes
$.each(monitoredProcesses, function(i, endpointProcesses) {
var exitLoop = false;
$.each(endpointProcesses, function(j, process) {
//console.log(process);
//var exitLoop = false;
if (process.progress == 1.0) {
completed++;
progressPercent += (100.0 / totalProcesses);
}
else {
// If there's no guid first, then
if (!process.guid) {
placeAsyncProcess(process);
}
// In case the reuslt was returned immediately
if (process.progress == 1.0) {
if (process.response == null)
process.response = config.asyncRequestFailTxt;
completed++;
}
else {
//console.log(process.progress);
// Else query for its status
$.ajax({
url: _asyncQueryUrl,
type: "GET",
dataType: _dataFormat,
async: false,
data: {guid: process.guid},
cache: false,
success: function(info, textStatus, jqXHR) {
// On success update the progress
progressPercent += ((info.Progress * 100.0) / totalProcesses);
process.progress = info.Progress;
// console.log(process.guid + " : " + process.progress);
// If it's complete ...
if (info.Progress == 1.0) {
// Save the result or set the respective text if it has failed
// console.log(info);
if (info.Result != null)
process.response = info.Result;
else
process.response = config.asyncRequestFailTxt;
completed++;
}
else {
// console.log("should exit loop");
// Using the exitloop flag since return fails to exit the external loop
exitLoop = true;
// return; // exit the loop to force this process being queried again until it's done
}
},
error: function (xhr, ajaxOptions, thrownError) {
// on failure update the progress as completed and set the response to the predefined failure text
progressPercent += (100.0 / totalProcesses)
process.progress = 1;
process.response = config.asyncRequestFailTxt;
completed++;
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError );
}
}); // end $.ajax();
} // end small else
} //end big else
if (exitLoop) return false;
}); // end internal $.each();
if (exitLoop) return false;
}); // end external $.each();
// update the final calculated progress
updateProgressbar(progressPercent);
var cancelChecked = $("#cancel-request").is(":checked");
// If all the processes are finished or cancel is checked then call the callback function
if (completed == totalProcesses || cancelChecked) {
var failed = countFailedRequests(monitoredProcesses);
hideProgressbar();
if (failed == totalProcesses)
return;
// If cancel is checked, uncheck it for future use and do not proceed
if (cancelChecked) {
$("#cancel-request").prop("checked", false);
return;
}
callback(monitoredProcesses);
}
else {
var t = setTimeout(function() {
queryMultipleAsyncProcessesSequentially(monitoredProcesses, callback);
},
asyncInterval);
}
}
/**
*
*
* */
function placeAsyncProcess(processObj) {
var contentType = ((_dataFormat == xmlFormat) ? xmlFormat : jsonContentType);
$.ajax({
url: processObj.asyncUrl,
type: "POST",
dataType: _dataFormat,
contentType: contentType,
data: processObj.reqData,
async: false,
success: function(result, textStatus, jqXHR) {
processObj.guid = result.TaskIdentifier;
processObj.response = result.Result;
processObj.progress = result.Progress;
},
error: function (xhr, ajaxOptions, thrownError) {
processObj.guid= null;
processObj.response = config.asyncRequestFailTxt;
processObj.progress = 1.0;
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
}
});
//console.log(processObj);
return processObj;
}
function countFailedRequests(monitoredProcesses) {
var totalProcesses = 0,
failedCounter = 0;
// Count the final failed requests
$.each(monitoredProcesses, function(i, endpointProcesses) {
totalProcesses += endpointProcesses.length;
$.each(endpointProcesses, function(j, process) {
if (process.response == config.asyncRequestFailTxt)
failedCounter++;
});
});
if (failedCounter > 0) {
Sexy.alert(failedCounter + " out of " + totalProcesses + " requests have failed!");
}
return failedCounter;
}
/**
* Function getParameters - NOT TESTED
*
* Gets only the end-point's parameters (synchronously).
*
* @dataFormat - override the default dataformat (optional)
*
* @returns - the end-point's available parameters
*
*/
function getParameters(dataFormat) {
var _dF = ((dataFormat) ? dataFormat : _dataFormat),
parameters = {};
$.ajax({
url: restUrl,
type: "GET",
dataType: _dF,
data: {},
async: false,
success: function(params, textStatus, jqXHR) {
parameters = params;
},
error: function (xhr, ajaxOptions, thrownError) {
console.error(this.url + "\n" + ajaxOptions + " " + xhr.status + " " + thrownError);
}
});
return parameters;
}
/**
* Function constructRequestXml
*
* Constructs an xml document from a js object, to be used for the filtering POST request
*
* @options - the js object with the information in the form of:
* {
* rootElement: Value,
* requestData: [
* {elementName: Value, elementValue: Value},
* ...
* ]
* }
*
* @returns - a jQuery xml object
*
*/
function constructRequestXml(options) {
var requestXml = $.parseXML("<" + options.rootElement + " />").documentElement;
$.each(options.requestData, function(i, d) {
$(requestXml)
.append(
$($.parseXML("<" + d.elementName + " />").documentElement).text(d.elementValue)
);
});
return requestXml;
}
/**
* Function populateXmlParams
*
* Populates a reporting framework parameters xml with given values
*
* @params - the ajax returned xml document
* @pValues - a predefined object with the values to populate the xml doc; Example:
* {
* ElementName: "ReportParameter",
* ElementKeyName: "Name",
* ElementValueName: "Value",
* Pairs: [
* {Key: "BuildIdentifiers", Value: "300"},
* {Key: "PlatformIdentifiers", Value: "PS3"},
* ....
* ]
* }
*
* @returns - the populated xml document
*/
function populateXmlParams(params, pValues) {
$(params).find(pValues.ElementName).each(function() {
xmlElement = $(this);
$.each(pValues.Pairs, function(i, pair) {
if (xmlElement.find(pValues.ElementKeyName).text() == pair.Key) {
xmlElement.find(pValues.ElementValueName).removeAttr("i:nil");
xmlElement.find(pValues.ElementValueName).text(pair.Value);
}
});
});
return params;
}
/**
* Function populateJsonParams
*
* Populates a reporting framework parameters json array with given values
*
* @params - the ajax returned json array
* @pValues - a predefined object with the values to populate the json array; Example:
* {
* ElementKeyName: "Name",
* ElementValueName: "Value",
* Pairs: {
* "BuildIdentifiers": "300",
* "PlatformIdentifiers": "PS3",
* "StartDate": start,
"EndDate": end,
* ....
* }
* }
*
* @returns - the populated json array
*/
function populateJsonParams(params, pValues) {
$.each(params, function(i, jItem) {
if (pValues.Pairs[jItem[pValues.ElementKeyName]] != null)
jItem[pValues.ElementValueName] = pValues.Pairs[jItem[pValues.ElementKeyName]];
});
return params;
}
/* Expose the public functions */
return {
sendSingleRequest: sendSingleRequest,
sendSingleAsyncRequest: sendSingleAsyncRequest,
sendMultipleAsyncRequest: sendMultipleAsyncRequest,
getParameters: getParameters,
constructRequestXml: constructRequestXml,
populateXmlParams: populateXmlParams,
populateJsonParams: populateJsonParams,
};
}