Section 8.4. Scripting Shared Objects on the Server

8.4. Scripting Shared Objects on the Server

Working with remote shared objects in Server-Side ActionScript is a little different than working with them in the Flash client. Example 8-5 shows a short main.asc file that forces users to sign into an application with a unique username and keeps track of each user in a remote shared object.

Example 8-5. main.asc file for a simple video chat application
 //   trim(  )   removes whitespace from the beginning and end of a string. function trim (str) {   if (typeof str != "string") return "";  // Make sure   str   is a string.   str = str.replace(/^\s*/, "");          // Trim leading spaces.   str = str.replace(/\s*$/, "");          // Trim trailing spaces.   str = str.replace(/\n/g,  "");          // Remove new lines.   str = str.replace(/\r/g,  "");          // Remove carriage returns.   str = str.replace(/\t/g,  "");          // Remove tabs.   return str; } // Get a temporary (non-persistent) RSO for a read-only list of usernames. application.onAppStart = function ( ) {    userList_so = SharedObject.get("public/userList"); }; /* Accept a client whose username is a unique, non-empty string  * and update the   userList   shared object.  * Each slot value in   userList   is the path to which each client  * has write access and where other clients should look for  * a stream to which to subscribe.  */ application.onConnect = function (client, userName) {   userName = trim(userName);   if (userName.length == 0) {     application.rejectConnection(client, {msg: "Blank or missing user name."});     return;   }   var userPath = userList_so.getProperty(userName);   if (userPath) {     application.rejectConnection(client,        {msg: "The user name '" + userName + "' is already in use."});     return;   }   client.readAccess  = "public";   client.writeAccess = "public/chat";   client.writeAccess = "public/textchat";   client.userName = userName;   userList_so.setProperty(userName, "public/chat/" + userName);   return true; }; // Delete records of clients when they disconnect. application.onDisconnect = function (client) {    userList_so.setProperty(client.userName, null); }; 

The server-side SharedObject.get( ) method is used in place of the client-side SharedObject.getRemote( ) method in Flash and does not require a URI to the application instance (because it is executed from within the FlashCom application):

 userList_so = SharedObject.get("public/userList"); 

Like streams, shared objects are identified by partial URIs that are relative to the application instance. In Example 8-5, the userList shared object is created within the public path. In the application.onConnect( ) method, all clients are given read-only access to the public path so that they can read but not update the userList shared object.

Since the server controls the shared object, there is no need in server-side scripts to call a server-side connect( ) method (there isn't one) or wait for an onSync( ) event.

Another difference from client-side ActionScript is that server-side shared objects don't have a data property. Assigning and retrieving values of server-side shared objects is done via the getProperty( ) and setProperty( ) methods . The following statement sets a property of the shared object. The first parameter in setProperty( ) is always a string property name, while the second parameter can be data of any built-in ActionScript datatypewith the same exceptions and caveats mentioned earlier:

 userList_so.setProperty(userName, "public/chat/" + userName); 

If an object, array, or other non-primitive data is placed in a shared object's slot and an element in the object or array is updated later, setProperty( ) must be called again to update the shared object. For example:

 // Create an object. var loc = {x: 10, y: 30}; // Copy it into the shared object property named   location   . userList_so.setProperty("location", loc); // Update the object. loc.x = 89; // You must copy the object back into the shared object to update it. userList_so.setProperty("location", loc); 

To delete a slot of a shared object in Server-Side ActionScript, call setProperty( ) and pass null as the second parameter. In Example 8-5, this deletes the entry for a user when her client disconnects:

 userList_so.setProperty(client.userName, null); 

To retrieve the value of a shared object's property in SSAS, use getProperty( ) :

 var userPath = userList_so.getProperty(userName); 

If a property does not exist, getProperty( ) returns null .

Working with server-side shared objects is not as convenient as working with them in client-side Flash ActionScript. The data object of client-side shared objects is not available on the server, and you have to call setProperty( ) every time you want to update any part of an object or array within a slot. The data object and automatic updates available in Flash were left out of the server implementation for performance reasons. Detecting and managing changes to elements of the data object is both a CPU- and memory- intensive process. However, you should not shy away from scripting shared objects on the server. It is often the right place to control updates, as described in Chapter 15 and Chapter 18. Let's look at a quick example. In Example 8-5, clients are given read-only access to a shared object. The shared object is created before any client connections are accepted, and all the updates are done on the server side. It is not uncommon for applications to simply deny write access to every client, as follows :

 application.onConnect = function (client) {    client.writeAccess = ""; // No write access    client.readAccess = "/"; // Read anything }; 

Now consider what happens if the server doesn't create the shared object before the first client is allowed to connect. If a shared object does not exist when a client with read-only access attempts to connect to it, the connection attempt will fail. To avoid the problem, shared objects are often created and initialized in the application.onAppStart( ) method as in Example 8-5.

8.4.1. Server-Side onSync( )

In Flash, a shared object's onSync( ) handler can be defined either on SharedObject.prototype or on an individual shared object instance. On the server, you cannot use the prototype to define an onSync( ) handler for all shared objects; for performance reasons, onSync( ) handlers must be defined for an individual instance. One way to define an onSync( ) handler for a SharedObject instance is by using a function expression, also called a function literal:

 ball_so = SharedObject.get("BallPosition"); ball_so.onSync = function (list) {   trace("ball_so.onSync> list.length: " + list.length);   for (var i in list) {     trace("---------- list item number: " + i + " ------------");     var info = list[i];     for (var p in info) {       trace(p + ": " + info[p]);     }   } }; 

Another option is to use a function declaration (also called a function statement) to define the function and then assign it to an individual instance as necessary:

 function genericOnSyncHandler (list) {   trace("ball_so.onSync> list.length: " + list.length);   for (var i in list) {     trace("---------- list item number: " + i + " ------------");     var info = list[i];     for (var p in info) {       trace(p + ": " + info[p]);     }   } } ball_so = SharedObject.get("BallPosition"); ball_so.onSync = genericOnSyncHandler; 

The shared ball example does not require a main.asc script. However, if we wrote one and added the code from either of the previous examples to it, when you drag the ball around, the output in the App Inspector movie would be similar to:

 Loading of app instance: chapter8/sharedBall/version_1 successful ball_so.onSync> list.length: 2 ---------- list item number: 0 ------------ code: change name: ball_1_mc_x oldValue: undefined ---------- list item number: 1 ------------ code: change name: ball_1_mc_y oldValue: undefined ball_so.onSync> list.length: 1 ---------- list item number: 0 ------------ code: change name: ball_1_mc_y oldValue: 82 

Whenever a change occurs as a result of an update from a Flash movie, the list array passed into the server-side onSync( ) method includes information objects with a code value of "change" or "delete" and will always contain an oldValue propertyeven if its value is undefined . When a change is made using the server-side setProperty( ) method, onSync( ) is not called on the server; however, the client-side onSync( ) method is called for each copy of the shared object in connected Flash movies, subject to the constraints described in the next section.

8.4.2. Locking a Shared Object

Client-generated updates of shared objects do not run in the same thread on the server as SSAS, so shared object updates can occur in between server-side setProperty( ) method calls. To guarantee that a shared object cannot be updated by a client until a unit of work is complete on the server, use the shared object's lock( ) and unlock( ) methods. A locked shared object will not notify clients of updates until it is unlocked, so locking a shared object on the server is also a good way to group updates together so they are all sent in one batch to clients. The client-side shared object's onSync( ) method will be called only after all the data has been incorporated into the local copy of the shared object. The following server-side code demonstrates using lock( ) and unlock( ) properly:

 //   initPuzzlePieces(  )   creates a shared object for each puzzle piece // containing the initial coordinates, x and y velocity, and state. function initPuzzlePieces (nClips, xMin, xMax, yMin, yMax) {    var so;    puzzlePieces = [];    for (var i = 0; i < nClips; i++) {       so = SharedObject.get("PuzzlePiece_" + i, true);       // Stop client update requests and stop sending updates to clients.       so.lock( );       // Select a random position within the travel limits.       so.setProperty("x", Math.floor(Math.random( )*(xMax-xMin) + xMin));       so.setProperty("y", Math.floor(Math.random( )*(yMax-yMin) + yMin));       // Select a random direction in which to start moving this clip.       so.setProperty("xVel", Math.floor(Math.random( )*12) - 5);       so.setProperty("yVel", Math.floor(Math.random( )*12) - 5);       // Mark the puzzle piece as being available.       so.setProperty("state", "free");       // Send the new properties for this shared object now.       so.unlock( );       // Keep a reference to each shared object.       puzzlePieces.push(so);    } } 

Locks can be nested, so be sure you have a matching unlock( ) call for every lock( ) you issue. FlashCom maintains a version number for the shared object as a whole and for each shared object slot. When lock( ) is called on a shared object, the version number is not incremented until the shared object is unlocked. The version number for the shared object is available in its version property and is normally incremented after every setProperty( ) call. The version number of each individual slot is not available to ActionScript.

8.4.3. Clearing a Shared Object

Three server-side approaches can be used to reliably clear all the properties of a shared object, so that none are left. One approach is to lock the shared object, get all its properties' names using getPropertyNames( ) , and then delete each property using setProperty( ) , as follows:

 so = SharedObject.get("SOName"); so.lock(  ); var names = so.getPropertyNames(  ); for (i in names) {   so.setProperty(names[i], null); } so.unlock( ); 

Executing a loop like this will also result in the client shared object's onSync( ) method being passed a list of information objects. Each item's code property will have a value of "delete." However, it is much simpler to use the server-side clear( ) method:

 so = SharedObject.get("SOName"); so.clear(  ); 

In this case, each client's shared object onSync( ) handler will receive an array containing one information object with a code value of "clear."

The application.clearSharedObjects( ) method can also be used to clear shared objects as discussed in "Clearing and Deleting Persistent Shared Objects" later in this chapter.

8.4.4. Checking the Size of a Shared Object

The size( ) method, available only on the server, returns the number of properties in a shared object and is a convenient way to check whether a shared object is already in use:

 if (so.size(  ) == 0) {   // Initialize some shared object properties. } 



Programming Flash Communication Server
Programming Flash Communication Server
ISBN: 0596005040
EAN: 2147483647
Year: 2003
Pages: 203

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net