Hello!

This is a post to demonstrate how to use the eight protocol lib for NodeJS implementing a simple chat server/client. According with the documentation (see at: https://github.com/irineu/eight-protocol), let’s implement the basic structure of the lib for the server:

var protocol = require("eight-protocol");
var server =  new protocol.server(7890);

server.on('server_listening', function(){
    console.log("server is ready!");
});

server.on('client_connected', function(socketClient){
   //add some logic here
});

server.on("data", function(socketClient, header, dataBuffer){
    //add some logic here
});

server.on('client_close', function(socketClient){
    //add some logic here
});

In this task, i’m gonna implement the following logic:

  1. Each client, right after connect on the server, will be asked from the server to inform their name. I will use a transaction named ID to make this job
  2. If the name not be valid, the server will respond with a ERROR transaction, if be valid, the server will respond with a WELCOME transaction followed by a broadcast to all clients with a transaction named: MESSAGE to inform the new member in the chat room
  3. After the client receive the WELCOME transaction, it will be allowed to type messages and when the operator press the key “enter”, the message will be sent to the server in a MESSAGE transaction, then the server will broadcast it.
  4. Finally, if a client closes the connection with the server, the server will broadcast a message to inform the others and if the server be closed, all clientes will terminate the process.

In our scenario we need store all connections for broadcast latter,  i prefer create a map for store each connection based on the socket id, the lib auto generate an id after each connection and set the property dynamically in the socket variable. When the server receive a new connection i put the socket in the map and when the server lost a connection, i remove from it, both scenarios based on the events provided by de lib eight protocol api:

 

//A map for store active connections
var activeConnections = {};

server.on('client_connected', function(socketClient){
	//send a transaction for identify the user
	protocol.send(socketClient, {transaction : "ID", date : Date.now()}, "");

	//store a reference of the socket in a map
	activeConnections[socketClient.id] = socketClient;
	console.log("ONLINE USERS: "+Object.keys(activeConnections).length);
});

server.on('client_close', function(socketClient){
	//broadcast the goodbye message
	Object.keys(activeConnections).forEach(function(k){
		protocol.send(activeConnections[k], {transaction : "MESSAGE", date : Date.now()}, socketClient.name+" was left!");
	});
	//Delete the reference of the user in our map
    delete activeConnections[socketClient.id];
    console.log("ONLINE USERS: "+Object.keys(activeConnections).length)
});

Finally, the following code handle all transaction rules from the chat server:

server.on("data", function(socketClient, header, dataBuffer){

	//Based in a property (transaction) on header, we can handle de message:
	switch(header.transaction){
		case "MESSAGE":
			//check if the socket already have idendified
			if(!socketClient.name) return protocol.send(socket, {transaction : "ERROR", date : Date.now()}, "ACCESS DENIED :"+msg);

			//Broadcast the message
			Object.keys(activeConnections).forEach(function(k){
				protocol.send(activeConnections[k], {transaction : "MESSAGE", date : Date.now()}, socketClient.name+" says:" + dataBuffer.toString());
			});
		break;
		case "ID":

			//Get the name and check if is valid
			var name = dataBuffer.toString();
			if(name){
				socketClient.name = name;

				//send a transaction for the client for start typeing
				protocol.send(socketClient, {transaction : "WELCOME", date : Date.now()}, "");

				//Then broadcast the wellcome message
				Object.keys(activeConnections).forEach(function(k){
					protocol.send(activeConnections[k], {transaction : "MESSAGE", date : Date.now()}, socketClient.name+" entered on chat!");
				});
			}else{
				//send a message to input a valid name
				protocol.send(socketClient, {transaction : "ERROR", date : Date.now()}, "invalid name");
			}
		break;
		default:
			console.log("Unrecognized transaction "+ header.transaction);
			socketClient.end();
		break;
	}
});

I’ve added that example inside the examples folder of the eight-protocol on my GitHub: https://github.com/irineu/eight-protocol/tree/master/examples/chat