Socket.io

Socket.IO is JavaScript implementation to work with HTML 5 WebSockets. In can be used in NodeJS & based server frameworks for server-side, while client-side can be integrated with pure JavaScript, AngularJS, React.

Socket.IO proves to be promising with over 49K GitHub Stars. Furthermore it’s stable for production level with V2.0.0 being released in 2017.

Quick links Documentation

NPM Version

1
npm -v

Node Version

1
node -v

0. Installing Packages

1
npm init

Installing Packages

1
npm i --save express nodemon socket.io

What is Express

Express.js, or simply Express, is a web application framework for Node.js, released as free and open-source software under the MIT License. It is designed for building web applications and APIs. It has been called the de facto standard server framework for Node.js. en.wikipedia.org

What is Nodemon

Nodemon is a development dependency that monitors for any changes in your Node. js application and automatically restarts the server, saving time and tedious work. medium.com

What is Socket.io

Socket.IO is JavaScript implementation to work with HTML 5 WebSockets. In can be used in NodeJS & based server frameworks for server-side, while client-side can be integrated with pure JavaScript, AngularJS, React.Socket.io

1
npm i --save-dev babel-cli babel-preset-env babel-preset-stage-0

In package.json file add these lines in the script keyword

1
2
3
4
5
// package.json
"scripts": {
    "start": "nodemon ./index.js --exec babel-node -e js",
    "test": "DEBUG=* npm run nodemon ./index.js --exec babel-node -e js"
  },

Create a new file .babelrc with the same directory of package.json file.

Hint

Insert the following snippet into the newly created file.

1
2
3
4
5
6
{
    "presets": [
        "env",
        "stage-0"
    ]
}

Hint

Babel is used to compile the project

1. Simple chat app

Create a file index.js on the same level of node_modules directory and paste the following snipet into it.

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = 3000;

server.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html');
});

io.on('connection', (socket) => {
    console.log('user connected');
    socket.emit('message', { manny: 'hey how are you?'});
    socket.on('another event', (data) => {
        console.log(data);
    })
})

code01

Now create a directory public on the same level of node_modules directory.

Create a file index.html and paste the below snippet into it.

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
  <head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io.connect('http://localhost:3000');
      socket.on('message', (data) => {
        console.log(data);
        socket.emit('another event', { jeremy: 'I am great thank you'});
      })
    </script>
  </body>
</html
1
node run start
[nodemon] app crashed - waiting for file changes before starting...

Node.JS: Getting error : [nodemon] Internal watch failed: watch ENOSPC

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
events.js:183
  throw er; // Unhandled 'error' event
  ^

Error: listen EADDRINUSE :::3000
    at Object._errnoException (util.js:1022:11)
    at _exceptionWithHostPort (util.js:1044:20)
    at Server.setupListenHandle [as _listen2] (net.js:1367:14)
    at listenInCluster (net.js:1408:12)
    at Server.listen (net.js:1492:7)
    at Object.<anonymous> (/home/mohsin/Desktop/chatter02/index.js:6:8)
    at Module._compile (module.js:652:30)
    at loader (/home/mohsin/Desktop/chatter02/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/home/mohsin/Desktop/chatter02/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:565:32)
[nodemon] app crashed - waiting for file changes before starting...

Solution to this problem is in the following snippet

1
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

or

There is a server that's already running, so you cannot start another server.

Now, with Bootstrap

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = 3000;

server.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html');
});

io.on('connection', (socket) => {
    console.log('user connected');
    socket.on('message', (msg) => {
        console.log(`message: ${msg}`);
        io.emit('message', msg);
    })
})

and the index.html (client) should look like this —

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
      form { padding: 20px; position: fixed; bottom: 0; width: 100%; padding-right: 50px;}
      #messages { list-style-type: none; margin: 0; padding: 0; width: 100%;}
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee;} 
    </style>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <ul id="messages"></ul>
      </div>
      <div class="row">
          <div class="col-lg-6">
            <form action="">
              <div class="input-group">
                  <input id="m" autocomplete="off" type="text" class="form-control" placeholder="Message..." aria-label="Message...">
                  <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Send</button>
                  </span>
                </div>
            </form>
          </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io();
      $('form').submit(() => {
        socket.emit('message', $('#m').val());
        $('#m').val('');
        return false;
      });

      socket.on('message', (msg) => {
        $('#messages').append($('<li>').text(msg));
      })
    </script>
  </body>
</html

2. Connect / Disconnect Events

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = 3000;

server.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html');
});

io.on('connection', (socket) => {
    console.log('user connected');
    socket.on('message', (msg) => {
        console.log(`message: ${msg}`);
        io.emit('message', msg);
    });

    socket.on('disconnect', () => {
        console.log('user disconnected');

        io.emit('message', 'user disconnected');
    })
})

and the index.html (client) should look like this —

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
      form { padding: 20px; position: fixed; bottom: 0; width: 100%; padding-right: 50px;}
      #messages { list-style-type: none; margin: 0; padding: 0; width: 100%;}
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee;} 
    </style>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <ul id="messages"></ul>
      </div>
      <div class="row">
          <div class="col-lg-6">
            <form action="">
              <div class="input-group">
                  <input id="m" autocomplete="off" type="text" class="form-control" placeholder="Message..." aria-label="Message...">
                  <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Send</button>
                  </span>
                </div>
            </form>
          </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io();
      $('form').submit(() => {
        socket.emit('message', $('#m').val());
        $('#m').val('');
        return false;
      });

      socket.on('connect', () => {
        // emiting to everybody
        socket.emit('message', 'user connected');
      })

      socket.on('message', (msg) => {
        $('#messages').append($('<li>').text(msg));
      })
    </script>
  </body>
</html

3. NameSpace Setup

Now, we are going to add a namespace tech to our server.

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = 3000;

server.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html');
});

// tech namespace
const tech = io.of('/tech');

tech.on('connection', (socket) => {
    console.log('user connected');
    socket.on('message', (msg) => {
        console.log(`message: ${msg}`);
        tech.emit('message', msg);
    });

    socket.on('disconnect', () => {
        console.log('user disconnected');

        tech.emit('message', 'user disconnected');
    })
})

and the index.html (client) should look like this —

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
      form { padding: 20px; position: fixed; bottom: 0; width: 100%; padding-right: 50px;}
      #messages { list-style-type: none; margin: 0; padding: 0; width: 100%;}
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee;} 
    </style>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <ul id="messages"></ul>
      </div>
      <div class="row">
          <div class="col-lg-6">
            <form action="">
              <div class="input-group">
                  <input id="m" autocomplete="off" type="text" class="form-control" placeholder="Message..." aria-label="Message...">
                  <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Send</button>
                  </span>
                </div>
            </form>
          </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io('/tech');
      $('form').submit(() => {
        socket.emit('message', $('#m').val());
        $('#m').val('');
        return false;
      });

      socket.on('connect', () => {
        // emiting to everybody
        socket.emit('message', 'user connected');
      })

      socket.on('message', (msg) => {
        $('#messages').append($('<li>').text(msg));
      })
    </script>
  </body>
</html

4. Setting up Rooms

Init Room Javascript

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = 3000;

server.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html');
});

// tech namespace
const tech = io.of('/tech');

tech.on('connection', (socket) => {
    socket.on('join', (data) => {
        socket.join(data.room);
        tech.in(data.room).emit('message', `New user joined ${data.room} room!`);
    })

    socket.on('message', (data) => {
        console.log(`message: ${data.msg}`);
        tech.in(data.room).emit('message', data.msg);
    });

    socket.on('disconnect', () => {
        console.log('user disconnected');

        tech.emit('message', 'user disconnected');
    })
})

and the index.html (client) should look like this —

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
      form { padding: 20px; position: fixed; bottom: 0; width: 100%; padding-right: 50px;}
      #messages { list-style-type: none; margin: 0; padding: 0; width: 100%;}
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee;} 
    </style>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <ul id="messages"></ul>
      </div>
      <div class="row">
          <div class="col-lg-6">
            <form action="">
              <div class="input-group">
                  <input id="m" autocomplete="off" type="text" class="form-control" placeholder="Message..." aria-label="Message...">
                  <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Send</button>
                  </span>
                </div>
            </form>
          </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const room = 'javascript';
      const socket = io('/tech');
      $('form').submit(() => {
        let msg = $('#m').val();
        socket.emit('message', { msg, room });
        $('#m').val('');
        return false;
      });

      socket.on('connect', () => {
        // emiting to everybody
        socket.emit('join', { room: room });
      })

      socket.on('message', (msg) => {
        $('#messages').append($('<li>').text(msg));
      })
    </script>
  </body>
</html

**JavaScript Room with seperate base file **

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = 3000;

server.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html');
});

app.get('/javascript', (req, res) => {
    res.sendFile(__dirname + '/public/javascript.html');
});

// tech namespace
const tech = io.of('/tech');

tech.on('connection', (socket) => {
    socket.on('join', (data) => {
        socket.join(data.room);
        tech.in(data.room).emit('message', `New user joined ${data.room} room!`);
    })

    socket.on('message', (data) => {
        console.log(`message: ${data.msg}`);
        tech.in(data.room).emit('message', data.msg);
    });

    socket.on('disconnect', () => {
        console.log('user disconnected');

        tech.emit('message', 'user disconnected');
    })
})

and the index.html (client) should look like this —

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
  </head>
  <body>
    <div class="jumbotron jumbotron-fluid">
      <div class="container">
        <h1 class="display-3">Tech space chatter</h1>
        <p class="lead">Select which room you'd like to join below!!!</p>
      </div>
    </div>
    <div class="container-fluid">
      <div class="row">
        <ul class="list-group col">
          <a href="/javascript" class="list-group-item list-group-item-action">Javascript</a>
          <a href="#" class="list-group-item">Swift</a>
          <a href="#" class="list-group-item">CSS</a>
        </ul>
      </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
  </body>
</html

javascript.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
      form { padding: 20px; position: fixed; bottom: 0; width: 100%; padding-right: 50px;}
      #messages { list-style-type: none; margin: 0; padding: 0; width: 100%;}
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee;} 
    </style>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <ul id="messages"></ul>
      </div>
      <div class="row">
          <div class="col-lg-6">
            <form action="">
              <div class="input-group">
                  <input id="m" autocomplete="off" type="text" class="form-control" placeholder="Message..." aria-label="Message...">
                  <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Send</button>
                  </span>
                </div>
            </form>
          </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const room = 'javascript';
      const socket = io('/tech');
      $('form').submit(() => {
        let msg = $('#m').val();
        socket.emit('message', { msg, room });
        $('#m').val('');
        return false;
      });

      socket.on('connect', () => {
        // emiting to everybody
        socket.emit('join', { room: room });
      })

      socket.on('message', (msg) => {
        $('#messages').append($('<li>').text(msg));
      })
    </script>
  </body>
</html

5. Complete tech rooms

"DemoApp"

"DemoApp"

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const port = 3000;

server.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html');
});

app.get('/javascript', (req, res) => {
    res.sendFile(__dirname + '/public/javascript.html');
});
app.get('/swift', (req, res) => {
    res.sendFile(__dirname + '/public/swift.html');
});
app.get('/css', (req, res) => {
    res.sendFile(__dirname + '/public/css.html');
});

// tech namespace
const tech = io.of('/tech');

tech.on('connection', (socket) => {
    socket.on('join', (data) => {
        socket.join(data.room);
        tech.in(data.room).emit('message', `New user joined ${data.room} room!`);
    })

    socket.on('message', (data) => {
        console.log(`message: ${data.msg}`);
        tech.in(data.room).emit('message', data.msg);
    });

    socket.on('disconnect', () => {
        console.log('user disconnected');

        tech.emit('message', 'user disconnected');
    })
}

and the index.html (client) should look like this —

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
  </head>
  <body>
    <div class="jumbotron jumbotron-fluid">
      <div class="container">
        <h1 class="display-3">Tech space chatter</h1>
        <p class="lead">Select which room you'd like to join below!!!</p>
      </div>
    </div>
    <div class="container-fluid">
      <div class="row">
        <ul class="list-group col">
          <a href="/javascript" class="list-group-item list-group-item-action">Javascript</a>
          <a href="/swift" class="list-group-item">Swift</a>
          <a href="/css" class="list-group-item">CSS</a>
        </ul>
      </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
  </body>
</html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter / Javascript</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
      form { padding: 20px; position: fixed; bottom: 0; width: 100%; padding-right: 50px;}
      #messages { list-style-type: none; margin: 0; padding: 0; width: 100%;}
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee;} 
    </style>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <ul id="messages"></ul>
      </div>
      <div class="row">
          <div class="col-lg-6">
            <form action="">
              <div class="input-group">
                  <input id="m" autocomplete="off" type="text" class="form-control" placeholder="Message..." aria-label="Message...">
                  <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Send</button>
                  </span>
                </div>
            </form>
          </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const room = 'javascript';
      const socket = io('/tech');
      $('form').submit(() => {
        let msg = $('#m').val();
        socket.emit('message', { msg, room });
        $('#m').val('');
        return false;
      });

      socket.on('connect', () => {
        // emiting to everybody
        socket.emit('join', { room: room });
      })

      socket.on('message', (msg) => {
        $('#messages').append($('<li>').text(msg));
      })
    </script>
  </body>
</html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter / Swift</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
      form { padding: 20px; position: fixed; bottom: 0; width: 100%; padding-right: 50px;}
      #messages { list-style-type: none; margin: 0; padding: 0; width: 100%;}
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee;} 
    </style>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <ul id="messages"></ul>
      </div>
      <div class="row">
          <div class="col-lg-6">
            <form action="">
              <div class="input-group">
                  <input id="m" autocomplete="off" type="text" class="form-control" placeholder="Message..." aria-label="Message...">
                  <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Send</button>
                  </span>
                </div>
            </form>
          </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const room = 'swift';
      const socket = io('/tech');
      $('form').submit(() => {
        let msg = $('#m').val();
        socket.emit('message', { msg, room });
        $('#m').val('');
        return false;
      });

      socket.on('connect', () => {
        // emiting to everybody
        socket.emit('join', { room: room });
      })

      socket.on('message', (msg) => {
        $('#messages').append($('<li>').text(msg));
      })
    </script>
  </body>
</html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Chatter / CSS</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
      form { padding: 20px; position: fixed; bottom: 0; width: 100%; padding-right: 50px;}
      #messages { list-style-type: none; margin: 0; padding: 0; width: 100%;}
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee;} 
    </style>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <ul id="messages"></ul>
      </div>
      <div class="row">
          <div class="col-lg-6">
            <form action="">
              <div class="input-group">
                  <input id="m" autocomplete="off" type="text" class="form-control" placeholder="Message..." aria-label="Message...">
                  <span class="input-group-btn">
                    <button class="btn btn-secondary" type="submit">Send</button>
                  </span>
                </div>
            </form>
          </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const room = 'css';
      const socket = io('/tech');
      $('form').submit(() => {
        let msg = $('#m').val();
        socket.emit('message', { msg, room });
        $('#m').val('');
        return false;
      });

      socket.on('connect', () => {
        // emiting to everybody
        socket.emit('join', { room: room });
      })

      socket.on('message', (msg) => {
        $('#messages').append($('<li>').text(msg));
      })
    </script>
  </body>
</html

6. Chat App Demo

"DemoApp"

server.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
var http = require('http').Server(app)
var io = require('socket.io')(http)

app.use(express.static(__dirname))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))

var messages = [
    {name: 'Mohsin', message: 'Hi'},
    {name: 'Mahmood', message: 'Hello'}
]

app.get('/messages', (req, res) =>{
    res.send(messages)
})

app.post('/messages', (req, res) =>{
    messages.push(req.body)
    io.emit('message', req.body)
    res.sendStatus(200)
})

io.on('connection', (socket) => {
    console.log('a user connected')
})

var server = http.listen(3000, () => {
    console.log('server is listening on port', server.address().port)
}

index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!doctype html>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
<script src="/socket.io/socket.io.js"></script>

<div class="container">
    <br>
    <div class="jumbotron">
        <h1 class="display-4">Send Message</h1>
        <br>
        <input id="name" class="form-control" placeholder="Name">
        <br>
        <textarea id="message" class="form-control" placeholder="Message"></textarea>
        <br>
        <button id="send" class="btn btn-success">Send</button>
    </div>
    <div id="messages">

    </div>
</div>
<script>
    var socket = io()
    $(() => {
        $("#send").click(()=>{
            var message = { name: $("#name").val(), message: $("#message").val()}
            postMessage(message)
        })
        getMessages()
    })

    socket.on('message', addMessage)

    function addMessage(message){
        $("#messages").append(`<h4> ${message.name} </h4> <p> ${message.message} </p>`)
    }

    function getMessages() {
        $.get('http://localhost:3000/messages', (data) => {
            data.forEach(addMessage);
        })
    }

    function postMessage(message) {
        $.post('http://localhost:3000/messages', message)
    }
</script

7. Debug Tool

Manually

For Linux

1
DEBUG=* npm run start

For Windows

1
set DEBUG=* & npm run start

Automatically

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "name": "chatter",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon ./index.js --exec babel-node -e js",
    "test": "DEBUG=* nodemon ./index.js --exec babel-node -e js"
  },
  "author": "Emmanuel Henri",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.2",
    "nodemon": "^1.12.1",
    "socket.io": "^2.0.3"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-env": "^1.6.0",
    "babel-preset-stage-0": "^6.24.1"
  }
}
1
npm run test