src.dualinventive.com/mtinfo/dist/webroot/main/html/javascript/comet_statusupdates.js

260 lines
10 KiB
JavaScript

/** \file comet_statusupdates.js
* \brief File containing all functions to handle ZKL status updates through a COMET/JSON link
* \author Bart van Hest, Core|Vision
* \version 1.0
* \date 20-10-2008
* \todo
*
* This file contains the functions needed to perform 'real-time' status updates for the ZKL through a COMET/JSON link.
* It works by opening a connection to a blocking PHP script using the XMLHttpRequest object. The PHP
* script must block as long as no status updates are available. When a status update is available,
* it should spit out JScript code which can be evaluated using eval(). This code should fill in
* an array of objects named ZKL_Status, with members of the object named s_<name>.
*
* The code does only a simple header check to find out if the data send by PHP is valid. The
* header should be ZKLsu1.0 in slash-star comment, which stands for ZKL Status Update v1.0
*
* After eval(), the Array should look like this:
* ZKL_Status[0]
* s_param1 : "param1 value"
* s_param2 : "param2 value"
* ZKL_Status[1]
* s_param1 : "param1 value"
* s_param2 : "param2 value"
* ..
* ZKL_Status[n]
* s_param1 : "param1 value"
* s_param2 : "param2 value"
*
* Also, the Array sent should contain information for all ZKLs monitored, not only the updated ones.
*/
var ZKL_Status = null; // The array with new ZKL status information returned during an update
var xmlhttp = null; // The XMLHttpRequest object used to get status updates
var TimeOut = null; // our timeout counter. We can't add this to the xmlhttp object; IE won't let us. #@$^#$ browser :(
var DataRdyCallback = null; // The callback which should handle new data
var DataErrorCallback = null; // The callback which should handle an error in the data
var ProjectID = -1; // Our project ID for which to ask status updates
var LastRequestTime = -1; // The time our last request was made. Used to discriminate between intentional and unintentional timeouts`
var Sequence = 0 // Add sequence to be unique and disable cache
var ValidRequestTime = -1; // The time our last request was valid. Used to discriminate between intentional and unintentional timeouts
var CometServerScriptURL = null; // The URL of our COMET dataserver script.
var TimeOutmSecs = 12000; // our timeout in milliseconds
/**
* Default data-error callback.
*
* This default callback crates an empty ZKL_Status() array and calls the DataRdyCallback.
* This causes all devices to simply disappear from the screen
*/
function defErrorCallback() {
DbgPrint ("Default data-error callback called.");
ZKL_Status = [];
if (DataRdyCallback != null) { DataRdyCallback(); }
}
/**
* Create the XMLHttpRequest object
*
* Inputs:
* - fnDataRdyCallback: A callback which is called when new statusinfo is received.
* - fnDataErrorCallback: A callback which is called when an error occurred during data reception.
* - sesson_id: A number which make this a unique session
*/
function createUpdater(fnDataRdyCallback, fnDataErrorCallback, sessionid) {
DbgPrint ("createUpdater()");
OurURL = document.URL;
DocRoot = OurURL.split('?');
CometServerScriptURL = DocRoot[0]+"index.php?redirect=scripts/other/rtstatus_datapump.php&id="+sessionid+"&extra_path=../../";
DbgPrint ("COMET server URL: "+CometServerScriptURL);
// Create the XMLHttpRequest object in a browser-independent way
try {
xmlhttp = new XMLHttpRequest();
}
catch (e) {
try {
xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
}
catch (e) {
try {
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}
catch (e) {
xmlhttp = null;
}
}
}
if (!xmlhttp && window.createRequest) {
try {
xmlhttp = window.createRequest();
} catch (e) {
xmlhttp=null;
}
}
if (typeof(fnDataRdyCallback) != 'undefined') {
DataRdyCallback = fnDataRdyCallback;
}
else {
DbgPrint ("INTERNAL ERROR: No DataReadyCallback passed");
}
if (typeof(fnDataErrorCallback) != 'undefined' && fnDataErrorCallback != null) {
DataErrorCallback = fnDataErrorCallback;
}
else {
// default error callback
DataErrorCallback = defErrorCallback;
DbgPrint ("No valid error callback given; reverting to default error callback..");
}
// Start the first request
xmlhttp_startrequest(true);
}
/**
* Abort & destroy the updater.
*
* Inputs:
* none.
*/
function AbortUpdater() {
DataErrorCallback = null;
if (xmlhttp!=null) {
// Assign an empty function to the state handler; IE doesn't like setting this to null.
xmlhttp.onreadystatechange = function () {}
// Abort current transfer. This will also call the state handler, which is not what we want
xmlhttp.abort();
// Clear object
xmlhttp = null;
}
}
/**
* Handle a timeout on the xmlhttp request
*/
function xmlhttp_Timeout() {
try {
DbgPrint ("XMLHttpRequest timed out. Restarting...");
// Assign an empty function to the state handler; IE doesn't like setting this to null.
xmlhttp.onreadystatechange = function () {}
// Abort the current status transfer
xmlhttp.abort();
// See if we need to call the data error callback
if ((new Date().getTime() - LastRequestTime) > TimeOutmSecs) {
if (DataErrorCallback != null) {
DataErrorCallback();
}
}
}
catch (ex) {
// Silent exception
}
finally {
// And start a new one (this will also re-initialise the state handler)
xmlhttp_startrequest();
}
}
/**
* Start a request for status updates.
*
* Inputs:
* - bFirstTime: A boolean indicating whether this is the first time we
* request data. The first time we need data immediately,
* subsequent requests may be stalled until there is new data
* available.
*/
function xmlhttp_startrequest(bFirstTime) {
// Check the arguments
bFirstTime = typeof(bFirstTime) == 'boolean' ? bFirstTime : false;
// start the XHR request
if (xmlhttp!=null) {
// We put a timeout on this request. Restarting the status updater script once in a while
// is not a bad idea since some Web-servers won't allow a script to run for a long time.
TimeOut = setTimeout("xmlhttp_Timeout();",TimeOutmSecs+250);
// Remember the current times so we know when a timeout was unintentional or not.
LastRequestTime = new Date().getTime();
if (ValidRequestTime == -1) {
ValidRequestTime = new Date().getTime();
}
xmlhttp.onreadystatechange=xmlhttp_statechange;
xmlhttp.open("GET",CometServerScriptURL+"&Seq="+(Sequence++)+"&blocking="+(bFirstTime?'false':'true'),true);
xmlhttp.send(null);
}
}
/**
* Data-present function which is called when new ZKL data arrives
*/
function xmlhttp_statechange() {
// Do we have an update from the server? => Else still in progress
if (xmlhttp.readyState == 4) {
try {
// Cancel settimeout
clearTimeout(TimeOut);
if (xmlhttp.status == 200 ) {
// Reset timeout
ValidRequestTime = new Date().getTime();
// Do something with the data. Check our 'magic-ID'. If it passes,
var offset = xmlhttp.responseText.search("\/[*]ZKLsu1.0[*]\/");
// Magic code available?
if (offset != -1) {
//DbgPrint(xmlhttp.responseText);
eval(xmlhttp.responseText.substring(offset));
// OK, by now we should have a ZKL_Status array with statuses of devices in the field.
// Call the user supplied callback
if (DataRdyCallback != null) {
DataRdyCallback();
}
// We had a valid request, so no DataErrorCallback may be called, so clear LastRequestTime
LastRequestTime = new Date().getTime();
}
else {
DbgPrint("Invalid data from server\n("+xmlhttp.responseText+")");
// Call our data error callback
if (DataErrorCallback != null) {
DataErrorCallback();
}
}
}
else if ((xmlhttp.status == 0) || (xmlhttp.status == 12029) || (xmlhttp.status == 12007)) {
// Catch IE/FF exceptions when no connection available
if ((new Date().getTime() - ValidRequestTime) > TimeOutmSecs) {
DbgPrint ("XMLHttpRequest FF timed out, status 0. Calling DataErrorCallback()..");
if (DataErrorCallback != null) {
DataErrorCallback();
}
}
}
else {
// Our request failed. Call the data error callback
DbgPrint ("xmlhttp_status: "+xmlhttp.status);
}
}
catch(ex) {
// Silent exception
}
finally {
// Redo request.
// We used to do a xmlhttp_startrequest() again. This works in every browser, except IE.
// IE won't allow us to call XMLHttpRequest methods from within the event handler.
// So, we use a hack: we shorten the timeout to 250msec. Once we have a timeout, a new
// request will be started.
TimeOut = setTimeout("xmlhttp_Timeout();",250);
}
}
}