Wednesday, March 16, 2011

Chat Application In Asp.net c#

Use this Global Class Application For Developing Chat Engine

using System;

using System.Threading ;

using System.Web;

using System.Collections;

using System.Collections.Specialized;

using System.Text;

namespace ASPNETChat

{

    /// <summary>

    /// The business logic of the chat application

    /// </summary>

    public class ChatEngine

    {

        private static Hashtable Rooms = new Hashtable(40);

        public ChatEngine()

        {

        }


        /// <summary>

        /// Deletes the empty chat rooms

        /// </summary>

        /// <param name="state"></param>

        public static void CleanChatRooms(object state)

        {

            Monitor.Enter(Rooms);

            foreach(object key in Rooms.Keys)

            {

                ChatRoom room=(ChatRoom)Rooms[key.ToString()];

                room.ExpireUsers(100);

                if (room.IsEmpty())

                {

                    room.Dispose();

                    Rooms.Remove(key.ToString());

                }

            }

            Monitor.Exit(Rooms);

        }

        /// <summary>

        /// Returns the chat room for this two users or create a new one if nothing exists

        /// </summary>

        /// <param name="user1ID"></param>

        /// <param name="user2ID"></param>

        /// <returns></returns>

        public static ChatRoom GetRoom(string user1ID,string user2ID)

        {

            return GetRoom(user1ID,"",user2ID,"");

        }

        /// <summary>

        /// Returns or creats a chat room for these two users or create a new one if nothing exists

        /// </summary>

        /// <param name="user1ID"></param>

        /// <param name="user1Name"></param>

        /// <param name="user2ID"></param>

        /// <param name="user2Name"></param>

        /// <returns></returns>

        private static ChatRoom GetRoom(string user1ID,string user1Name,string user2ID,string user2Name)

        {

            ChatRoom room=null;

            string rid1=CreateRoomID(user1ID,user2ID);

            string rid2=CreateRoomID(user2ID,user1ID);

            Monitor.Enter(Rooms);


            if (Rooms.Contains(rid1))

                room=(ChatRoom)Rooms[rid1];

            else

            {

                if (Rooms.Contains(rid2))

                    room=(ChatRoom)Rooms[rid2];

                else

                {

                    //if (user1Name=="" && user2Name=="")

                    // return null;

                    //else

                    room=new ChatRoom(user1ID,user1Name,user2ID,user2Name);

                    Rooms.Add(rid1,room);

                }


            }

            Monitor.Exit(Rooms);

            return room;

        }


        #region Room ID,User IDs Manipulation

        /// <summary>

        /// Creates the room id using the ids of the two users

        /// </summary>

        /// <param name="user1"></param>

        /// <param name="user2"></param>

        /// <returns></returns>

        public static string CreateRoomID(string user1,string user2)

        {


            user1=user1.ToUpper();

            user2=user2.ToUpper();

            return user1+";"+user2;

        }

        #endregion

        #region Delete Room

        /// <summary>

        /// Deletes the specified room

        /// </summary>

        /// <param name="roomID"></param>

        public static void DeleteRoom(string roomID)

        {

            Monitor.Enter(Rooms);

            ChatRoom room=(ChatRoom)Rooms[roomID];

            room.Dispose();

            Rooms.Remove(roomID);

            Monitor.Exit(Rooms);

        }

        public static void DeleteRoom(string user1id,string user2id)

        {

            DeleteRoom(CreateRoomID(user1id,user2id));

        }

        #endregion

    }




    public class ChatRoom : IDisposable

    {

        //public Hashtable activeUsers = null;

        public ArrayList messages = null;

        public string RoomID;

        private ChatUser FirstUser;

        private ChatUser SecondUser;

        public void Dispose()

        {


            this.messages.Clear();

            this.RoomID="";

            this.FirstUser.Dispose();

            this.SecondUser.Dispose();

        }

        /// <summary>

        /// Returns the user with the specified id

        /// </summary>

        /// <param name="userID"></param>

        /// <returns></returns>

        public ChatUser GetUser(string userID)

        {

            userID=userID.ToUpper();

            if (FirstUser.UserID.ToUpper()==userID)

                return FirstUser;

            else

                return SecondUser;

        }


        #region constructors

        public ChatRoom(string user1ID,string user1Name,string user2ID,string user2Name)

        {

            this.messages = new ArrayList();

            this.RoomID=ChatEngine.CreateRoomID(user1ID,user2ID);

            this.FirstUser=new ChatUser(user1ID,user1Name);

            this.SecondUser=new ChatUser(user2ID,user2Name);

        }

        #endregion


        /// <summary>

        /// Determines if the users of the room are active or not

        /// </summary>

        /// <returns></returns>

        public bool IsEmpty()

        {

            lock(this)

            {

                if (this.FirstUser.IsActive==false&& this.SecondUser.IsActive==false)

                    return true;

                else

                    return false;

            }

        }



        #region Operations Join,Send,Leave

        //

        /// <summary>

        /// Marks the user as inactive

        /// </summary>

        /// <param name="userID"></param>

        /// <returns></returns>

        public string LeaveRoom(string userID)

        {

            //deactivate user

            ChatUser user=this.GetUser(userID);

            user.IsActive=false;

            user.LastSeen=DateTime.Now;


            //Add leaving message

            Message msg = new Message(user.UserName ,"",MsgType.Left);

            this.AddMsg(msg);

            //Get all the messages to the user

            int lastMsgID;

            ArrayList previousMsgs= this.GetMessagesSince( user.LastMessageReceived,out lastMsgID);

            user.LastMessageReceived=lastMsgID;

            //return the messages to the user

            string str=GenerateMessagesString(previousMsgs);

            if (IsEmpty())

                ChatEngine.DeleteRoom(this.RoomID);

            return "";

        }

        /// <summary>

        /// Activates the user and adds a join message to the room

        /// </summary>

        /// <param name="userID"></param>

        /// <param name="userName"></param>

        /// <returns>All the messages sent in the room</returns>

        public string JoinRoom(string userID,string userName)

        {

            //activate user

            ChatUser user=this.GetUser(userID);

            user.IsActive=true;

            user.UserName=userName;

            user.LastSeen=DateTime.Now;

            //Add join message

            Message msg=new Message(user.UserName ,"",MsgType.Join);

            this.AddMsg(msg);


            //Get all the messages to the user

            int lastMsgID;

            ArrayList previousMessages=this.GetMessagesSince(-1,out lastMsgID);

            user.LastMessageReceived=lastMsgID;


            //return the messages to the user

            string str=GenerateMessagesString(previousMessages);

            return str;

        }

        /// <summary>

        /// Adds a message in the room

        /// </summary>

        /// <param name="strMsg"></param>

        /// <param name="senderID"></param>

        /// <param name="toUserID"></param>

        /// <returns>All the messages sent from the other user from the last time the user sent a message</returns>

        public string SendMessage(string strMsg,string senderID,string toUserID)

        {

            ChatUser user=this.GetUser(senderID);

            Message msg=new Message(user.UserName ,strMsg,MsgType.Msg);

            user.LastSeen=DateTime.Now;

            this.ExpireUsers(100);

            this.AddMsg(msg);

            int lastMsgID;

            ArrayList previousMsgs= this.GetMessagesSince( user.LastMessageReceived,out lastMsgID);

            if (lastMsgID!=-1)

                user.LastMessageReceived=lastMsgID;

            string res=this.GenerateMessagesString(previousMsgs);

            return res;

        }

        #endregion

        /// <summary>

        /// Removes the users that hasn't sent any message during the last window secondes

        /// </summary>

        /// <param name="window">time in secondes</param>

        public void ExpireUsers(int window)

        {

            lock(this)

            {

                if (this.FirstUser.LastSeen != System.DateTime.MinValue )

                {

                    TimeSpan span = DateTime.Now - this.FirstUser.LastSeen;

                    if (span.TotalSeconds > window && this.FirstUser.IsActive!=false)

                    {

                        this.LeaveRoom(this.FirstUser.UserID);

                    }

                }

                if (this.SecondUser.LastSeen != System.DateTime.MinValue )

                {


                    TimeSpan span = DateTime.Now - this.SecondUser.LastSeen;

                    if (span.TotalSeconds > window && this.SecondUser.IsActive!=false)

                    {

                        this.LeaveRoom(this.SecondUser.UserID);

                    }

                }

            }

        }

        /// <summary>

        /// Adds a message to the room

        /// <param name="msg"></param>

        /// <returns> the id of the new message</returns>

        public int AddMsg(Message msg)

        {

            int count;

            lock(messages)

            {

                count = messages.Count;

                messages.Add(msg);

            }

            return count;

        }

        /// <summary>

        /// Iterates over the messages array calling ToString() for each message

        /// </summary>

        /// <param name="msgs"></param>

        /// <returns></returns>

        private string GenerateMessagesString(ArrayList msgs)

        {

            string res="";

            for (int i=0;i<msgs.Count;i++)

            {

                res+=((Message)msgs[i]).ToString()+"\n";

            }

            return res;

        }

        /// <summary>

        /// Returns an array that contains all messages sent after the message with id=msgid

        /// </summary>

        /// <param name="msgid">The id of the message after which all the message will be retuned </param>

        /// <param name="lastMsgID">the id of the last message returned</param>

        /// <returns></returns>

        public ArrayList GetMessagesSince(int msgid,out int lastMsgID)

        {

            lock(messages)

            {

                if ((messages.Count) <= (msgid+1))

                    lastMsgID=-1;

                else

                    lastMsgID=messages.Count-1;

                return messages.GetRange(msgid+1 , messages.Count - (msgid+1));

            }

        }


        /// <summary>

        /// Returns all the messages sent since the last message the user received

        /// </summary>

        /// <param name="userID"></param>

        /// <returns></returns>

        public string UpdateUser(string userID)

        {

            ChatUser user=this.GetUser(userID);

            user.LastSeen=DateTime.Now;

            this.ExpireUsers(100);

            int lastMsgID;

            ArrayList previousMsgs= this.GetMessagesSince( user.LastMessageReceived,out lastMsgID);

            if (lastMsgID!=-1)

                user.LastMessageReceived=lastMsgID;

            string res=this.GenerateMessagesString(previousMsgs);

            return res;

        }

    }

    #region the ChatUser Class

    public class ChatUser : IDisposable

    {

        public string UserID;

        public string UserName;

        public bool IsActive;

        public DateTime LastSeen;

        public int LastMessageReceived;

        public ChatUser(string id,string userName)

        {

            this.UserID=id;

            this.IsActive=false;

            this.LastSeen=DateTime.MinValue ;

            this.UserName=userName;

            this.LastMessageReceived=0;

        }

        public void Dispose()

        {

            this.UserID="";

            this.IsActive=false;

            this.LastSeen=DateTime.MinValue ;

            this.UserName="";

            this.LastMessageReceived=0;

        }

    }

    #endregion

    #region the Message Class

    public class Message

    {

        public string user;

        public string msg;

        public MsgType type;


        public Message(string _user, string _msg, MsgType _type)

        {

            user = _user;

            msg = _msg;

            type = _type;

        }

        public override string ToString()

        {

            switch(this.type)

            {

                case MsgType.Msg:

                    return this.user+" says: "+this.msg;

                case MsgType.Join :

                    return this.user + " has joined the room";

                case MsgType.Left :

                    return this.user + " has left the room";

            }

            return "";

        }


        public Message(string _user, MsgType _type) : this(_user, "", _type) { }

        public Message(MsgType _type) : this("", "", _type) { }

    }

    public enum MsgType { Msg, Start, Join, Left, Action }

    #endregion

}