In the first part, we created Login and registration page, did all the necessary server and client setup and created config files required for our Nodejs server. In this part, we will implement Homepage of our Private Real Time chatting app.
I have divided implementation of homepage into four parts as shown below,
- Connecting user to the socket server.
- Checking user’s session again once a user logs into application and redirects to the homepage.
- Displaying User’s Chat list with current online users.
- Sending message unique users.
But as of now, in this part, we will complete three points out of four points listed above. The last pointSending message unique userswill be covered in the3rd partof the application.
1. Connecting user to the socket server
Now, the user is logged in into the application, the first step is to connect that user to socket server when user redirects to the homepage.
=>Inside thehome.controller.js
, write down the below line, this line will do the required work for us, which is defined inside the AppService class.
=>Since we already created AppService class in the first part and As I explained in point number 7 of the first part, where we have talked about each method’s usage.
home.controller.js :
// Connect the user to socket server appService.connectSocketServer(UserId);
=>Now when user will connect to a socket, we will update the socket id of the user by executing the MySql query. In order to do this, we will write a middleware in thesocket.js
file.
=>This middleware will execute before any socket event would execute and it will socket the new socket id every time socket server will start.
=>In the below code, inside the methodsocketConfig()
will write this middleware.
socket.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; const path = require('path'); const helper = require('./helper'); class Socket{ constructor(socket){ this.io = socket; } socketEvents(){ this.io.on('connection', (socket) => { /** * We will Socket socket Events here. */ }); } socketConfig(){ this.io.use( async (socket, next) => { let userId = socket.request._query['userId']; let userSocketId = socket.id; const response = await helper.addSocketId( userId, userSocketId); if(response && response !== null){ next(); }else{ console.error(`Socket connection failed, for user Id ${userId}.`); } }); this.socketEvents(); } } module.exports = Socket;
=>If you notice we have calledaddSocketId()
method of the helper class.
=>In this method, we will simply perform an update MySql query by usingsocketId
anduserId
, so copy the below method in the helper class.
helper.js:
/** * Real Time chatting app * @author Shashank Tiwari */async addSocketId(userId, userSocketId){ try { return await this.db.query(`UPDATE user SET socketid = ?, online= ? WHERE id = ?`, [userSocketId,'Y',userId]); } catch (error) { console.log(error); return null; } }
2. Checking user’s session
It is very important that no one should able to send a message without login and to achieve this we will check session of logged in user and if that user is not logged into the application then we will redirect that user to the Login page again. Now to do that we have to use controller file on the homepage.
=>Here we will consumehttCall()
method of AppService class, which will senduserId
of the user over the HTTP call.
=>In the response, it will return whether the user is logged in or not.
/** * Real Time chatting app * @author Shashank Tiwari */ 'user strict'; app.controller('homeController', function ($scope, $routeParams, $location, appService){ const UserId = $routeParams.userId; $scope.data = { username: '', chatlist: [], selectedFriendId: null, selectedFriendName: null, messages: [] }; appService.connectSocketServer(UserId); appService.httpCall({ url: '/userSessionCheck', params: { 'userId': UserId } }) .then((response) => { $scope.data.username = response.username; /* * Code for Real time chat list update goes here */ }) .catch((error) => { console.log(error.message); $scope.$apply( () =>{ $location.path(`/`); }); }); });
=>The above code looks easy to understand, the HTTP call is made to/userSessionCheck
route with UserId as route parameter.
=>Now we will create a route named as/userSessionCheck
, using express inside theroutes.js
file, take a look below,
routes.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; this.app.post('/userSessionCheck', async (request,response) =>{ const userId = request.body.userId; const sessionCheckResponse = {} if (userId == '') { sessionCheckResponse.error = true; sessionCheckResponse.message = `User Id cant be empty.`; response.status(412).json(sessionCheckResponse); }else{ const username = await helper.userSessionCheck(userId); if (username === null || username === '') { sessionCheckResponse.error = true; sessionCheckResponse.message = `User is not logged in.`; response.status(401).json(sessionCheckResponse); }else{ sessionCheckResponse.error = false; sessionCheckResponse.username = username; sessionCheckResponse.message = `User logged in.`; response.status(200).json(sessionCheckResponse); } } });
=>If you notice we have useduserSessionCheck()
method of the Helper class, In this method, we basically check the online status of the user.
=>We update the online column, in socket.io middleware when the user connects to the socket server. If the online status of the user found asY
then it returns the username OR if the online status isN
then it will returnnull
.
helper.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; async userSessionCheck(userId){ try { const result = await this.db.query(`SELECT online,username FROM user WHERE id = ? AND online = ?`, [userId,'Y']); if(result !== null){ return result[0]['username']; }else{ return null; } } catch (error) { return null; } }
3. Displaying user’s chat list
Our user is connected to socket server and logged into the application, now it’s time to fetch the chat list. In this application, we will show only those users on the chat list, which are already logged into the application and connected to socket.io. In order to do this, we will write a MySql Query in a helper class and we will consume this in our socket events.
=>So The first step would be to emit an event from a client that, the user is ready to receive chat list.
=>When Server receives that event, it will respond back with chat list data in the form event.
=>Once a client receives the chat list, AngularJs will render the chat list by reading the data received through that server event.
home.controller.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; appService.httpCall({ url: '/userSessionCheck', params: { 'userId': UserId } }) .then((response) => { $scope.data.username = response.username; appService.socketEmit(`chat-list`, UserId); appService.socketOn('chat-list-response', (response) => { $scope.$apply( () =>{ if (!response.error) { if (response.singleUser) { /* * Removing duplicate user from chat list array */ if ($scope.data.chatlist.length > 0) { $scope.data.chatlist = $scope.data.chatlist.filter(function (obj) { return obj.id !== response.chatList.id; }); } /* * Adding new online user into chat list array */ $scope.data.chatlist.push(response.chatList); } else if (response.userDisconnected) { /* * Removing a user from chat list, if user goes offline */ $scope.data.chatlist = $scope.data.chatlist.filter(function (obj) { return obj.socketid !== response.socketId; }); } else { /* * Updating entire chatlist if user logs in */ $scope.data.chatlist = response.chatList; } } else { alert(`Faild to load Chat list`); } }); }); /* * Code to get the real time messages goes here */ }) .catch((error) => { console.log(error.message); $scope.$apply( () =>{ $location.path(`/`); }); });
Explanation :
Inside thehttpCall()
method, we are updating the list of the user, which is defined into the AppService class. For example, If a new user logs in into the system or an existing user goes offline in both the cases we will update the list of online users.
Now, here I am emitting the complete list of users to the user who justlogged into the system.
And, the for the rest of users, those who are already online will get the users information whowent offlineorjust logged in.
This makes sense, right? Because sending the complete list of online users to each and every user is not good.
Now if you see the above code there iselse if()
code block,for the below task.
- If the response from the socket event contains thesingleUser propertywhich means the new socket connection is established.
- If the response contains theuserDisconnected propertythen it means the user went and offline remove the user from the chat list.
- And at the end,In the else condition we will update the list of users in the else block.
Alright, that was the AngularJs part let’s take a look at the markup for the same. Openhome.htmland write down the below markup.
=>The markup show below is straight to understand and we are using the $scope variable to ender the chat list.
home.html:
<!-- Real Time chatting app @author Shashank Tiwari --> <div class="home-page"> <!-- Home page header starts --> <div class="home-header"> <p class="welcome-user">Welcome {{ data.username }}</p> <span class="logout-user" ng-click="logout()"> <i class="fa fa-power-off" aria-hidden="true"></i> </span> </div> <!-- Home page header ends --> <!-- Home page body start --> <div class="home-body"> <div class="row"> <!-- Message Area Markup starts --> <div class="col-md-8"> <!-- Markup for Messages goes here --> </div> <!-- Message Area Markup ends --> <!-- Chat list Markup starts --> <div class="col-md-4"> <div class="chat-list-container"> <p class="chat-list-heading"><i class="fa fa-list" aria-hidden="true"></i> <span >Chat list</span> </p> <div class="chat-list"> <ul class="list-group" ng-if="data.chatlist.length > 0"> <li class="list-group-item" ng-repeat="friend in data.chatlist" ng-class="{'active':friend.id == data.selectedFriendId}" >{{friend.username}}</li> </ul> <div class="alert alert-info" ng-if="data.chatlist.length === 0"> <strong>No one is online to chat, ask someone to Login.</strong> </div> </div> </div> </div> <!-- Chat List Markup ends --> </div> </div> <!-- Home page body start --> </div>
Let’s see what we have to do for socket events to complete this feature. As you all know we will write our socket events insocket.jsfile, so open it and write down the below code.
=>In the below code we will send an event to AngulaJs along chat list data, by consuming theHelper
class.
socket.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; socketEvents(){ this.io.on('connection', (socket) => { /** * get the user's Chat list */ socket.on('chat-list', async (userId) => { let chatListResponse = {}; if (userId === '' && (typeof userId !== 'string' || typeof userId !== 'number')) { chatListResponse.error = true; chatListResponse.message = `User does not exits.`; this.io.emit('chat-list-response',chatListResponse); }else{ const result = await helper.getChatList(userId, socket.id); this.io.to(socket.id).emit('chat-list-response', { error: result !== null ? false : true, singleUser: false, chatList: result.chatlist }); socket.broadcast.emit('chat-list-response', { error: result !== null ? false : true, singleUser: true, chatList: result.userinfo }); } }); }); }
=>We are fetching the list of the user based on details we have in our database, so to do this we will run a MySql query. This query is written insidegetChatList()
method of theHelper
class.
=>Now openhelper.jsand write down the below code, In the below query we will fetch inform based ononline status
andsocket.id
.
helper.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; getChatList(userId, userSocketId){ try { return Promise.all([ this.db.query(`SELECT id,username,online,socketid FROM user WHERE id = ?`, [userId]), this.db.query(`SELECT id,username,online,socketid FROM user WHERE online = ? and socketid != ?`, ['Y',userSocketId]) ]).then( (response) => { return { userinfo : response[0].length > 0 ? response[0][0] : response[0], chatlist : response[1] }; }).catch( (error) => { console.warn(error); return (null); }); } catch (error) { console.warn(error); return null; } }
For this part that’s it, in this article, we implemented the chat list feature and In thenext part, we will implement the real-time messaging feature. And finally, the users will able to chat with each other.
See you in next article and if you like this article please do share.
why you have not used mongodb , Pls help me understand ,when we should use mongoDB ,and when we can use Mysql with node js
Yeah, actually I wrote this article for beginners to understand how nodejs works, how to use mysql in Nodejs and how to create a basic chat app.
In upcoming month I will update this article where I will use either MongoDB or RethinkDB.
Can you please provide some article or information ,when to use mongoDB over Mysql with nodejs.
Please help me understanding this
Well, This depends upon your project what kind of project you are making.
Open below link & read first three links => https://www.google.co.in/?q=when%20to%20use%20mongodb%20over%20mysql%20nodejs
I think,you will get clear idea about this.