Liquid UI - Documentation - 4.2 Avatar.sjs

4.2 Avatar.sjs


The avatar.js file is the main configuration file that runs the bot. This file contains the functions and APIS used by bot. Many of these elements are not intended to be user-editable, and those will not be covered in this document. Only the elements that users may need to edit or understand will be covered. These user-relevant elements are as follows.

const R3_SERVER_NAME
  1. This defines the name of the SAP application server to which the bot will connect. This value is a connection string. This is one of the few elements that you will need to edit in order to use bot. Replace the default connection string with the string to your own application or message server.

  2. const R3_SERVER_NAME = "/H/juneau"; 
    
const SESSION_TIMEOUT
  1. This value defines the timeout in seconds before the session times out and we display a relevant message. The default value is five (5) seconds as shown below. This element is also intended to be user-editable, so you can adjust the timeout to suit your environment.

  2. const SESSION_TIMEOUT = 5;
const USE_CORNELIUS
  1. This specifies whether the bot does or does not use the Liquid UI WS engine. The two possible states are 'true' and 'false' and the default value is 'true' as shown below.

  2. const USE_CORNELIUS = true;
  3. Note: This value must be set 'true' in order for the bot to run. Bot will only work with Liquid UI WS - it will not run with a non-WS version of Liquid UI.
const GS_INIT
  1. In bot, we have defined a number of states for the bot process. These states are used in the functions that drive bot. Users should not need to modify these states in the avatar.js file, but it may be useful to know the states, in case you need to perform any troubleshooting. The first state is the GS_INIT state. In this state, the process is initializing. The default value is '0' as shown below.

  2. const GS_INIT = 0;
const GS_RUN
  1. In this state, the process is running. This will continue until an order to halt is issued to the process. The default value is '1' as shown below.

  2. const GS_RUN = 1;
const GS_WAIT40
  1. This state occurs when the process has been ordered to halt, but there is at least one connection. This state will endure as long as there are more than zero connections. In this state, the process will wait for the connections to reach zero before proceeding to any other state. The value assigned is '2' as follows.

  2. const GS_WAIT40 = 2;
const GS_ZEROCNT
  1. This state is reached when there are zero connections to the SAP server. THe default value is '3'.

  2. const GS_ZEROCNT = 3;
const GS_HALT
  1. This designates the final state of the bot. Once the connections reach zero, then the state will change to GS_HALT and the bot will exit. The default value is '4'.

  2. const GS_HALT = 4;
SharedMemory('LiquidUIAvatar').write({sjs:'C:\ \GuiXTWS\\SJS\\TRX.sjs'});
  1. This creates another shared memory in a file, into which data will be written and read. This line must be present for the bot to work and should not be edited or changed by users. This shared memory is unavailable to users and the data cannot be used in a script.

SharedMemory('WS').write({autoexit:true});
  1. This creates a shared memory called 'WS' and creates a variable called 'autoexit', which is then set to 'true'. This variable is new for the bot and instructs the process to exit gracefully if the actions cannot be completed. Autoexit has two possible states - true and false. In the 'true' state, it will exit gracefully in the event of a problem, whereas in the 'false' state, the process will freeze. The default state is 'true', as in this example. You can use this in a script to perform an action based on the value of the autoexit variable. However, the avatar.js file entry should not be changed by users. An exampel is shown below, wher we are checking to see if the variable exists. If so, we read the value and then perform an enter command where we send the exit code to SAP.

  2. if(SharedMemory('WS').read().autoexit) enter('/i');

The remainder of the information in the avatar.js file will not be covered in this document, as it is not intended for users to edit. Most of the data contained is required for the bot to work, and this file serves as the control for the bot solution.


Avatar.js Contents

The complete avatar.js file is displayed below.

/*****************************************************************/ /*                                                               */ /*               Synactive Liquid UI Avatar bot                 */ 
/*  Copyright (c) 2013-2013 Synactive Inc. All Rights Reserved.  */
 /*         */ 
/* First draft: August 27 2013      */ 
/*                                                               */ /*****************************************************************/ /***************************************************************** *        
 * * If you want to be reconnected, say, for processing another    
* * user, please put this line somewhere in your WS script  * *        
 * * SharedMemory('avatar').write({loop:true});    * *        
 * * This will cause the system to reconnect again and you can   
automate a login as another user.     * *       
* *****************************************************************/
const R3_SERVER_NAME = "/H/juneau"; 
 // in seconds, wait before we display message if no FS 
 const SESSION_TIMEOUT = 5; 
  // Synactive Inc Cornelius
 const USE_CORNELIUS = true; 
 //SharedMemory('LiquidUIAvatar').write({sjs:'C:\\GuiXTWS\\SJS\\TRX.sjs'}); 
 SharedMemory('WS').write({autoexit:true});
 const GS_INIT = 0; 
 const GS_RUN = 1; 
 // wait for num connections to go down to zero before GS_HALT 
 const GS_WAIT40 = 2; 
 // we are at zero connections
 const GS_ZEROCNT= 3; 

 const GS_HALT = 4; // final state, bye 

Object.InstanceID = 0; 

GWAConnection.prototype.onConnect = function() 
 { 
  } 
  GWAConnection.prototype.onReceiveFromServer = 
  function(nType, nMessage, iSession, iOriginatingSession) 
  {  
  this.lFromServerStatus = nType;    
  println('onReceiveFromServer nType='+nType);    
  println(system.stringify(nMessage));    
  this.touch(); 
  }
// A close connection can come from various places 
// 1. Web Session times out. As determined by SESSION_TIMEOUT value 
// 2. A graceful exit, as indicated by DIAG CLOSE CONNECTION bit 
// 3. Forced network termination 
// // In all cases, this callback is invoked when a hard TCP IP connection 
// ends. This will be the last activity on this object; and the 
// final callback. After this, the JS object is no longer linked to 
// its C++ counterpart. 
GWAConnection.prototype.onClose = function() { 
   this.bConnectionTerminated = true;    
   println('Connection '+this._toHandle()+' terminated');
   } 
   // update the lasttick of this session 
GWAConnection.prototype.touch = function() {
  this.lasttick = GWWebServer.HTTICKS(); 
  } 
  
GWAConnection.TPS_SESSION_TIMEOUT = SESSION_TIMEOUT * GWWebServer.TPS; 

GWAConnection.prototype.getTimeoutDuration = function() {    
	return GWAConnection.TPS_SESSION_TIMEOUT; 
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// GWAMenu object 
//--------------------------------------------------------------------
// GWAMenu represents a menu option 
// Top level menu is declared in vivien as 
// vivien.tm = { "e": [xx, yy]; "Elements": array of GWAMenu } 
// Pop-up menus contains "e"; that identifies the children of this popup 
// The top level children are found in "vivien.tm.e" 
function GWAMenu(argVivien) {    
	this._vivien = argVivien;  
	// dontenum 
	} 
	GWAMenu.prototype.onSetMenu = function(nIdx, nParentIdx, szLabel, iFlag, szInfo, szAccel, evtArray)
	{
		
	}
 
//-------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// GWAVivien object
//------------------------------------------------ // This is the object used to create a message of Vivien arrays function GWAVivien() { // do vivien object initialization here } // called by infrastructure to create a control object GWAVivien.prototype.onConstructControl = function() { return {}; } // context menu & application toolbar GWAVivien.prototype.onConstructCmTb = function() { return {}; } GWAVivien.prototype.onConstructMenu = function(iCnt) { // top level object to hold elements and 'e' this.tm = {}; // top level menu this.tm.Elements = [iCnt]; var i; for(i=0; i<iCnt; i++) this.tm.Elements[i] = new GWAMenu(this); return this.tm.Elements; } // Table column attribute GWAVivien.prototype.onConstructColumnAttribute = function() { return {}; } // Table cell GWAVivien.prototype.onConstructTableCell = function() { return {}; } // TabStrip GWAVivien.prototype.onConstructTabStrip = function() { return {}; } // TableTree GWAVivien.prototype.onConstructTableTree = function() { return {}; } // ImageControl GWAVivien.prototype.onConstructImage = function() { return {}; } // called by infrastructure after completion of total construction // of object GWAVivien.prototype.onConstructionComplete = function() { } // HTML GWAVivien.prototype.onConstructHTML = function() { return {}; } // Object GWAVivien.prototype.onConstructObject = function() { return {}; } // called by infrastructure to construct a vivien object to be // populated. The call here allows each connection to be in control // of how a vivien will look GWAConnection.prototype.onConstructVivien = function() { var obj = new GWAVivien(); // if neccessary, we can do some processing here // this exists in GWAMessage.data // dontenum obj._connection = this; return obj; } //--------------------------------------------------------------------- //--------------------------------------------------------------------- //--------------------------------------------------------------------- //--------------------------------------------------------------------- // GWA object //--------------------------------------------------------------------- // GWA is defined is defined DGWA.cpp // GWA.prototype.process_check = function() { var iProcessed = 0; switch(this.state) { case GS_INIT: try { SharedMemory('avatar').write({loop:false}); var connection = this._connect(this.r3Conn); this.connections[connection._toHandle()] = connection; this.state = GS_RUN; // set the GWA application object in the connection connection.GWA = this; } catch(err) { this.state = GS_HALT; println(err); } break; case GS_RUN: var TPS_NOW = GWWebServer.HTTICKS(); for(var keyHandle in this.connections) { var pConnection = this.connections[keyHandle]; if(pConnection.bConnectionTerminated) { println('[process_check] Connection terminated'); this.state = GS_WAIT40; delete this.connections[keyHandle]; } if((pConnection.lasttick + pConnection.getTimeoutDuration() ) < TPS_NOW) { if(!pConnection.bTimeoutMessageShowed) { println('[process_check] Connection '+keyHandle+' has no ') println('activity for '+SESSION_TIMEOUT+' seconds, please check script'); pConnection.bTimeoutMessageShowed = true; pConnection._shutdown(); this.state = GS_WAIT40; delete this.connections[keyHandle]; } } } break; case GS_WAIT40: println(this.getRunningCount()+ ' connections'); if(this.getRunningCount() == 0) this.state = GS_ZEROCNT; break; case GS_ZEROCNT: // zero connections, we can start afresh if need to if(SharedMemory('avatar').read().loop) this.state = GS_INIT; else this.state = GS_HALT; break; } iProcessed += this._check(); return iProcessed; } GWA.prototype.getRunningCount = function() { return this._getRunningCount(); } GWA.prototype.isStopEventSignaled = function() { var bStop = this.state==GS_HALT; return bStop; } GWA.prototype.shutdown = function() {} var g_Running = true; //--------------------------------------------------------------------- //--------------------------------------------------------------------- //--------------------------------------------------------------------- //--------------------------------------------------------------------- //--------------------------------------------------------------------- // Main loop //--------------------------------------------------------------------- function processFTELoop(application) { // turn on traces //if(TRACE_TRAFFIC) vGWA._traceTraffic(1); //testconnect(vGWA); var iWait = 2; var iNoProc = 0; var iProcessed = 0; for(;g_Running;) { var bStopEventSignaled = application.isStopEventSignaled(); if(bStopEventSignaled || system._ctrlc()) { if(!g_bExitPending) { application.shutdown(); g_bExitPending = true; // set flag to prevent client from reconnecting again print('Exiting ..'); // wait until all the connections are shutdown completely g_Running = false; } else if(application.getRunningCount() == 0) { break; } } if(iWait > 0) Thread.sleep(iWait); iProcessed = application.process_check(); if(iProcessed > 0) { iWait = 0; iNoProc = 0; } else { iNoProc++; if (iNoProc % 50 == 0) system.gc(); if(iNoProc < 3) iWait = 3; // 0 - 2 else if(iNoProc < 4) iWait = 8; // 3 else if(iNoProc < 8) iWait = 12; // 4 - 7 else if(iNoProc < 9) iWait = 50; // 8 else if(iNoProc <13) iWait = 350; // 9 - 12 else if(iNoProc <20) iWait = 450; // 13- 19 else if(iNoProc < 300) iWait = 1000; else { iWait = 1000; system.gc(); iNoProc = 8; // start over // println('Loop reset count'); } } } application = null; return; } function performRun() { var vGWA = new GWA({cornelius:USE_CORNELIUS}); vGWA.state = GS_INIT; vGWA.r3Conn = {}; vGWA.r3Conn.scSvrName = R3_SERVER_NAME; vGWA.connections = {}; processFTELoop(vGWA); delete vGWA.connections; vGWA = void 0; system.gc(); } function main() { performRun(); } main();

Can't find the answers you're looking for?