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.

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.
|
|