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 the 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 that the bot will connect to is defined by this value, which is a connection string. Replace the default connection string with the one for your own application or message server.

  2. const R3_SERVER_NAME = "/H/juneau"; 
    
const SESSION_TIMEOUT
  1. This value defines the session's timeout in seconds and displays a relevant message.This element is user-editable, you can customize the timeout to your environment. The default value is five (5) seconds as shown below.

  2. const SESSION_TIMEOUT = 5;
const USE_CORNELIUS
  1. This determines whether the bot utilizes the Liquid UI WS engine. It can be set to 'true' or 'false', with 'true' being the default value.

  2. const USE_CORNELIUS = true;
     
    Note: This value must be set 'true' to run for the bot. The bot will only work with Liquid UI WS - it will not run with a non-WS version of Liquid UI.
const GS_INIT
  1. The bot process is defined by different states that are integrated into the functions. Users don't need to modify these states within the avatar.js file, however, it may be beneficial to know these states,  particularly when troubleshooting is required. The initial state is designated as the GS_INIT state. During this state, the process undergoes an initialization phase and the default value is '0'.

  2. const GS_INIT = 0;
const GS_RUN
  1. The process will continue in this state until an order to halt is issued. The default value is '1'.

  2. const GS_RUN = 1;
const GS_WAIT40
  1. This state occurs when the process has been ordered to halt, but at least one connection exists. 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 assigned value is '2'.

  2. const GS_WAIT40 = 2;
const GS_ZEROCNT
  1. Zero connections to the SAP server trigger this state. The default value is '3'.

  2. const GS_ZEROCNT = 3;
const GS_HALT
  1. Once the connections reach zero, the bot will enter its final state, GS_HALT, and exit. The default value is '4'.

  2. const GS_HALT = 4;
SharedMemory('LiquidUIAvatar').write({sjs:'C:\ \GuiXTWS\\SJS\\TRX.sjs'});
  1. This line sets up a shared memory in a file for reading and writing data. This shared memory is not user-accessible and the data cannot be used in a script. It is crucial to keep this line unchanged for the bot to operate correctly.

SharedMemory('WS').write({autoexit:true});
  1. This creates a shared memory named 'WS', and a variable 'autoexit', by default it is set to 'true'. The 'autoexit' variable determines how the process responds to issues - if set to 'true', the process exits gracefully, and if set to 'false', the process freezes. By default, it's set to 'true'. Users are advised to refrain from making any modifications to the avatar.js file. For example, you can check if the variable exists, read its value, and execute an enter command to 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 discussed in this document because it is not meant to be modified by users. Most of the data within this file is essential for the bot's functionality, and it acts as the primary control mechanism for the bot's operation.


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?