Rich Internet Applications for SLA Research/FlashComm Database Interaction FlashComm

The Flash Communication Server code must be placed in a subfolder of the applications directory. The subfolder should be named AMFPHPChat, and the following code should be placed within a file named main.asc:

 // AMFPHPChat - Server-side code (main.asc)
 load ("components.asc");
 load ("NetServices.asc");
 //
 application.onAppStart = function (info) {
   // program name constant
   application.appName = "AMFPHPChat";
   //
   trace("In onAppStart");
   //
   application.confId = 0;
   //
   trace("Begin sharing text");
   //
   // get the server shared object textchat_so
   // this shared object is non-persistent and
   // it handles method invocations between clients
   // and the application's server-side methods
   application.AMFPHPChat_so = SharedObject.get("AMFPHPChat_so", false);
   //
   // initialize the history of the text share
   application.chat = ""; // chat text that the user sees
   application.chatTS = ""; // chat text that is sent to the database; "TS" = timestamp
   //
   // *************************************************************
   // Netservices set-up: This creates a Flash Remoting connection 
   // to the AMFPHP-enabled web server (e.g., Apache) and allows 
   // the .swf to call a function in a PHP script, thereby working 
   // around the crossdomain restrictions imposed on loadVars objects.
   //
   // http://www.amfphp.org for more information on the technology.
   // *************************************************************
   NetServices.setDefaultGatewayUrl("http://DOMAINNAME/cgi-bin/" + application.appName + "/gateway.php");
   //
   // Then, create the connection object without passing a response object parameter 
   // to the method. The response object will be specified when the component's function
   // is called via the service object, myService, defined below.
   SS_AMFPHPChatConnection = NetServices.createGatewayConnection();
   trace("SS_AMFPHPChatConnection: " + SS_AMFPHPChatConnection);
 };
 //
 application.onConnect = function(clientObject, username) {
   // ** ACCEPT THE CONNECTION
   trace("the Server is connecting... (application.onConnect)");
   trace("onConnect - clientObject: " + clientObject);
   //
   // Set the global user name for the UI Components
   gFrameworkFC.getClientGlobals(clientObject).username = username;
   //
   application.acceptConnection(clientObject, username);
 };
 //
 // **************************************************************************
 application.onConnectAccept = function(clientObject, username) {
   // requestSID() connects to the database and creates a new entry
   // in the chatText_SID table.
   SS_AMFPHPService = SS_AMFPHPChatConnection.getService("DBServices", new AMFPHPResult( clientObject ) );
   trace("SS_AMFPHPService: " + SS_AMFPHPService);
   //
   startSession = function(aUsername, anotherUsername, aDateTime) {
   trace("startSession called; aUsername: " + aUsername 
         + "; anotherUsername: " + anotherUsername 
         + "; aDateTime: " + aDateTime);
   //
   // Call the service; callback is defined after all 
   // application.{whatever} code has been defined, at
   // the end of this script.
   SS_AMFPHPService.nextSession(aUsername, anotherUsername, aDateTime);
   _global.startSessionInterval = setInterval(startSessionTO, 1000);
 };
 //
 saveTextToDB = function () {
   trace("saveTextToDB called");
   //
   // Call the service
   // trace("application.SID: " + application.SID + "; application.chatTS: " + application.chatTS);
   SS_AMFPHPService.saveChatText(application.SID, application.chatTS);
   _global.saveTextToDBInterval = setInterval(saveChatTextTO, 1000);
 };
 //
 // this client method allows the researcher interface to call the AMFPHP service
 // for saving chat text: SS_AMFPHPService.saveChatText(application.SID, application.chatTS)
 clientObject.saveTextToDB = function () {
   trace("clientObject.saveTextToDB called");
   //
   saveTextToDB();
 };
 //
 // this client method (for researcher use only) destroys the session ID information
 clientObject.destroySession = function() {
   destroySession();
 }
 //
 // this SSAS method is called by CSAS in researcher .SWF
 destroySession = function() {
   _global.destroySIDInterval = setInterval(destroySIDTO, 1000);
   trace("SS_AMFPHPService.destroySid()");
   SS_AMFPHPService.destroySID();
 };
 //
 trace("Client.ip: " + clientObject.ip);
 //
 application.confId++;
 trace("confId: " + application.confId);
 //
 if(application.confId == 1) {
   SSASDate = new Date();
   application.startTimeDate = SSASDate;
   timeString = formatTime(SSASDate);
   firstLineMsg = "############################<BR>"
                + "### Chat Started (timestamp: " + timeString + ")<BR>"
                + "############################<BR>";
   application.chat = firstLineMsg;
   // add text to queue for chat text storage in database
   application.chatTS =  firstLineMsg;
   application.user01 = username;
   trace("application.user01: " + application.user01);
 };
 //
 // make each client's name the user's name
 clientObject.name = username;
 //
 // The following method is invoked by client to signal that it is completely initialized/loaded.
 // This server-side script then passes any chat text added to the shared object before the 
 // second or third (instructor) participant has connected.
 //
 clientObject.ready = function() {
   application.AMFPHPChat_so.send("startChat", application.chat);
 };
 //
 clientObject.waiting = function() {
   trace("in clientObject.waiting; confId: " + application.confId);
   //
   // ** TODO: need to add another condition here
   // ** to signal application was never loaded before;
   // ** property of AMFPHPChat_so? (is it persistent presently?)
   if(application.confId == 2) {
     application.user02 = username;
     trace("application.user01: " + application.user01);
     trace("application.user02: " + application.user02);
     startSession(application.user01, application.user02, application.startTimeDate);
   };
 };
 //
 activateClients = function() {
   trace("application.AMFPHPChat_so: " + application.AMFPHPChat_so);
   application.AMFPHPChat_so.send("enterChat");
 };
 //
 // SSAS function to ring all clients' doorbells in response
 // to one client clicking her "doorbell" button.
 clientObject.doorbellRing = function () {
   trace("doorbellRing called");
   application.AMFPHPChat_so.send("clientRing");
 };
 //
 // the client will call this function to get the server to accept
 // the message, add the user's name to it, and send it back
 // to all connected clients.
 clientObject.clientChatMessage = function(plainMSG, color) {
   trace("clientChatMessage has been called from client (AMFPHPChat_01)");
   SSASDate = new Date();
   timeString = formatTime(SSASDate);
   //
   msg = "<FONT COLOR=\"" 
         + color 
         + "\"><B>" 
         + username 
         + ":</B> " 
         + plainMSG 
         + "</FONT><BR>";
   trace("msg: " + msg);
   //
   msgTS = "(" + timeString + ") "
           + "<FONT COLOR=\"" 
           + color 
           + "\"><B>" 
           + username 
           + ":</B> " 
           + plainMSG 
           + "</FONT><BR>";
   trace("msgTS: " + msgTS);
   //
   application.chat += msg;
   application.chatTS +=  msgTS;
   trace("application.chat: " + application.chat);
   trace("application.chatTS: " + application.chatTS);
   application.AMFPHPChat_so.send("serverChatMessage", msg);
   saveTextToDB();
 };
 //
 application.onDisconnect = function(clientObject) {
   trace("disconnect: " + clientObject.name);
   //
   application.confId--;
   trace(".confId: "+application.confId);
   if(application.confId < 1) {
     application.chat = "";
     application.chatTS = "";
   };
 };
 //
 application.onAppStop = function (info) {
   trace("In onAppStop");
   //
   /*
   TODO(?): Later versions of the application may include code to write the text from the chat to the database via a Remoting gateway (AMFPHP, at present) when application.onAppStop(info) is called.
   */
 };
 //
 // formatTime(aDate): called within clientObject.clientChatMessage(plainMSG, color), 
 // which is within application.onConnectAccept
 function formatTime(aDate) {
   //theHours = "0" + aDate.getHours();
   //theHours = theHours.substr(theHours.length - 2, theHours.length);
   //trace("theHours:" + theHours);
   //
   theMinutes = "0" + aDate.getMinutes();
   theMinutes = theMinutes.substr(theMinutes.length - 2, theMinutes.length);
   // trace("theMinutes: " + theMinutes);
   //
   theSeconds = "0" + aDate.getSeconds();
   theSeconds = theSeconds.substr(theSeconds.length - 2, theSeconds.length);
   // trace("theSeconds: " + theSeconds);
   //
   //timeString = theHours + ":" + theMinutes + ":" + theSeconds;
   timeString = theMinutes + ":" + theSeconds;
   trace("timeString: " + timeString);
   return timeString;
 };
 //
 TIMEOUT = 2; // TIMEOUT is a constant to set the number of seconds before an AMFPHP call is sent again
 /**
 * generic AMFPHPResult object
 * used by all remoting calls
 *
 * NOTE: Response objects for individual remoting calls
 * are within the "application.{FUNCTION}" code where
 * AMFPHP services are called
 **/
 AMFPHPResult = function ( client ) {
   // set the client object
   this.client = client;
 };
 //
 /**
 * startSession wait function: startSessionTOInterval
 *
 * called in application.onConnect
 * within clientObject.PHPSID()
 */
 startSessionTOCounter = 0;
 //
 startSessionTO = function( client ) {
   startSessionTOCounter++;
   // trace("startSessionTOCounter: " + startSessionTOCounter);
   //
   if (startSessionTOCounter > TIMEOUT) {
     clearInterval (_global.startSessionInterval);
     startSessionTOCounter = 0;
     trace("TRYING AGAIN - startSessionTOCounter: " + startSessionTOCounter);
     startSession(application.user01, application.user02, application.startTimeDate);
   };
 };
 //
 AMFPHPResult.prototype.nextSession_Result = function ( data ) {
   clearInterval (_global.startSessionInterval);
   application.SID = data;
   trace("application.SID: " + application.SID);
   trace("calling activateClients()");
   activateClients();
 };
 //
 /**
 * saveChatText wait function
 *
 * called in application.onDisconnect
 * within clearSessionID()
 */
 saveChatTextTOCounter = 0;
 //
 saveChatTextTO = function() {
   saveChatTextTOCounter++;
   trace("saveChatTextTOCounter: " + saveChatTextTOCounter);
   //
   if (saveChatTextTOCounter > TIMEOUT) {
     clearInterval (_global.saveTextToDBInterval);
     saveTextToDB();
   };
 };
 //
 AMFPHPResult.prototype.saveChatText_Result = function ( data ) {
   clearInterval (_global.saveTextToDBInterval);
   trace("data: " + data);
 };
 //
 /**
 * destroySID wait function
 *
 * called in application.onDisconnect
 * within clearSessionID()
 */
 destroySIDTOCounter = 0;
 //
 destroySIDTO = function() {
   destroySIDTOCounter++;
   trace("destroySIDTOCounter: " + destroySIDTOCounter);
   //
   if (destroySIDTOCounter > TIMEOUT) {
     clearInterval (_global.destroySIDInterval);
     destroySession();
   };
 };
 //
 AMFPHPResult.prototype.destroySID_Result = function ( data ) {
   clearInterval (_global.destroySIDInterval);
   trace("data: " + data);
 };