Building a multiuser chat application with the Union Platform and Flex Builder 3

Post to Twitter

Several years ago there was a socket server for Flash called Unity. Well, recently Unity has been reborn (re-written actually) as the Union Platform. The same developers (Colin Moock and Derek Clayton) are still hard at work making connecting Flash/Flex applications via sockets as easy as possible. Keep in mind the spec for Union’s message format is open so I’d assume you could connect clients like Silverlight, thick clients, etc. to Union as well. This is going to be an excellent platform for building online games, chat applications, and much more.

[ad name=”Google Adsense”]

This post was updated on May 10, 2009 based upon feedback from the master of ActionScript himself Colin Moock.

In this article we will build a multiuser chat application in Flex. You can build this chat application in one of two ways. First, you can download the goodies and install them and use the Union server that has been setup for developers to use at TryUnion.com. If you go that way then you only need to have Flex Builder 3.02 (a trial version is available) and Reactor. If you prefer to install everything then you will need:
1. Java 1.6 (JDK)
2. Flex Builder 3.02 (a trial version is available)
3. Union Platform – grab Reactor (this is the ActionScript 3 client SDK) and the Server.

I’m using Windows Vista to build this chat application and I’ll assume you have everything installed and ready to go. I am still learning the Union Platform API so there are probably more efficient ways to go about things, feel free to leave comments on how best to optimize this code.

Before you begin please note there is an issue when it comes to joining rooms in the Alpha 1 release – in particular an error is thrown and that has to do with the ordering of UPC messages and will be resolved in the Alpha 2 release.

Lets begin. First open Flex Builder and create a new project. Call it “UnionRoomChat”.

Creating the new project

Click the “next” button and on the last page of the wizard link to the Reactor.swc file you downloaded as part of the Union client SDK.

Linking to the SWC library

I’m going to layout the initial panel the user will be greeted with when they first come to our chat application. It will consist of a button, a textinput control as well as a simple graphic I pulled from Wikimedia Commons. My screen looks like this:

The first screen

The MXML so far looks like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" fontFamily="Verdana" fontSize="12" color="#000000" currentState="Start">
	<mx:states>
		<mx:State name="Login">
			<mx:AddChild position="lastChild">
				<mx:Panel width="362" height="226" layout="absolute" horizontalCenter="0" verticalCenter="0" borderColor="#A2A2A2" backgroundColor="#EEEEEE" id="login_pnl" title="Union Room Chat">
					<mx:TextInput x="98.5" y="15" maxChars="20" id="username_txt" borderStyle="solid"/>
					<mx:Label x="13.5" y="17" text="Username:" fontWeight="bold"/>
					<mx:Button click="onLoginClicked();" x="266.5" y="13" label="Login" id="login_btn"/>
					<mx:Image x="107" y="45" source="images/Crystal_Clear_talk.png"/>
				</mx:Panel>
			</mx:AddChild>
		</mx:State>
	</mx:states>
</mx:Application>

That’s pretty straight forward, I’m going to add the following ActionScript now to the MXML file:

<mx:Script>
	<![CDATA[

		import net.user1.reactor.Room;
		import net.user1.reactor.IClient;
		import net.user1.reactor.UConnection;
		import net.user1.reactor.UConnectionEvent;

		private var connection:UConnection;

		private function onLoginClicked():void
		{
			// Create the connection object
			connection = new UConnection();
			// Add the event listeners
			connection.addEventListener(UConnectionEvent.READY, connectionReadyListener);
			connection.addEventListener(UConnectionEvent.CLOSE, connectionCloseListener);
			// Open the connection, I've set my port to 80
			connection.open("localhost", 80);
		}

		private function connectionReadyListener(e:UConnectionEvent):void
		{
			trace("Connected!");
		}

		private function connectionCloseListener(e:UConnectionEvent):void
		{
			trace("Closed!");
		}
	]]>
</mx:Script>

If we run this project right now (ignoring the username textbox) we ought to see something like this in Flex Builder’s console:

Flex Builder console output

Ok, we need to add the code now to set the username. We will do this using attributes of the Client class. The code now looks like this:

<mx:Script>
	<![CDATA[

		import net.user1.reactor.Room;
		import net.user1.reactor.IClient;
		import net.user1.reactor.UConnection;
		import net.user1.reactor.UConnectionEvent;

		private var connection:UConnection;
		private var client:IClient;

		private function onLoginClicked():void
		{
			// Create the connection object
			connection = new UConnection();
			// Add the event listeners
			connection.addEventListener(UConnectionEvent.READY, connectionReadyListener);
			connection.addEventListener(UConnectionEvent.CLOSE, connectionCloseListener);

			// Open the connection, I've set my port to 80
			connection.open("localhost", 80);
		}

		private function connectionReadyListener(e:UConnectionEvent):void
		{
			trace("Connected!");

			// Get a reference to the client
			client = connection.getClientManager().self();
			// Set the username attribute, you would want to ensure
			// the user actually entered something in username_txt
			client.setAttribute("username", username_txt.text, null, false);
		}

		private function connectionCloseListener(e:UConnectionEvent):void
		{
			trace("Closed!");
		}

	]]>
</mx:Script>

You can see we added more code to the “connectionReadyListener” function to handle setting the username attribute. Now we need to join the default chat room, or if it doesn’t exist we need to create it. We also need to move to the main lobby chat panel now that we are connected. Lets add the new panel first by adding a new state to the project called “MainPanel”.

Main Lobby panel

The new panel will look like this:

Main lobby panel with components

We need to add some code to the end of the “connectionReadyListener” function in order for the new main lobby panel to show up.

setCurrentState("MainLobby");

Now we need to add the code to make this all work! First, recall we need to join the default chat room and if it doesn’t exist we need to create it. The RoomManager will do this work for us, in particular the call to createRoom. If the room already exists you might see this show up in the console “[SERVER] Room creation results for room ‘mainLobbyRoom’: ROOM_EXISTS”. That is ok, we can ignore that for this simple application.

// Create a room that doesn't go away when no one is in it
var roomSettings:RoomSettings = new RoomSettings();
roomSettings.dieOnEmpty = false;
// Create the room (it might already exist)
currentRoom = connection.getRoomManager().createRoom("mainLobbyRoom", roomSettings);
// Listen for chat messages in this room
currentRoom.addMessageListener(CHAT_MESSAGE, mainLobbyChatMessageListener);
// Join the room
currentRoom.join();

I’m going to add a string const to the top of the script since we will reuse this string fairly often:

private const CHAT_MESSAGE:String = "CHAT_MESSAGE";

Lets add code now to send a chat message. First we will add an event handler for the send button:

<mx:Button x="252" y="263" label="Send" id="send_btn" click="onSendClicked();"/>

Now we add a function for the send button:

private function onSendClicked():void
{
    if(currentRoom != null)
    {
        currentRoom.sendMessage(CHAT_MESSAGE, true, null, input_txt.text);
        input_txt.text = "";
    }
}

We can hook up the chatMessageListener function which will display the messages to the user:

private function chatMessageListener(fromClient:IClient, chatText:String ):void
{
    output_txt.htmlText += "<b>" + fromClient.getAttribute(null, "username") + ":</b> " + chatText;
}

Time to hook up the disconnect button:

<mx:Button x="470" y="263" label="Disconnect" id="disconnect_btn" width="140" click="onDisconnectClicked();" />

…and the function for it:

private function onDisconnectClicked():void
{
	// You don't need to call the leave() function since
	// the disconnect will remove the client when the
	// connection is closed but it is a good practice in
	// case something goes wrong in the disconnect and
	// the user appears as a ghost (ghosts are eventually
	// removed by the server when they cannot be reached).
    if(currentRoom != null)
        currentRoom.leave();

    connection.close();
    setCurrentState("Login");

    output_txt.htmlText = "";
    input_txt.text = "";
}

There are several more things we need to do now. First I want to hook up the event listeners for the rooms being added or existing rooms being removed as well as initially listening to the lobby room at the start.

   private function addRoomListeners():void
   {
        currentRoom.addEventListener(RoomEvent.ADD_CLIENT, clientAddedListener);
        currentRoom.addEventListener(RoomEvent.REMOVE_CLIENT, clientRemovedListener);
        currentRoom.addEventListener(RoomEvent.SYNCHRONIZE, synchronizeRoomListener);
   }

   private function removeRoomListeners():void
   {
        currentRoom.removeEventListener(RoomEvent.ADD_CLIENT, clientAddedListener);
        currentRoom.removeEventListener(RoomEvent.REMOVE_CLIENT, clientRemovedListener);
        currentRoom.removeEventListener(RoomEvent.SYNCHRONIZE, synchronizeRoomListener);
   }

That code will go into connectionReadyListener() and later on will be called in the join room and create room functions.

I’m going to run the project and open an additional window so I have two chat applications running.

Two chats running

Lets hook up the code now to fill the rooms and users listboxes. I’m going to create a bindable variable for the rooms and users listboxes to make this easy.

[Bindable]
private var arrRooms:Array = new Array();
[Bindable]
private var arrUsers:Array = new Array();

Now I bind them like this:

<mx:List x="319" y="22" width="142" height="234" verticalScrollPolicy="on" id="users_lst" dataProvider="{arrUsers}"></mx:List>
<mx:List x="469" y="22" width="142" height="170" verticalScrollPolicy="on" id="rooms_lst" dataProvider="{arrRooms}"></mx:List>

We will hook up the synchronizeRoomListener function as well so we get the initial list of the users in the room they join.

   private function synchronizeRoomListener(e:RoomEvent):void
   {
        // Get the list of all users in the current room
        var arrClientTemp:Array = currentRoom.getClients();
        arrUsers.length = 0;

        for(var i:int = 0; i < arrClientTemp.length; i++)
        {
            var c:Client = arrClientTemp[i];
            arrUsers.push(c.getAttribute(null, "username"));
        }
        arrUsers.sort(Array.CASEINSENSITIVE);
        users_lst.data = arrUsers;
   }

So the functions now to handle the populating of the user and room listboxes will look like this:

   private function clientAddedListener(e:RoomEvent):void
   {
   		arrUsers.push(e.getClient().getAttribute(null, "username"));
   		arrUsers.sort(Array.CASEINSENSITIVE);
   		users_lst.data = arrUsers;
   }

   private function clientRemovedListener(e:RoomEvent):void
   {
   	   // To be safe you probably would want to remove the clients by
   	   // their clientID, not their username attribute like I'm using
   	   // since you could have two users with the same username and end up
   	   // removing the wrong one.  Or if your using some form of authentication
   	   // you would want to ensure no two usernames could be the same when
   	   // users register for your application
	   arrUsers.splice(arrUsers.indexOf(e.getClient().getAttribute(null, "username")), 1);
       users_lst.data = arrUsers;
   }

   private function roomRemovedListener(e:RoomManagerEvent):void
   {
       for(var obj:Object in arrRooms)
       {
       		if(arrRooms[obj] == e.getRoomID())
       			arrRooms.splice(arrRooms.indexOf(e.getRoomID()), 1);
       }
       rooms_lst.data = arrRooms;
   }

   private function roomAddedListener(e:RoomManagerEvent):void
   {
   		arrRooms.push(e.getRoomID());
   		rooms_lst.data = arrRooms;
   		rooms_lst.dataProvider.refresh();
   }

We can add the code now to hook up the create room and join room buttons:

private function onCreateRoomClicked():void
{
	// Ensure the room hasn't already been created
	if (currentRoom.getRoomID() == connection.getClientManager().self().getAttribute(null, "username"))
	{
		output_txt.htmlText = "<b>Room '" + currentRoom.getRoomID() + "' already exists.</b>";
		return;
	}

    currentRoom.removeMessageListener(CHAT_MESSAGE, chatMessageListener);
    removeRoomListeners();
    currentRoom.leave();
    currentRoom = connection.getRoomManager().createRoom(connection.getClientManager().self().getAttribute(null, "username"));
    currentRoom.addMessageListener(CHAT_MESSAGE, chatMessageListener);
    addRoomListeners();
    currentRoom.join();
    output_txt.htmlText = "<b>Creating room: " + currentRoom.getRoomID() + "...</b>";
}

private function onJoinRoomClicked():void
{
    if(rooms_lst.selectedItem != null)
    {
        currentRoom.removeMessageListener(CHAT_MESSAGE, chatMessageListener);
        removeRoomListeners();
        currentRoom.leave();
        currentRoom = connection.getRoomManager().joinRoom(rooms_lst.selectedItem.toString());
        currentRoom.addMessageListener(CHAT_MESSAGE, chatMessageListener);
        addRoomListeners();
        output_txt.htmlText = "<b>Joining room: " + currentRoom.getRoomID() + "...</b>";
    }
}

My final code looks like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" fontFamily="Verdana" fontSize="12" color="#000000" currentState="Login">
    <mx:states>
        <mx:State name="Login">
            <mx:AddChild position="lastChild">
                <mx:Panel width="362" height="226" layout="absolute" horizontalCenter="0" verticalCenter="0" borderColor="#A2A2A2" backgroundColor="#EEEEEE" id="login_pnl" title="Union Room Chat">
                    <mx:TextInput x="98.5" y="15" maxChars="20" id="username_txt" borderStyle="solid"/>
                    <mx:Label x="13.5" y="17" text="Username:" fontWeight="bold"/>
                    <mx:Button click="onLoginClicked();" x="266.5" y="13" label="Login" id="login_btn"/>
                    <mx:Image x="107" y="45" source="images/Crystal_Clear_talk.png"/>
                </mx:Panel>
            </mx:AddChild>
        </mx:State>
        <mx:State name="MainLobby">
            <mx:AddChild position="lastChild">
                <mx:Panel width="640" height="338" layout="absolute" horizontalCenter="0" verticalCenter="0" fontFamily="Verdana" fontSize="12" id="mainPanel_pnl" title="Union Room Chat">
                    <mx:TextArea x="10" y="22" width="301" height="234" borderStyle="solid" verticalScrollPolicy="on" id="output_txt"/>
                    <mx:TextInput x="10" y="264" width="234" id="input_txt" maxChars="100"/>
                    <mx:Button x="252" y="263" label="Send" id="send_btn" click="onSendClicked();"/>
                    <mx:Button x="469" y="200" label="Create Room" id="createRoom_btn" width="141" click="onCreateRoomClicked();" />
                    <mx:Button x="470" y="232" label="Join Room" id="joinRoom_btn" width="140" click="onJoinRoomClicked();"/>
                    <mx:Button x="470" y="263" label="Disconnect" id="disconnect_btn" width="140" click="onDisconnectClicked();" />
                    <mx:List x="319" y="22" width="142" height="234" verticalScrollPolicy="on" id="users_lst" dataProvider="{arrUsers}"></mx:List>
                    <mx:List x="469" y="22" width="142" height="170" verticalScrollPolicy="on" id="rooms_lst" dataProvider="{arrRooms}"></mx:List>
                    <mx:Label x="129" y="2" text="Chat" fontWeight="bold"/>
                    <mx:Label x="515" y="2" text="Rooms" fontWeight="bold"/>
                    <mx:Label x="363" y="2" text="Users" fontWeight="bold"/>
                </mx:Panel>
            </mx:AddChild>
        </mx:State>
    </mx:states>
    <mx:Script>
        <![CDATA[
            import net.user1.reactor.Client;
            import net.user1.reactor.Room;
            import net.user1.reactor.IClient;
            import net.user1.reactor.UConnection;
            import net.user1.reactor.RoomEvent;
            import net.user1.reactor.RoomSettings;
            import net.user1.reactor.RoomManagerEvent;
            import net.user1.reactor.UConnectionEvent;

            import mx.controls.Alert;

            private var connection:UConnection;
            private var currentRoom:Room;
            private var client:IClient;
            private var firstTime:Boolean = true;
            private const CHAT_MESSAGE:String = "CHAT_MESSAGE";

            [Bindable]
            private var arrRooms:Array = new Array();
            [Bindable]
            private var arrUsers:Array = new Array();


            private function onLoginClicked():void
            {
                // Create the connection object
                connection = new UConnection();
                // Add the event listeners
                connection.addEventListener(UConnectionEvent.READY, connectionReadyListener);
                connection.addEventListener(UConnectionEvent.CLOSE, connectionCloseListener);

                // Open the connection, I've set my port to 80
                connection.open("localhost", 80);
            }

            private function connectionReadyListener(e:UConnectionEvent):void
            {
                // Get a reference to the client
                client = connection.getClientManager().self();
                // Set the username attribute, you would want to ensure
                // the user actually entered something in username_txt
                client.setAttribute("username", username_txt.text);
                setCurrentState("MainLobby");

                // Reset the arrays in case they disconnect and reconnect
                arrRooms.length = 0;
                arrUsers.length = 0;

                // Add event listeners when rooms are added or removed
                connection.getRoomManager().addEventListener(RoomManagerEvent.ROOM_ADDED, roomAddedListener);
                connection.getRoomManager().addEventListener(RoomManagerEvent.ROOM_REMOVED, roomRemovedListener);

                connection.getRoomManager().watchForRooms();

                // Create a room that doesn't go away when no one is in it
                var roomSettings:RoomSettings = new RoomSettings();
                roomSettings.dieOnEmpty = false;
                // Create the room (it might already exist)
                currentRoom = connection.getRoomManager().createRoom("mainLobbyRoom", roomSettings);

                currentRoom.addMessageListener(CHAT_MESSAGE, chatMessageListener);

                // Start listening to the room events, it's a good
                // practice to set the listeners before you join the room
                addRoomListeners();

                // Join the room
                currentRoom.join();
           }

           private function addRoomListeners():void
           {
                currentRoom.addEventListener(RoomEvent.ADD_CLIENT, clientAddedListener);
                currentRoom.addEventListener(RoomEvent.REMOVE_CLIENT, clientRemovedListener);
                currentRoom.addEventListener(RoomEvent.SYNCHRONIZE, synchronizeRoomListener);
           }

           private function removeRoomListeners():void
           {
                currentRoom.removeEventListener(RoomEvent.ADD_CLIENT, clientAddedListener);
                currentRoom.removeEventListener(RoomEvent.REMOVE_CLIENT, clientRemovedListener);
                currentRoom.removeEventListener(RoomEvent.SYNCHRONIZE, synchronizeRoomListener);
           }

           private function clientAddedListener(e:RoomEvent):void
           {
           		arrUsers.push(e.getClient().getAttribute(null, "username"));
           		arrUsers.sort(Array.CASEINSENSITIVE);
           		users_lst.data = arrUsers;
           }

           private function clientRemovedListener(e:RoomEvent):void
           {
           	   // To be safe you probably would want to remove the clients by
           	   // their clientID, not their username attribute like I'm using
           	   // since you could have two users with the same username and end up
           	   // removing the wrong one.  Or if your using some form of authentication
           	   // you would want to ensure no two usernames could be the same when
           	   // users register for your application
			   arrUsers.splice(arrUsers.indexOf(e.getClient().getAttribute(null, "username")), 1);
               users_lst.data = arrUsers;
           }

           private function synchronizeRoomListener(e:RoomEvent):void
           {
                // Get the list of all users in the current room
                var arrClientTemp:Array = currentRoom.getClients();
                arrUsers.length = 0;

                for(var i:int = 0; i < arrClientTemp.length; i++)
                {
                    var c:Client = arrClientTemp[i];
                    arrUsers.push(c.getAttribute(null, "username"));
                }
                arrUsers.sort(Array.CASEINSENSITIVE);
                users_lst.data = arrUsers;
           }

           private function roomRemovedListener(e:RoomManagerEvent):void
           {
               for(var obj:Object in arrRooms)
               {
               		if(arrRooms[obj] == e.getRoomID())
               			arrRooms.splice(arrRooms.indexOf(e.getRoomID()), 1);
               }
               rooms_lst.data = arrRooms;
           }

           private function roomAddedListener(e:RoomManagerEvent):void
           {
           		arrRooms.push(e.getRoomID());
           		rooms_lst.data = arrRooms;
           		rooms_lst.dataProvider.refresh();
           }

            private function connectionCloseListener(e:UConnectionEvent):void
            {
                Alert.show("Connection Closed");
            }

            private function chatMessageListener(fromClient:IClient, chatText:String ):void
            {
                output_txt.htmlText += "<b>" + fromClient.getAttribute(null, "username") + ":</b> " + chatText;
            }

            private function onSendClicked():void
            {
                if(currentRoom != null)
                {
                    currentRoom.sendMessage(CHAT_MESSAGE, true, null, input_txt.text);
                    input_txt.text = "";
                }
            }

            private function onDisconnectClicked():void
            {
            	// You don't need to call the leave() function since
            	// the disconnect will remove the client when the
            	// connection is closed but it is a good practice in
            	// case something goes wrong in the disconnect and
            	// the user appears as a ghost (ghosts are eventually
            	// removed by the server when they cannot be reached).
                if(currentRoom != null)
                    currentRoom.leave();

                connection.close();
                setCurrentState("Login");

                output_txt.htmlText = "";
                input_txt.text = "";
            }

            private function onCreateRoomClicked():void
            {
            	// Ensure the room hasn't already been created
				if (currentRoom.getRoomID() == connection.getClientManager().self().getAttribute(null, "username"))
				{
					output_txt.htmlText = "<b>Room '" + currentRoom.getRoomID() + "' already exists.</b>";
					return;
				}

                currentRoom.removeMessageListener(CHAT_MESSAGE, chatMessageListener);
                removeRoomListeners();
                currentRoom.leave();
                currentRoom = connection.getRoomManager().createRoom(connection.getClientManager().self().getAttribute(null, "username"));
                currentRoom.addMessageListener(CHAT_MESSAGE, chatMessageListener);
                addRoomListeners();
                currentRoom.join();
                output_txt.htmlText = "<b>Creating room: " + currentRoom.getRoomID() + "...</b>";
            }

            private function onJoinRoomClicked():void
            {
                if (rooms_lst.selectedItem != null)
                {
                    currentRoom.removeMessageListener(CHAT_MESSAGE, chatMessageListener);
                    removeRoomListeners();
                    currentRoom.leave();
                    currentRoom = connection.getRoomManager().joinRoom(rooms_lst.selectedItem.toString());
                    currentRoom.addMessageListener(CHAT_MESSAGE, chatMessageListener);
                    addRoomListeners();
                    output_txt.htmlText = "<b>Joining room: " + currentRoom.getRoomID() + "...</b>";
                }
            }
        ]]>
    </mx:Script>
</mx:Application>

Final Results

A few last things based upon feedback I received from Colin…

1. You probably want to use a room qualifier for your roomIds. I could use something like “com.giantflyingsaucer.mainLobbyRoom”, etc. This way if your using TryUnion.com you can specifically check for those qualified roomIds that match your unique naming scheme and only show those to the users. This way you ignore any rooms created by other developers that your not interested in. It is also just good practice to use a naming convention like this even if your not using TryUnion.com.

2. You can add nice little features like when the user joins a room. You could do that with the RoomEvent.SYNCHRONIZE listener.

3. If you want to get the maximum amount of logging information while debugging you can do this:

// Add this import
import net.user1.logger.Logger;

// Set the level
connection.getLog().setLevel(Logger.DEBUG);

4. This chat application should have a label or something that displays the current room the user is in. You can get that information from the currentRoom variable.

My thanks to Colin and Derek for making another excellent product and for some great feedback on this article!

[ad name=”Google Adsense”]

Post to Twitter

This entry was posted in ActionScript, Adobe, AJAX, C#, Flex, Java, Online Games, Socket Server, Union Framework. Bookmark the permalink.

27 Responses to Building a multiuser chat application with the Union Platform and Flex Builder 3

  1. Chris says:

    I tried to do this tutorial but can’t get passed the login creation because the compile reads:

    Unable to load SWC reactor.swc

    I have tried different tutorials in both flash and Flex and I am getting nowhere… if you have a copy that isn’t currupt could you email it to me. It would be much appreciated…

    Thank you so much and great tutorial from what I have done so far

  2. Chad Lung says:

    @Chris,

    It sounds like you need to link to the reactor.swc file. The top of this article shows that with a screenshot.

    Chad

  3. Chris says:

    Nah wasn’t that had it all linked… problem was that IE8 was converting it to zip or somethng when I dled it… just dled it with firefox and it all seems to work now

    But now that I did the 2 tutorials on the Union Platforms website I will now do this lovely one since it has a little bit more to it…

    Thanks chad for trying to help though.

    Best,
    Chris

  4. Chris says:

    Chad got another question for you…

    How is it that you are removing the users when they close the browser windo my users keep staying. Another thing is I can’t get a flashvar to not read null when I pass it into the app… I am almost done with my chat but stuck on those 2 problems… as for the flashvars i have tried all techniques I know of and it is always reading null… but really just need to know the first part of this long drawn out question…

    Thanks,
    Chris

  5. Chad Lung says:

    @Chris,

    Are you using Flash or Flex?

    Chad

  6. arif says:

    i can’t get passed the login form, suddenly i “got connection close” warning

    and i got this error,,

    [IOErrorEvent type=”ioError” bubbles=false cancelable=false eventPhase=2 text=”Error #2031: Socket Error. URL: localhost”]

    can you help me?

    i’m using flex builder

  7. Chad Lung says:

    @arif,

    Can you supply more details?

    Chad

  8. nomad778 says:

    Will this chat work with FMS2 or FMS3. If not are they away that webcams can be added to this chat?

  9. Chad Lung says:

    @nomad778,

    This particular chat application is specific to Union and currently there is no webcam support for it.

    For webcam support you might want to look at Adobe’s Flash Collaboration Service as well as FMS:

    http://labs.adobe.com/technologies/afcs/

    Chad

  10. Angel says:

    hi chad im trying your application but i have a problem ,the problem is the same of arif ,I debug the problem and is a problem with the server not work or not find the server please canyou tell me somthing about the server i dont understend how work your application , i need explian the conexion of the server maybe more extendet please

  11. Chad Lung says:

    @Angel,

    You might want to go to the Union website to read about how the server works:

    http://unionplatform.com/

    They have some decent documentation there.

    Chad

  12. Edwin says:

    I got this same error as “ARIF”

    i can’t get passed the login form, suddenly i “got connection close” warning

    and i got this error,,

    [IOErrorEvent type=”ioError” bubbles=false cancelable=false eventPhase=2 text=”Error #2031: Socket Error. URL: localhost”]

    can you help me?

    i’m using flex builder…

    Moreover, i am using the connection.open(“tryunion.com”,9100)… does this cause any problem

  13. shrihari says:

    Hello i tried this tutorial.It is giving some error. i installed java 1.6 which is downloaded from above link given and i got that reactor.swc file also i included that also can you please clear my doubt.

  14. sampath says:

    I am getting a problem like this
    “1046: Type was not found or was not a compile-time constant: UConnectionEvent.”

  15. Angel says:

    hi is a good exmaple its work , only you have to see the new version of union and reactor,there are examples ,are really good ,only have to read the tutorial and ready a chat ready!!!!
    the website is http://www.unionplatform.com/ follow the tutorial in the page of union and ready!!!!!!!!!!

  16. sunil says:

    Hello Guys,

    I am trying to implement the multi user chat application.
    I copied entire code and even loaded SWC. However, I am receiving error messages in loading config.xml file.
    Do I need to write config.xml explicitly ?????
    If so, please help me to isolate this issue.

    Here is the error message :
    [SWF] F:\ACCORDION\MultiModeChat\bin-debug\MultiModeChat.swf – 1,208,222 bytes after decompression
    3/30/10 19:59:31.609 UTC+5.5 INFO: Flash Player Version: WIN 9,0,262,0 (debug version, security sandbox type: localTrusted)
    3/30/10 19:59:31.609 UTC+5.5 INFO: Union Client Version: Reactor 1.0.0 (Build 652)
    3/30/10 19:59:31.609 UTC+5.5 INFO: Client UPC Protocol Version: 1.6.0
    3/30/10 19:59:31.609 UTC+5.5 INFO: [CONNECTION_MANAGER] Ready timeout set to 10000 ms.
    3/30/10 19:59:31.609 UTC+5.5 INFO: [CONNECTION_MONITOR] Auto-reconnect frequency set to -1 ms.
    3/30/10 19:59:31.625 UTC+5.5 INFO: [CONNECTION_MONITOR] Connection timeout set to 60000 ms.
    3/30/10 19:59:31.625 UTC+5.5 INFO: [CONNECTION_MONITOR] Heartbeat frequency set to 10000 ms.
    3/30/10 19:59:31.625 UTC+5.5 INFO: [REACTOR] Initialization complete.
    3/30/10 19:59:31.625 UTC+5.5 INFO: [REACTOR] Loading config from config.xml.
    3/30/10 19:59:31.625 UTC+5.5 INFO: [REACTOR] Configuration file loaded.
    3/30/10 19:59:31.625 UTC+5.5 ERROR: [REACTOR] Could not parse configuration file. Illegal XML encountered. Settings not loaded. Error follows: TypeError: Error #1009: Cannot access a property or method of a null object reference.

    Thanks in advance.

    Regards,
    Sunil.

  17. Eman says:

    Hello,

    this is a cool tutorial. where i can download the unio server used in this tutorial so that i can test it on my pc.

    thanks.
    cheers.

  18. Chad Lung says:

    @Eman,

    The link to download is in the article: http://www.unionplatform.com/

    Chad

  19. Eman says:

    @Chad

    thanks for the help. I downloaded the latest server but when i run the chat apps i pop this error:

    ArgumentError: Error #1063: Argument count mismatch on CoreMessageListener/u66(). Expected 2, got 4.
    at Function/http://adobe.com/AS3/2006/builtin::apply()
    at net.user1.reactor::MessageManager/notifyMessageListeners()[/Users/colin/data/union/dev/Union 1.0/reactor/src/net/user1/reactor/MessageManager.as:563]
    at net.user1.reactor::MessageManager/upcReceivedListener()[/Users/colin/data/union/dev/Union 1.0/reactor/src/net/user1/reactor/MessageManager.as:248]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at net.user1.reactor::SocketManager/dataListener()[/Users/colin/data/union/dev/Union 1.0/reactor/src/net/user1/reactor/SocketManager.as:185]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at flash.net::XMLSocket/scanAndSendEvent()

    any idea how to fix this problem?

    thanks.

  20. Eman says:

    when i hit the login button, that error pops-up

    thanks.

  21. Chad Lung says:

    @Eman,

    Sounds like the Union API has maybe changed since my article was written. I know Colin and Derek have done a couple major releases since I wrote this article. You might want to work through their more up to date examples:

    http://www.unionplatform.com/?page_id=44
    http://www.unionplatform.com/?page_id=1216

    Chad

  22. Eman says:

    @Chad

    Is there a possibility that you could update your example with latest API. I like the way you present the chat application with joining and leaving the rooms.

    Many thanks.
    Cheers.

  23. Chad Lung says:

    #Eman,

    Sorry but I don’t have any plans right now to update this article.

    Chad

  24. Pingback: Getting Perl and Flex talking via XML | Giant Flying Saucer

  25. Madhumitha says:

    I m getting error when irun this code.
    1046: Type was not found or was not a compile-time constant: UConnectionEvent.

  26. Nagendra says:

    Hi,
    I need help i am developping chatting application similar to Gmail chatting using Flex and Blaze DS. its easy by using subtopics i have done it.

    but now my problem for exchanging messages both users should have opened their respective pop up windows for sending/receiving messages.

    i am stuck with, when user 1 sends a message to user 2 automatically the chat pop up window along with user 1 meesage needs to be opened at user 2 side,
    so that user 2 will come to know and he can proceed for chat.its similar to gmail chatt.

    i am very new to Flex.

    please help me or guide me to proceed forther. thanks in advance for your great help.

    nagendrakamisetti@gmail.com

  27. Chad Lung says:

    @Nagendra,

    You probably want to bounce these kinds of questions around in the Adobe developer forums.

    Chad

Comments are closed.