Section 8.6. Proxied Shared Objects

8.6. Proxied Shared Objects

Every shared object belongs to one application instance. The master instance , also called the home instance , is the only one that can use Server-Side ActionScript to lock a shared object. However, other application instances can access a shared object belonging to a master instance using a network connection. The process of connecting to another instance in order to access its shared object is very much like the process used by a Flash movie to connect to an instance's shared objects.

One instance uses a NetConnection object to connect to the master instance. Then it creates a SharedObject and connects it to a shared object in the master instance. Once synchronization takes place, it can get and set data in the shared object belonging to the master instance. Many instances can connect to the master instance and update the master's shared objects. Figure 8-1 shows two instancesnamed chatApp/room2 and chatApp/room1 connected to a master instance named chatApp/_definst_ . The master instance contains one shared object with a relative URI of private/roomList . The other two instances have connected to the master instance and to its private/roomList shared object.

Figure 8-1. Two instances connected to a master instance in order to access its private/roomList shared object

The following short SSAS code snippet shows how an instance can connect to the _definst_ instance of an application named chatApp and then connect to the master instance's roomList shared object. We'll learn more about this application in the next section:

 // Create a new NetConnection object. nc = new NetConnection(  ); /* Connect to the   _definst_   instance of the   chatApp   application. */ The   _definst_   instance is the master instance. /* See Example 8-6 and Example 8-7. */ nc.connect("rtmp://localhost/chatApp", "room"); // Create a proxy of the master's   private/roomList   shared object // using the net connection, nc. roomList_so = SharedObject.get("private/roomList", false, nc); 

In SSAS, there is no SharedObject.connect( ) method to call, so, instead, the NetConnection object is passed directly into the SharedObject.get( ) method where it is used to connect the local and remote copies of the shared object. Another difference from client-side ActionScript is that regardless of whether the shared object is temporary or persistent, the instance must wait until the shared object's onSync( ) method is called before trying to read or update the shared object, as shown in Example 8-8. When a room instance updates the shared object, the update is passed to the master instance, where the remote shared object is updated. Updates are then sent by the master instance to every client copy of the shared object.

When an instance connects to a master instance's shared object, it automatically makes the master's shared object available to its own movies. In Figure 8-2, the Flash clients connected to the room instances can access the master instance's shared object via the room instances. Each movie connects to a shared object using the relative URI of private/roomList as though the shared object belongs to the room instance. The shared object to which the Flash movies are connected is, in fact, a stand-in for the master's shared object. (That is, each room provides a proxy of the master's shared object for its client movies to connect to.)

Figure 8-2. Flash movies accessing the private/roomList shared object of the master (_definst_) movie via the other instances

The proxy processin which one instance makes available a shared object, stream, or method belonging to another instanceis important for building large-scale applications and for applications that require collaboration between instances.

One example in which instances must cooperate is when one application instance acts as a lobby and the others as chat rooms. The lobby must inform its clients what chat rooms are active and how many people are in them. The information about how many visitors are in each room originates in each chat room instance and must somehow be shared with the lobby. In some applications, visitors in chat rooms may also want to know how many people are in each of the other roomsinformation the lobby instance collects from all the rooms.

One way to share room information across the lobby and room instances is for the lobby to create and manage a room list shared object. Each slot in the room list can be named after a room instance and contain the number of visitors in that room. To get information into the lobby's room list, every chat room instance opens a NetConnection to the lobby and connects to the lobby's room list shared object. Whenever a client enters or leaves a chat room, each room updates its copy of the room list shared object.

Any Flash clients that connect to the lobby can also connect to the room list shared object and will be notified of any room list updates. Similarly, clients that connect to a room can also connect to the room's copy of the room list and will also receive notices of updates via the onSync( ) method. Each room's copy of the shared object acts as a proxy, or stand-in, for the master instance's shared object. A Flash movie connecting to a room instance connects to the room list shared object as though it is owned by the room instance. However, the movie is really connecting to a proxied shared object, and its messages to and from the shared object are passed by the room to the master instance (the lobby).

8.6.1. Lobby and Chat Room Example

Example 8-6 lists the code for the main.asc file for the chatApp application. The file has one purpose: when a request for the _definst_ instance of the application is received, it loads the lobby.asc file. When a request for any other instance occurs, it loads the chatRoom.asc file. In this simple scheme, there is, therefore, only one lobby, which is the default instance of the application. See Chapter 16 for alternatives.

Example 8-6. The main.asc file for chatApp, which delegates to the lobby.asc or chatRoom.asc file
 // Use regular expressions to separate the instance and application name // from the   application.name   property. application.instanceName    = application.name.replace(/.*?\//, ""); application.applicationName = application.name.replace(/\/.*/, ""); if (application.instanceName == "_definst_") {    load("lobby.asc"); } else {    load("chatRoom.asc"); } 

The script guarantees that when any movie or instance attempts to connect to the default instance of the application, the lobby.asc script is run; all other instances are run with the chatRoom.asc file loaded.

The lobby.asc file, shown in Example 8-7, provides the server-side lobby behavior for the application. It sets up the room list and accepts connections from Flash movies and from other application instances (typically rooms).

Example 8-7. The lobby.asc file
 application.onAppStart = function (  ) {    // Since rooms will also connect, keep track of the    // number of Flash clients in a separate variable.    this.clientCount = 0;    // Get a temporary shared object for the room list.    roomList_so = SharedObject.get("private/roomList");    // Update the number of users in the lobby.    roomList_so.setProperty(this.instanceName, this.clientCount); }; application.onConnect = function (client, userName, instanceName) {    // Test to see if a room or regular Flash client is trying to connect.    if (client.ip == "127.0.0.1" &&        client.agent.indexOf("FlashCom") == 0 &&        userName == "room") {      // It's a room connecting.      client.type = "room";      client.instanceName = instanceName;      client.readAccess  = "private";      client.writeAccess = "private";      return true;    }    else {      // It's not a valid room connecting,      // so assume client is a Flash client.      this.clientCount++;      client.type = "client";      client.readAccess = "/";      client.writeAccess = "public";      roomList_so.setProperty(this.instanceName, this.clientCount);      return true;    } }; application.onDisconnect = function (client) {   if (client.type == "client") {     this.clientCount--;     roomList_so.setProperty(this.instanceName, this.clientCount);   }   else {     roomList_so.setProperty(client.instanceName, null);   } }; 

For good measure, the lobby keeps track of each Flash client that connects to it and updates a slot named _definst_ in the room list shared object with the number of Flash clients in the lobby. Inside the onAppStart( ) method, in this statement:

 roomList_so.setProperty(this.instanceName, this.clientCount); 

the this.instanceName property is used to name the lobby's slot _definst_ , and the clientCount property is used to track the number of Flash clients. Why not use the application.clients.length property that automatically keeps track of the number of client connections to the lobby instance? The problem is that both room instances and Flash movies can connect to the lobby; the lobby's onConnect( ) method must determine whether a new client object is a Flash movie or a room instance. Since application.clients.length includes room instances attached as clients, the lobby keeps track of how many Flash movies have connected in the clientCount property.

The room instances don't have the same problem. They can use the application.clients.length property to count the number of clients, because only Flash clients (not other instances) connect to rooms. Example 8-8 shows the code that implements a chat room instance for the application.

Example 8-8. The chatRoom.asc file
 function roomListOnSync (list) {   if (!this.ready) {     this.ready = true;     this.setProperty(application.instanceName, application.clients.length);   } } application.onAppStart = function ( ) {   nc = new NetConnection( );   nc.connect("rtmp://localhost/" + this.applicationName, "room",              this.instanceName);   roomList_so = SharedObject.get("private/roomList", false, nc);   roomList_so.ready = false;   roomList_so.onSync = roomListOnSync; }; application.onConnect = function (client, userName) {   roomList_so.setProperty(application.instanceName, application.clients.length + 1);   return true; }; application.onDisconnect = function (client) {   roomList_so.setProperty(application.instanceName, application.clients.length); }; 

In chatRoom.asc 's application.onAppStart( ) method, the room connects to the lobby, requests a shared object named private/roomList , and assigns an onSync( ) method for the shared object. After the NetConnection.connect( ) to the lobby succeeds, the shared object is automatically connected, synchronization takes place, and the onSync( ) handler of the proxied shared object is called for the first time. If the onSync( ) method is being run for the first time, it updates the shared object with the current number of clients in the room. The onConnect( ) and onDisconnect( ) methods also update the shared object as each client connects to or leaves the room.

Although both the onConnect( ) and onDisconnect( ) methods update the shared object, having onSync( ) also update the shared object is necessary to report the correct number of connected clients when the first user arrives. The reason for this is that a room instance is created when the first client connects. The room instance starts the process of connecting to the lobby and its private/roomList shared object. However, while waiting for the connection process to complete, the room's onConnect( ) method is called and passed a Client object representing the first client. Since the shared object may not be synchronized yet, updating it may have no effect.

Let's look at the problem in detail. When a client connection request starts up a room instance, the following sequence occurs:

  1. The main.asc file is loaded.

  2. The main.asc file loads chatRoom.asc .

  3. The application.onAppStart( ) method in chatRoom.asc is invoked automatically.

  4. The chatRoom instance starts the process of connecting to the lobby instance and proxying its roomList shared object. The connection process is asynchronous. NetConnection.connect( ) returns immediately even though the connection is not established immediately.

  5. The application.onConnect( ) method in chatRoom.asc is invoked automatically (based on the original client request to connect to this application).

  6. The application.onConnect( ) method attempts to update the roomList_so shared object before the shared object is synchronized.

  7. The network connection is established to the lobby instance.

  8. The roomList_so.onSync( ) method is called, and the roomList_so is now ready for updates.

The problem is that the shared object is not ready when the first client connects to a new chat room. So the shared object must be updated with the number of clients after it finally connects.

With every chat room instance creating a proxy to the lobby's private/roomList shared object, a Flash movie does not have to distinguish between connecting to the lobby or chat room to connect to the private/roomList shared object and display the number of users in each room in a listbox. Here is a short function that could be called within a Flash movie to connect to either the lobby instance or a chat room instance depending on the URI in the instanceURI variable:

 function doConnect (  ) {   nc.close(  );   nc.connect(instanceURI);   roomList_so = SharedObject.getRemote("private/roomList", nc.uri);   roomList_so.onSync = function (list) {     roomList_lb.removeAll( );     for (var p in this.data) {       roomList_lb.addItem(this.data[p] + ": " + p);     }   };   roomList_so.connect(nc); } 

In the lobby/chat room example, only the lobby or chat room instances update the shared object. In fact, each movie is given only read access to the shared object. However, an application can allow write access to a proxied shared objectfor example, to allow text chat across more than one instance.

With some alteration to the previous sample code, the lobby could be a separate application on one server, and the chat rooms could exist on more than one server in order to distribute the processing load across multiple servers. That is, instances can connect to other instances and their shared objects, on the same server or across servers.

Each network connection from one instance to another is counted by the communication server's license manager as one client network connection. Consequently, an application that uses interinstance connections will consume client licenses faster than one that does not.



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