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
) 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"?> <mx :Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()"> </mx><mx :Script> < ![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 += "<i>Client: Connected to server" + "<br />"; } private function ReconnectHandler(event:CloseEvent):void { if (event.detail == Alert.YES) init(); } private function onClose(event:Event):void { board.htmlText += "<i>Disconnected from server</i>" + "<br />"; Alert.show("Reconnect to the chat?", "Reconnect?", (Alert.YES | Alert.NO), this, ReconnectHandler); } private function onEvent(event:Event):void { board.htmlText += "Error" + "<br />"; trace(event); } private function onData(event:DataEvent):void { board.htmlText += event.text; } private function sendMesg():void { socket.send(username.text+ ': <font color="#' + cp.selectedColor.toString(16) + '">' + mesg.text + "</font>\n"); mesg.text = ""; } ]]> </mx> <mx :Style> .marginstyle { paddingTop:12; paddingBottom:12; paddingLeft: 12; paddingRight: 12; } .spacestyle { paddingTop:2; paddingBottom:2; paddingLeft: 2; paddingRight: 2; } </mx> <mx :Panel title="chatterbox" styleName="marginstyle"> <mx :TextArea editable="false" id="board" text="" height="400" width="600" color="#0000FF" styleName="spacestyle"/> </mx><mx :HBox> <mx :TextArea id="username" text="guest" height="20" width="50%"/> <mx :ColorPicker id="cp" height="20" width="20"/> </mx> <mx :HBox> <mx :TextArea id="mesg" height="50" width="500" styleName="spacestyle"/> <mx :Button label="Send" click="sendMesg()"/> </mx>
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 = "\000" 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 "<i>#{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 "<i>#{MSGS["byebye"]}</i>" + EOF local_session.close data = "<i>#{name} disconnected from the server</i>" + EOF end end sessions.each do |s| begin s.puts "<b>#{name}</b>: #{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.