Introduction
What about a chat portal which offers 100% privacy? Yes, in practice it is impossible but at least can't we manage not to store users' personal chat messages in server?
This article is an attempt to design such a chat system. I am using what ever language features coming to mind so please keep in mind that there are better and other suitable options available.
Solution Design
Requirement: A very simple chat program which allows individuals to chat each other, while not keeping their personal messages in database.
Solution: Keep the messages temperorily in an in-memory object until it is delivered to the other user or until a specific time delay, say 2 minutes is expired.
Technical Details:
Here, a static List<> is used to temperorily store messages. Browser will pull messages from this object asynchronously in defined intervals, eg: 3 seconds and show in browser. Once the message is read from the object those will be instantly removed. Orphen messages in list also will be removed on defined intervals so that the variable memory consumption remains minimum.
Technologies and features used in the sample application are:
- HTML5 and CSS
- jQuery - version: 1.10.2
- ASP.NET with C# under .NET Framework 4.5
In this sample, no any sophisticated technologies like WebAPI are used so the funcationality can be implemented in any language easily.
P2P chat involves chat between two persons. Let me call them you and a stranger.
Using the code
Client side code
Below are the PUSH and PULL chat message handlers written in jQuery.
$(function () {
$("#t").focus();
$("#s").click(function () {
if ($("#t").val().trim() != "") {
u1 = $("#u1").val();
u2 = $("#u2").val();
$.ajax({
url: "e.aspx",
type: "POST",
data: { c: "p", u1: u1, u2: u2, t: escape($("#t").val()) }
});
}
$("#t").val("").focus();
});
});
function pull() {
u1 = $("#u1").val();
u2 = $("#u2").val();
if (u1.trim() == "" || u2.trim() == "") return;
$.ajax({
url: "e.aspx",
type: "POST",
data: { c: "g", u1: u1, u2:u2 }
})
.done(function (d) {
$.each($.parseJSON(d), function (k, v) {
var cls = "cu";
var me = v.wu;
if (v.wu == u1) {
cls = "cu1";
}
$("#c").html($("#c").html() + " <span class='" + cls + "'>" + me + ": " + v.msg + "</span><br />");
$("#c").scrollTop(1000000);
});
});
}
And, pull() is executed every X seconds, eg:
setInterval(pull, 1000);
Server side code
Next code shows how to handle PULL and PUSH commands triggered from browser.
First, a chat message record looks like this:
public class REC
{
public string user1 { get; set; } public string user2 { get; set; } public string msg { get; set; } public string wu { get; set; } public DateTime dt { get; set; } }
Below is the declaration of our in-memory storage object:
public static List<REC> data;
Next comes PUSH and PULL handlers.
string ret = null;
u1 = Request["u1"].ToString().ToLower();
u2 = Request["u2"].ToString().ToLower();
switch (Request["c"])
{
case "p":
var t = Uri.UnescapeDataString(Request["t"].ToString());
DateTime dt = DateTime.UtcNow;
data.Add(new REC(u1, u2, t, u1, dt));
data.Add(new REC(u2, u1, t, u1, dt));
ret = "1";
break;
case "g":
var z = data.Where(x => (x.user1.Contains(u1)));
ret = new JavaScriptSerializer().Serialize(z);
data.RemoveAll(x => (x.user1.Contains(u1)));
data.RemoveAll(x => (DateTime.UtcNow - x.dt).TotalMinutes > 2); break;
}
Response.Write(ret);
PUSH: Adds the incoming chat message to data. You can see, two records are inserted - one for you and other for stanger.
PULL: Retrieves the chat message of particular user. Instatly, it removes it from the data object after retrieval. Second RemoveAll() lamda removes any messages which are of orphen in nature. Due to network issues or browser closing, there might be unused messages pending delivery.
Points of Remember
- A Static List<> is what came to my mind at first but note that using static is not a recomended method. It can loose values if the app domain is recycled, it will not work for load balanced environments, its storage capability depends on how much memory your machine hold etc. Please explore other ways of in-memory storage
- This sample application is not scalable unless modified for scalability
- This design does not consider group chats.
- If a third person uses one of the first or second user's nick, the system will behave weird
- No proper exception handling in sample code
- Coding best practices hardly followed
Demo
I have hosted a sample demo here. But I dont know how long this will be available, so please do not complain if the link is not working.