Section 3.7. Communication Components Without SimpleConnect

3.7. Communication Components Without SimpleConnect

Chapter 2 showed how applications can be created using Macromedia's communication components. Macromedia supplies the SimpleConnect component to manage a network connection and connect all the other components to it. SimpleConnect allows users to log in using any name when they connecteven the same name someone else is using. If you need to develop an application that manages user identities differently but want to use Macromedia's communication components, there are two options. One is to write your own connection component. Chapter 13 through Chapter 15 describe how to build custom components. The other option is not to use a connection component at all, as illustrated in the final example in Chapter 2. The following example uses a little server-side scripting, a NetConnection subclass, and the communication components to demonstrate creating a basic chat room application with separate login and chat screens. The application enforces unique usernames, doesn't allow name changes while connected, and does not permit lurking. It is not designed to provide a lobby and multiple chat rooms. These and other enhancements are added in later chapters.

3.7.1. Creating the Application on the Server

To use the communication components without SimpleConnect, an application's main.asc file must load the component framework and store a username for every client that connects within the framework. A minimal main.asc file is shown in Example 3-12.

Example 3-12. Minimal main.asc file when SimpleConnect is not used
 load("components.asc"); application.onConnect = function (client, userName) {   gFrameworkFC.getClientGlobals(client).username = userName;   application.acceptConnection(client); }; 

Example 3-12 allows anyone to connect with any username. To reject connections in which the username is blank or already in use requires a little more work. Example 3-13 shows a listing of another main.asc file. The script uses an object named users to keep track of the userName associated with each Flash movie. (An object such as users , in which the item name is used to access array elements, is known as an associative array , hash table , or simply hash .) The trim( ) function is used to preprocess each userName before checking whether it is null, an empty string, or already in the users object.

Example 3-13. The main.asc file for the netConnectChat application
 load("components.asc"); // Trim any whitespace from before or after the userName. // SSAS supports regular expressions, but client-side ActionScript does not. 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; } // Hash of client objects using the   userName   as a property name. users = {}; // The   onConnect( )   method rejects connection attempts // where   userName   is invalid text or is already in use. application.onConnect = function (client, userName) {   userName = trim(userName);   // Remove leading and trailing whitespace.   if (userName.length == 0) {  // If it is empty, reject it.     application.rejectConnection(client, {msg: "Empty username."});     return;   }   if (users[userName]) {    // If it is in use already, reject it.     application.rejectConnection(client,             {msg: 'The username "' + userName + '" is already in use.'});     return;   }   // Store a reference to the client in the   users   hash.   users[userName] = client;   gFrameworkFC.getClientGlobals(client).username = userName;   application.acceptConnection(client); }; // When a client disconnects, remove the username from the //   users   hash so someone can use it again. application.onDisconnect = function (client) {   var userName = gFrameworkFC.getClientGlobals(client).username;   delete users[userName]; }; 

Placing the main.asc file from Example 3-13 into an applications subdirectory named netConnectChat allows this server-side main.asc script to control the netConnectChat application. If you were developing the main.asc script, you could always test it with a test client but let's push on to create the client-side part of the netConnectChat application in the next section.

3.7.2. Building the Client

Let's build a Flash movie to connect to our brand new netConnectChat application. For now, we'll stick with ActionScript 1.0 and the v1 UI components on which Macromedia's communication components rely. In Chapter 13, when we develop our own custom communication components, we'll switch to ActionScript 2.0 and the v2 UI components.

Using Macromedia's communication components without SimpleConnect is a two-step process: establish a network connection to the application instance and then pass the NetConnection object to each component's connect( ) method. The netConnectChat application uses the PeopleList, Chat, and UserColor components to create a simple text chat interface. The interface can be created with everything on a single frame, as is popular when using the SimpleConnect component, or the different states of the movie can be spread over the timeline. The book's web site includes an example of a single-frame movie. In this example, we'll build the client-side movie for this application using the timeline. Figure 3-4 shows the timeline and Stage when the movie is on the Chat frame.

Figure 3-4. The timeline and Stage with the playhead on the Chat frame

The Chat frame includes the following movie clips (components) and text field:


chat_mc

A Chat component instance


peopleList_mc

A PeopleList component instance


userColor_mc

A UserColor component instance


userName_txt

The text field at the bottom of the Stage


connect_btn

The Connect button at the bottom of the Stage

The Login frame contains only the userName_txt field and connect_btn button. If we were using the SimpleConnect component to log in the user, any other communication component would have to exist throughout the same timeline frames as SimpleConnect. In this example, the communication components do not need to be on the same frames as the username field or the Connect button. The components need only a NetConnection to function, so the username field and Connect button don't have to be included in the Chat frame either. However, in the Chat state, we change the Connect button label to Disconnect; the button logs out the user when clicked. The username text field is kept on the Stage to show the current user's name, but it is disabled during the chat.

The Scripts layer contains all but two lines of the script for the movie. The three important frames are the Init frame, which contains most of the script, and the Login and Chat frames. When the script on the Init frame has completed executing, the playhead moves to the Login frame. There is only one line of code on the Login frame of the Scripts layers :

 startLoginState(  ); 

This statement calls the startLoginState( ) function declared in the first frame of the timeline to initialize the elements on the Stage:

 function startLoginState (  ) {   connect_btn.setLabel("Connect");   userName_txt.selectable = true; } 

Similarly, there is only a single function call on the Chat frame:

 startChatState(  ); 

The startChatState( ) function, also declared on the first frame, initializes the elements in the Chat frame:

 function startChatState (  ) {   connect_btn.setLabel("Disconnect");   userName_txt.selectable = false;   peopleList_mc.connect(nc);   chat_mc.connect(nc);   userColor_mc.connect(nc); } 

The label on the Connect button is reset as necessary by both functions, and the selectable property of the username field is used to disable and enable the userName_txt field.

When the playhead moves to the Chat frame, the communication components are created because that is the first frame in which they exist. But they also need to be connected to a NetConnection object or a NetConnection subclass to operate . The startChatState( ) function passes the global nc object to the connect( ) method of each component for this purpose.

The remaining scripts on the timeline (frames 4, 14, and 24) contain only a stop( ) function call. In addition to the components and movie clips placed directly on the Stage, the Library also contains an AlertBox movie clip symbol. It contains a MessageBox component named alert_mc from the Flash UI components set 2 and provides a way to display pop-up messages. The AlertBox movie clip's timeline contains code to set the title of the MessageBox and set its message text:

 alert_mc.setTitle("Alert"); alert_mc.setMessage(message); 

Example 3-14 shows the script from the main timeline (see timelineComponentConnect.as on the book's web site):.

Example 3-14. Main timeline script
 // A simple alert function and variables to pop a message dialog box on stage. alertLevel = 10;  // Level on which to display the alert dialog box. upperLeft  = 10;  // _x and _y position of the alert dialog box. //   alert( )   displays   msg   in a pop-up alert dialog box. function alert (msg) {   attachMovie("AlertBox", "abox" + alertLevel, alertLevel,                {_x: upperLeft, _y: upperLeft, message: msg} );   // Increment the   alertLevel   and   upperLeft   position.   alertLevel += 1;   upperLeft += 10;   if (upperLeft > 150) upperLeft = 10; } /*   ChatConnection   is a subclass of   NetConnection   designed to move the playhead  * to the   Chat   frame when a connection is made and move it back to the   Login   * frame when it is lost.  */ function ChatConnection ( ) {   super( ); } ChatConnection.prototype = new NetConnection( );      // Subclass   NetConnection   . ChatConnection.prototype.handleCloseEvents = true;   // Initial value. //   connect( )   turns on the   handleCloseEvents   flag before calling   super.connect( )   . ChatConnection.prototype.connect = function ( ) {   this.handleCloseEvents = true;   var result = super.connect.apply(super, arguments);   if (!result) {     alert("Invalid target URI: " + this.uri);   }   return result; }; //   close( )   turns off the   handleCloseEvents   flag before closing the connection. ChatConnection.prototype.close = function ( ) {   this.handleCloseEvents = false;   super.close( ); }; /*   onStatus( )   reports closed connections and errors except when closed  * connections are expected. When a connection is closed, the playhead is  * sent to the   Login   frame. When it is opened, it is sent to the   Chat   frame.  */ ChatConnection.prototype.onStatus = function (info) {   if (info.code == "NetConnection.Connect.Success") {     gotoAndPlay("Chat");   }   else if (!this.isConnected) {     if (this.handleCloseEvents) {       var msg;       if (info.code == "NetConnection.Connect.Rejected") {          msg = 'Connection Rejected!';          if (info.application) {            msg += '\n' + info.application.msg;         }       }       else {         msg = 'Error: Connection ' + info.code.split(".").pop( );       }       alert(msg);       this.handleCloseEvents = false;       gotoAndPlay("Login");     }   } }; // Main timeline button handler functions. /*   doConnect( )   is called whenever   connect_btn   is clicked. If the button label  * is Connect, the   NetConnection.connect( )   method is called. If the label  * is Disconnect, the   close( )   method is called.  */ function doConnect (btn) {   if (btn.getLabel( ) == "Connect") {     if (!nc.isConnected) {       nc.connect("rtmp:/netConnectChat", userName_txt.text);       btn.setLabel("Waiting...");     }   }   else if (btn.getLabel( ) == "Disconnect") {     if (nc.isConnected) {       userColor_mc.close( );       peopleList_mc.close( );       chat_mc.close( );       nc.close( );       gotoAndPlay("Login");     }   } } // Main timeline state change functions. // Called after the   Chat   frame is entered to connect communication components // and change the appearance or behavior of other Flash components. function startChatState ( ) {   connect_btn.setLabel("Disconnect");   userName_txt.selectable = false;   peopleList_mc.connect(nc);   chat_mc.connect(nc);   userColor_mc.connect(nc); } // Called after the   Login   frame is entered to reset login components. function startLoginState ( ) {   connect_btn.setLabel("Connect");   userName_txt.selectable = true; } // Create the chat connection object. _global.nc = new ChatConnection( ); gotoAndPlay("Login"); 

If you test the movie in multiple browser windows , you'll see that you can log in only if the specified username is unique.

Other than that the fact the alert( ) method has replaced writeln ( ) and that state change functions have been added, there should be little here that isn't familiar from the previous examples in this chapter. One difference is in the onStatus( ) handler, which reports some errors a little differently:

 msg = 'Error: Connection ' + info.code.split(".").pop(  ); 

The info.code property always contains a dot-delimited string. The preceding statement uses the split( ) method to split the string into an array and then the array pop( ) method to return the last part of the array. If info.code returns a message such as "NetConnection.Connect.Failed", the preceding statement appends the string "Failed" to "Error: Connection". When a code property is provided, the first term in the string is always the class of object with which the event is associated. The second term is usually the name of the action attempted, and the third is the result. Table 3-2 shows all the NetConnection information object code and level values as of FlashCom 1.5.

Table 3-2. NetConnection code and level values

Code

Level

Meaning

NetConnection.Call.Failed

Error

A remote method call was attempted on this connection and failed. The info.description property contains more details including the name of the method. Remote method calls are discussed in Chapter 9.

NetConnection.Connect.AppShutdown

Error

This message is supposed to be returned when an application instance is forced to shut downfor example when it is out of memory. However, as of FlashCom 1.5, this message is never received; "NetConnection.Connect.Closed" is received instead.

NetConnection.Connect.Closed

Status

Connection was closed by the server or the client. As of FlashCom 1.5, despite the level value of "status", it may indicate an error such as an application instance shutting down because it is using too much memory.

NetConnection.Connect.Failed

Error

The connection attempt failed. The server may not have been reachable or may be down.

NetConnection.Connect.InvalidApp

Error

This message is supposed to be returned when an application name is not registered on the server. However, as of FlashCom 1.5, this message is never received; "NetConnection.Connect.Closed" is received instead.

NetConnection.Connect.Rejected

Error

The attempt to connect was rejected by the server or by the application on the server. The reason the client was rejected depends on several factors. For example, the application may reject the connection because the user's credentials are invalid. The application may return an application object as a property of the information object. The info.description property will contain useful information if the application name was not found, if the resource limits of the application were exceeded, or if the server license does not allow more connections or the usage of more bandwidth. See Table 3-3.

NetConnection.Connect.Success

Status

A connection has been established.


The info.description property is often empty but for some messages contains important additional information. When the server returns a "NetConnection.Connect.Rejected" message, either the server or the application has rejected the connection. When an application rejects a connection, the server-side script writer has the option to return an application object to explain why. When the server rejects a connection, it returns information in the description property that explains why. A rejected description message looks like this:

 [ Server.Reject ] : (_defaultRoot_, _defaultVHost_) : Application (appName)  is not defined. 

Table 3-3 lists the three types of server rejection messages included in the description property.

Table 3-3. Description values for NetConnection.Connect.Rejected messages

Message

Meaning

Server.Reject

The server rejected the connection because the application did not exist, because of a configuration error, or because of some other problem such as bad network data.

Resource.Limit.Exceeded

The resource limits for the server, virtual host, or application have been exceeded. For example, the maximum allowed number of instances or shared objects has been exceeded.

License.Limit.Exceeded

The number of simultaneous client connections or bandwidth limit has been exceeded. See the Preface for FlashCom licensing information.




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