| Ryerson Home > Ryerson Flash Communication Development Server > Lobby and Rooms Test Applications |
There has been some discussion about how to write server-side scripts to create
separate lobby and room instances in FlashCom. How does the lobby know how many
people are in the room instances, who they are, and perhaps what they are doing?
One solution is to use a shared object belonging to the lobby that the room
instances update. For this to work, each room instance must connect to the lobby
instance and use SharedObject.get() in order to get a reference
to the lobby's shared object before it can update it. There are a number of
ways to do this and there are also other solutions to this problem. These notes
only describe some experiments where room instances update the lobby's shared
object.
One approach to writing the server-side code is perhaps the simplest: create
separate lobby and rooms folders. This simplifies development slightly because
it is relatively easy to write separate main.asc files for the
lobby and for the rooms. However, many of the examples posted on discussion
groups use one folder and use a single main.asc file that behaves differently
depending on if the client connects to its lobby or room instance. The short
demonstration programs provided here do it both ways: using two application
folders and using only one. To simplify the all-in-one-folder example a simple
workaround is used to load different asc files depending on what instance the
client connects to. In either case, the approach is only one way to solve this
problem. There are many others! This is NOT a recommendation to do it this way
- it is just some experiments that were done in response to some discussions
both on and off some FlashCom lists.
Warning: there is also an important drawback to creating separate instances and having them communicate with each other as clients connect to one instance and then another. FlashCom is licensed by bandwidth and by the maximum number of client connections permitted. Each instance-to-instance connection counts as a client connection to FlashCom's license manager. Also, while it may seem convenient under some circumstances to maintain multiple client-to-server connections this also consumes a lot of client connections. Check out the FlashCom components for one alternative to doing instance-to-instance communications. Here are two links to some of the online discussions about this:
Some other solutions you may find there are polling the admin server for the number of visitors in each room (connecting to the admin server does not count as a client connection), use remoting to keep track of things (remoting connections don't count as client connections), and use one instance that behaves as both the lobby and separate rooms (much more complex).
To keep things simple these test applications don't do much:
Each client displays the information that is normally output to the app_inspector by each application using trace. Normally, in your own testing you would use the app_inspector to see this output but since visitors shouldn't have access to the app_inspector all the application's instance output is sent back to clients when they connect. (Actually, all the output is sent to the client up to a point. When the text field gets too full some of the application's output is truncated.) You can open a client by using the swf link below. The code is available via the links below that.
A FlashCom application instance is typically started when the first client
attempts to connect to it. First the application.onAppStart method
is called and when complete the application.onConnect method is
called. The logical place to get a shared object is in the appStart method.
Here is some simplified code from a lobby application:
application.onAppStart = function(){
writeln("onAppStart> application name: " + application.name);
roomList_so = SharedObject.get("roomList");
roomList_so.onSync = RoomList_onSync;
writeln("onAppStart> roomList_so: " + roomList_so);
}
Once we have the roomList shared object, when the client connects it is a simple matter to store the number of connected clients in the room list. Here's a very simplified listing of how the lobby does this:
application.onConnect = function(client, room){
application.acceptConnection(client);
clientCount++;
roomList_so.setProperty('lobby', clientCount );
}
So the lobby property of the room list contains the number of currently connected clients in the lobby. Of course when a client leaves the value is reduced:
application.onDisconnect = function(client){
clientCount--;
roomList_so.setProperty('lobby', clientCount );
}
Of course having the lobby use the room list to keep track of the number of people in the lobby is beside the point. What is needed is for the room instances to connect to the lobby and update the lobby's shared object so the lobby knows how many people are in each room. The code shown so far works fine in the lobby because the shared object is always setup and ready by the time the client connects. However, this is not the case for a proxied shared object. In the case where the room application connects to the lobby it must wait for the network connection to the lobby to succeed before it can get a reference to the lobby's room list shared object. By the time the connection has succeeded however, the first client has already connected and the onConnect method has completed. In other words the onConnect method can't tell the lobby about the first client using the room list shared object because it hasn't connected to it yet. Here's some simplified code that shows how a room application connects to a lobby application and gets the lobby's room list:
function NetConnection_onStatus(info){
writeln("NetConnection.onStatus> info.code: " + info.code);
if (info.code == "NetConnection.Connect.Success"){
roomList_so = SharedObject.get("roomList", false, nc);
roomList_so.onSync = RoomList_onSync;
writeln("onAppStart> roomList_so: " + roomList_so);
}
}
application.onAppStart = function(){
roomName = application.name.split("/").pop();
writeln("onAppStart> application name: " + aName);
nc = new NetConnection();
nc.onStatus = NetConnection_onStatus;
var result = nc.connect( 'rtmp://localhost/lobby00/lobby', roomName);
writeln("onAppStart> nc: " + nc + " connect result: " + result);
}
application.onConnect = function(client){
application.acceptConnection(client);
clientCount++;
roomList_so.setProperty(roomName, clientCount );
writeln("A client has connected. There are now: " + clientCount + " client(s).");
}
First onAppStart requests the network connection to the lobby, then the client connects, and finally, the network connection to the lobby succeeds after the onConnect method completes. Here is the trace from a room instance that shows this:
onAppStart> application name: rooms00/room_1
onAppStart> nc: [object NetConnection] connect result: true
A client has connected. There are now: 1 client(s).
NetConnection.onStatus> info.code: NetConnection.Connect.Success
Now even though there is a client connected to the room this information hasn't been placed in the lobby's room list because it wasn't available at the time the client connected. When the second client attaches to the room everything will work fine as the connection has been established. A simple workaround to this problem is to check when clients connect to see if the network connection to the lobby is connected. If it isn't then use the setInterval function to call a function to update the room list later. Here is the onConnect method and an updateRoomList function that do this:
function updateRoomList(){
writeln("updateRoomList> nc.isConnected: " + nc.isConnected );
if (nc.isConnected && roomList_so){
clearInterval(pendingUpdate);
roomList_so.setProperty(roomName, clientCount );
}
}
application.onConnect = function(client){
application.acceptConnection(client);
clientCount++;
if (nc.isConnected && roomList_so){
roomList_so.setProperty(roomName, clientCount );
}
else{
if (! pendingUpdate){ // only need one update
pendingUpdate = setInterval(updateRoomList, 1000);
}
}
writeln("A client has connected. There are now: " + clientCount + " client(s).");
}
Just to show this works, here is a trace listing of a room application after the first client connected to it and the updateRoomList function was called:
onAppStart> application name: rooms00/room_1
onAppStart> nc: [object NetConnection] connect result: true
A client has connected. There are now: 1 client(s).
NetConnection.onStatus> info.code: NetConnection.Connect.Success
onAppStart> roomList_so: [object SharedObject]
updateRoomList> nc.isConnected: true
roomList_so.onSync> Here is what is in the roomList:
roomList_so.onSync> lobby: 1
roomList_so.onSync> room_1: 1
Instead of accepting a client connection and trying to count it immediately, it is also possible to put clients into a pending state. After the network connection to the lobby is established and the roomList_so object receives an onSync method call, pending clients can be accepted and the room list updated.
Open the swf file in a browser window.
Here are the source files:
Writing a single main.asc file to act as both a lobby and rooms is not an appealing
task. The application would have to look at its application.name
to figure out how it is supposed to behave and would contain code for lobby
and room behaviour. As a work around to this scenario four files are used on
the server side:
lobby_rooms/main.asc - this file examines the name of the application
and then loads one of the files below.lobby_rooms/lobby.asc - this file contains all the lobby code.lobby_rooms/room.asc - this file contains the code to make
the application behave like a room.lobby_rooms/rejectConnections.asc - the code in this file just
rejects all connection attempts.Here is the source from the main.asc file:
validRooms = {'lobby_rooms/room_1': true, 'lobby_rooms/room_2': true, 'lobby_rooms/room_3': true};
if (application.name == 'lobby_rooms/lobby'){
load('lobby.asc');
}
else if ( validRooms[application.name] ){
load('room.asc');
}
else{
load('rejectConnections.asc')
}
There is one small problem with this approach that is likely not a problem in practice. The loading of the lobby file is slightly delayed. In some tests where clients were simultaneously connecting to both the lobby and a room for the first time ( and therefore both lobby and room instances are loading at almost the same time ) the client connected to the room did not see information on how many clients were in the lobby. In practice clients connect to the lobby first and then to rooms so this should never happen. This effect can only be seen because test client provided here allows you to connect directly to rooms without first visiting the lobby. Finally, even when this does occur the server-side applications have the correct client counts.
Open the swf file in a browser window.
Here are the source files:
client01.asclient01.flalobby_rooms/main.asclobby_rooms/lobby.asclobby_rooms/room.asclobby_rooms/rejectConnections.ascThis document was written by Brian Lesser and last updated: