Friday, April 17, 2020

Use WebSocket(socket.io) in node-angular application

I modern web application It is most useful and required to display data in real-time without refresh page. to overcome this problem we can use ajax but by using ajax we need to send ajax request continuously as defined some second. so it is not good to send the request to a server in every defined second because it may increase unusable traffic and consume more and more bandwidth. So the best way is to use socket.io (WebSocket)

By using socket.io we can get data in real-time and we can also send real-time data to particular users or all users. and we can also get a message or data directly from the server without sending any request means we can send requests from another pc and get a response in another pc.

The main use of  WebSocket(socket.io) is to get realtime notifications and to make real-time chat applications.

Here we will discuss, how to use socket.io (WebSocket) in nodejs and angular web application (mean stack) application.

Right now we create one simple demo for send message from the client to server and get a response from a server to client and display in page using nodejs version12 and angular version8

Integrating/Installing Socket.io
npm install socket.io-client --save
npm install @types/socket.io-client --save

index.js (in Server side) (C:\projects\myProject\index.js)
/*
 * @Author: Laxman Chavda
 * @Date:  2020-04-17 12:30:00 PM
 * @Last Modified by: Laxman  Chavda
 * @Last Modified time: 2020-04-17 12:30:00 PM
 * @Purpose : Server side main starting file
 */

"use strict";
var express = require("express");
var https = require('https');
var http = require("http");
var fs = require('fs');
var app = express();
var config, httpserver, callSocketDir;

/**
 * @description all process variables
 */

require("./server/config/vars")(app, fs);
config = require("./server/config/config.js")(app, express);
callSocketDir = './server/socket';

/**
 *@description Instantiation of an app, create clusters of an process
 */
httpserver = http.createServer(app).listen(3000, function (req, res) {
    console.log('Project is listening on port ' + 3000 + ", proccess id is " + process.pid + '!');
});

require(callSocketDir)(app, httpserver);

Here you can include socket file using callSocketDir = './server/socket'; and path may be different as per your project configuration on the server-side. and put require(callSocketDir)(app, httpserver); in last line.

socket.js (in Server side) (C:\projects\myProject\socket.js)
/*
 * @Author: Laxman chavda
 * @Date:  2020-04-17 12:30:00 PM
 * @Last Modified by:   Laxman chavda
 * @Last Modified time: 2020-04-17 12:30:00 PM
 * @Purpose : Custom socket events
 */

'use strict';
var logger = require("./config/log");
//var jwt = require("jsonwebtoken");
//var User = require("./app/data/models/user"); // Here you can add any models for do any operations like as add, edit or delete data

/**
 * @description socket.io connnections
 */
module.exports = function(app, httpServer) {

    //var socketioJWT = require('socketio-jwt');
    var io = require("socket.io").listen(httpServer);
    var clients = [];
    var connectedClientSocketIds = []; //for store socket all opened ids.
    var clientsStatus = {};
 
    // io.use(socketioJWT.authorize({
    //     secret: global.hzConfig.jwtPrivateKey,
    //     handshake: true
    // }));

    /**
     * @description Socket connection in when user going to online
     */
    io.sockets.on("connect", function(socket) {
     
        var cId = socket.decoded_token.id;
        var lastFriendsConnected = socket.decoded_token.id;
        logger.log("info", cId + " is connected");
        if (clients.indexOf(cId) === -1) {
            clients.push(cId);
            clientsStatus[cId] = true;
        }
        //check is connected client is already connected.
        if (connectedClientSocketIds[cId] === undefined) {
            connectedClientSocketIds[cId] = [];
        }
        //add new socket connection to logged in user
        connectedClientSocketIds[cId].push(socket.id);

         console.log("=======connected=====");
         console.log(connectedClientSocketIds);
         console.log("=======connected=====");

        /**
         * @description Socket connection off when user going to offline
         */
        socket.on('disconnect', function() {
            var index = clients.indexOf(socket.decoded_token.id);
            //var index = clients.indexOf(socket);
            if (index !== -1) {
                //remove disconnected socket id from one or may connected socket
                if (connectedClientSocketIds[cId] !== undefined) {
                    var ClientSocketIdsIndex = connectedClientSocketIds[cId].indexOf(socket.id);
                    if (ClientSocketIdsIndex !== -1) {
                        //console.log("found......" + ClientSocketIdsIndex);
                        connectedClientSocketIds[cId].splice(ClientSocketIdsIndex, 1);
                    }
                }
                 console.log("=======connected=====");
                 console.log(connectedClientSocketIds);
                 console.log("=======connected=====");
             
                //make user off line status and remove this user if any socket connection is not available of this user.
                if (connectedClientSocketIds[cId] !== undefined && connectedClientSocketIds[cId].length <= 1) {
                    //unset current user form socket id lists.
                    delete connectedClientSocketIds[cId];
                    clients.splice(index, 1);
                    clientsStatus[cId] = false;
                    logger.log("info", cId + " is disconnected");
                }
            }
        });
     
        /**
         *
         */
        socket.on("sendMessage", function(params) {
            console.log('Here in sendMessage metod....... params : ', params);
            socket.emit("getMessage", { status: 1, code: 200, type: "success", data: { data: params} });

           /*
           *If you want to send response to another user or friend then pass user id in reciverFriendIs id, you send this perticulr user by using  socket.broadcast.to method like as bellow
           */
           // console.log(params.reciverFriendIs);
            // console.log(connectedClientSocketIds[params.reciverFriendIs]);
            // socket.broadcast.to(connectedClientSocketIds[params.reciverFriendIs]).emit("getMessage", { status: 1, code: 200, type: "success", data: params });

        });
    });
    return app;
};

In this file, you can get and send any socket requests and manage it.
Here, I have commented on some code for JWT token. if you are using jwt token then uncomment following codes like as

//var jwt = require("jsonwebtoken");

//var socketioJWT = require('socketio-jwt');

// io.use(socketioJWT.authorize({
//     secret: global.hzConfig.jwtPrivateKey,
//     handshake: true
// }));

Find these lines and uncomment them. but make sure you must need to send jwt token in socket connection's connect method from the client-side. for it check bellow (socketio.service) file.

one more thing if you are using jwt token then you must have to install the following node module
npm install socketio-jwt --save

socketio.service.ts (in Client side) (C:\projects\myProject\src\app\socketio.service.ts)
/*
 * @Author: Laxman chavda
 * @Date:  2020-04-17 12:30:00 PM
 * @Last Modified by:   Laxman chavda
 * @Last Modified time: 2020-04-17 12:30:00 PM
 * @Purpose : Custom socket events
 */

import { Injectable } from '@angular/core';
import * as io from 'socket.io-client';
import {Observable} from 'rxjs';
//import {Observable} from 'rxjs/Observable';
import { CookieService } from 'ngx-cookie-service';

@Injectable()
export class SocketService {
  private socket:SocketIOClient.Socket;

  constructor(private cookieService: CookieService) {
    /*
    *For create socket connection
    */
 
    this.socket= io.connect('http://localhost:3000');

    // this.socket= io.connect('http://localhost:3000', {
    //     query: 'token=' + this.cookieService.get("myapp-token")
    // });
  }

  /*
  *For send socket's emit method to server side
  */
  emit(eventName:string, data:any){
    this.socket.emit(eventName,data);
  }

  /*
  *For get socket's response method to server side
  */
  on(eventName:string){
    return Observable.create(observer=>{
    this.socket.on(eventName,data=>{
      observer.next(data);
    });
    })
  }

  /*
  *For disconnect from socket to server side
  */
  disconnect(){
    console.log("here for disconnect....");
    this.socket.disconnect();
  }

}

In this file, you can get and send any socket requests and manage it.
Here, I have commented socket connection code for JWT token. if you are using jwt token then uncomment following codes like as and comment this.socket= io.connect('http://localhost:3000'); line

// this.socket= io.connect('http://localhost:3000', {
//     query: 'token=' + this.cookieService.get("myapp-token")
// })

Find these lines and uncomment them. but make sure you must need to send jwt token in socket connection's connect method which is got from the server-side and it may be stored in cookie or localstorage or session storage. here we will get this toke from cookie named myapp-token wihch is get at login time.

one more thing for import Observable in socketio.service.ts
if you have used RxJs 6.5 or lower then use
import {Observable} from "rxjs";

if you have used RxJs 7 greater than 7 then use
import {Observable} from rxjs/Observable;

app.module.ts (in Client side) (C:\projects\myProject\src\app\app.module.ts)
...
...
...
import {SocketService} from './socketio.service';
...
...
...

@NgModule({
  declarations: [
    ...
    ...
    ...
  ],
  imports: [
    ....
    ....
    ....
  ],
  providers: [
    ....
    ....
    ....
    SocketService,
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

You can import SocketService here or if you are using lazy loading then you can use it in your module where you need it.

chat.component.ts (in Client side) (C:\projects\myProject\src\app\chat\chat.component.ts)
import { Component, OnInit } from '@angular/core';
....
....
...
import {SocketService} from './../socketio.service';
...
...
...

@Component({
  selector: 'app-chat',
  templateUrl: './chat.component.html',
  styleUrls: ['./chat.component.css']
})
export class ChatComponent implements OnInit {

  message: string;
  messageFromServer:any;

  // constructor(private router: Router, private route: ActivatedRoute, private http: HttpClient) { }
  constructor(private socketService : SocketService) {
 
  }

  ngOnInit() {
      ...
      ...
      ...
      this.socketService.on('getMessage').subscribe(data=>{
        console.log("here is the data comes from the server : ",data);
        this.messageFromServer = data;
      });
     
      this.socketService.on('GroupMessage').subscribe(data=>{
        console.log("here is the data comes from the server : ",data);
      });

      this.socketService.on('searchedResults').subscribe(data=>{
        console.log("here is the data comes from the server : ",data);
      });     
      ...
      ...
      ...
  }

  pushMessage(){
    this.socketService.emit('sendMessage',this.message);
  }

  pushGroupMessage(){
    this.socketService.emit('sendGroupMessage',this.message);
  }

  searchMessages(text){
    this.socketService.emit('searchMessages',text);
  }

}

chat.component.html (in Client side) (C:\projects\myProject\src\app\chat\chat.component.html)
<div class="container">
  <h1>
  Chat List
  </h1>
  ....
  ....
  ....
  ....
  <!--<div *ngIf="!!messageFromServer">
    <pre>
      Here is the response from server :  {{messageFromServer | json}}
    </pre>
  </div>-->
  .....
  ....
  <input type="text" class="form-control" [(ngModel)]="message" name="author" required>
  ...
  ...
  ...
  <a href="javascript:void(0);" (click)="pushMessage();" *ngIf="!!message">Send message</a>
  ......
  ......
  .....
</div>

I think now it is clear how to use WebSocket(socket.io) in nodeJs and angular applications thought if you have any doubt then you can write in the comment box.

No comments:

Post a Comment