Multiuser Chat using Flex and Ruby

For the last few days I had been googling for some good help for coding networked flash applications for a pet project of mine. Mostly using Flex & Ruby. There have been quite a few I saw – made with flash and using Java; but nothing to my personal liking. And hence I set to build a prototype of my own.

Being a coder and a poor (financially & aesthetically & skillfully :D) visual designer, I am totally in love with Flex for the visual quality it brings to the flash applications i can build.

Ruby for the beauty it brings to the code; but then the code is only as good as the coder. And for cooking up a quick prototype, no language has been so good of course except for Perl (for me ofcourse).

Multiplayer – thats a tricky question. Flash cannot support P2P (peer-to-peer) applications as yet. So the best choice available is to use a client-server architecture – the good ole’ sockets.

Hence using the code from a lot of different places and porting them from other languages, I managed to quickly cook up a Flex multiuser chat application with a ruby backend. Without further ado, into the code.

The server right now runs on the 9999 port of the localhost and the client connects to the same host and port. If you plan to test it on a hosting server, make sure you change the host and the port.

Note: My wordpress code plugin is fucking up the mxml code. For this part you may just download the zip file and use the client.mxml.

The Flex client:

< ?xml version="1.0"?>

	
		< ![CDATA[
			import flash.display.Sprite;
		
			import flash.net.XMLSocket;
			import flash.events.Event;
			import flash.events.DataEvent;
			import flash.events.IOErrorEvent;
			import mx.events.CloseEvent;
			import mx.controls.Alert;
	
			public var socket:XMLSocket = new XMLSocket();
			private var host:String     = "localhost";
			private var port:int        = 9999;
	
			public function init():void	{
				socket.connect(host, port);
	
				socket.addEventListener(DataEvent.DATA, onData);
				socket.addEventListener(Event.CONNECT, onConnect);
				socket.addEventListener(Event.CLOSE, onClose);
				socket.addEventListener(IOErrorEvent.IO_ERROR, onEvent);
			}
			
			private function onConnect(event:Event):void	{
				board.htmlText += "Client: Connected to server" + "
"; } private function ReconnectHandler(event:CloseEvent):void { if (event.detail == Alert.YES) init(); } private function onClose(event:Event):void { board.htmlText += "Disconnected from server" + "
"; Alert.show("Reconnect to the chat?", "Reconnect?", (Alert.YES | Alert.NO), this, ReconnectHandler); } private function onEvent(event:Event):void { board.htmlText += "Error" + "
"; trace(event); } private function onData(event:DataEvent):void { board.htmlText += event.text; } private function sendMesg():void { socket.send(username.text+ ': ' + mesg.text + "n"); mesg.text = ""; } ]]>
.marginstyle { paddingTop:12; paddingBottom:12; paddingLeft: 12; paddingRight: 12; } .spacestyle { paddingTop:2; paddingBottom:2; paddingLeft: 2; paddingRight: 2; }

To compile it to a swf
Assuming you already have the free Flex SDK just use
$> mxmlc client.mxml
which will create a client.swf file for you.

Multiuser Ruby chat server:

#!/usr/bin/ruby
require 'socket'

MSGS = {"init"    => "Server started. Waiting for connections...",
        "welcome" => "Welcome! type EXIT to quit",
        "byebye"  => "Disconnected from server"}

EOF     = "00"
HOST		= "localhost"
PORT		= 9999

server	= TCPServer.new(HOST, PORT)
puts MSGS["init"] 

# array to store all the active connections
sessions = []
while (session = server.accept)
  # push the current session(socket) in the array
  sessions < < session
  # initialize a new thead for each connection
  Thread.new(session) do |local_session|
		local_session.puts "#{MSGS["welcome"]}" + EOF

    # each time a client sends some data send it to all the connections
    while(true)
      data = local_session.gets
			
			if !data.nil?
				delim_pos = data.index(":")
				name      = data[0..delim_pos-1]
				data      = data[delim_pos+1..-1]

				if data[0] == EOF
					data = data[1..-1] 
				elsif data.chomp == "EXIT"
					sessions.delete(local_session)
					local_session.puts "#{MSGS["byebye"]}" + EOF
					local_session.close
					
					data = "#{name} disconnected from the server" + EOF
				end
			end

      sessions.each do |s| 
        begin
          s.puts "#{name}: #{data.chomp}" + EOF
        rescue Errno::ECONNRESET
          # an exception is raised, that means the connection to the client is broken
          sessions.delete(s)
        end
      end
    end
  end
end

To Run
User ruby chat_server.rb

Source Code: Download here. It contains a simple single user server – java & ruby versions [simpleServer.java & server.rb], a multiuser server [chat_server.rb] and the client [client.mxml].

Anyone, any doubts can leave a comment.