Simple Chatroom using Websockets in Node.js

Code for this can be found here: https://github.com/JBaczuk/simple-chatroom-websockets-nodejs

Set up Node project

npm init

You can choose details for your project however you like:

package name: (chatroom)
version: (1.0.0)
description:
entry point: (chat_server.js)
test command:
git repository:
keywords:
author:
license: (ISC)

Create server

Create a new file called chat_server.js and paste the following:

const express = require('express');
const http = require('http');
const url = require('url');
const WebSocket = require('ws');

const app = express();
var users = [];

const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

// Broadcast to all.
wss.broadcast = function broadcast(data) {
    wss.clients.forEach(function each(client) {
        if (client.readyState === WebSocket.OPEN) {
            client.send(data);
        }
    });
};

wss.on('connection', function connection(ws, req) {
    const location = url.parse(req.url, true);
    // You might use location.query.access_token to authenticate or share sessions
    // or req.headers.cookie (see http://stackoverflow.com/a/16395220/151312)
    // TODO: don't allow users with the same id
    console.log("User " + req.headers.origin + " joined!");
    users.push(req.headers.origin);
    wss.broadcast("room: User " + req.headers.origin + " joined!");

    ws.on('message', function incoming(message) {
        console.log('received: %s', message);
        wss.broadcast(message);
    });

    ws.on('close', function close(ws, req) {
        console.log('Connection closed...');
    });
});

server.listen(8000, function listening() {
    console.log('Listening on %d', server.address().port);
});

Run server

npm install --save express
npm install --save ws
node chat_server.js

Server Description

This app uses express server to host a server on port 8000. A websocket server is created using the ws Node.js WebSocket library by passing the express server as a parameter: const wss = new WebSocket.Server({ server });. Then callback functions are defined:

  • wss.on('connection'..., which fires when a client connects
  • ws.on('message'..., which fires when a message is received from a client
  • ws.on('close'..., which first when a client closes the connection

Also, there is a helper function wss.broadcast() which will send a message to all connected clients at once. Finally, we keep track of users in the var users = []; array.

Create Client

Create a new file called chat_client.js and paste the following:

const WebSocket = require('ws');
const readline = require('readline');
const colors = require('colors');
var ws;
rl = readline.createInterface({
    input: process.stdin, 
    output: process.stdout
});

var userId;

welcome();

if (process.argv.length > 2) {
    userId = process.argv[2];
}
else {
    rl.question('Choose a username: ', (answer) => initConnection(answer));
}

function initConnection(id) {
    userId = id;
    // NOTE: Change this url to the server's ip address/domain
    ws = new WebSocket('ws://localhost:8000', {
        origin: id,
        perMessageDeflate: false,
    });
    ws.on('open', function open(ws, req) {
        console.log("= Connection to chatroom established!".blue);
        flush(prompt);
    });
    
    ws.on('message', function incoming(data) {
        console.log(data);
        flush(prompt);
    });
}

function welcome() {
    console.log(["= Welcome to Websocket Chatroom"
        , "= Please keep it civil - or don't who cares"
    ].join('\n').blue);
}

function prompt() {
    var arrow = '> '
        , length = arrow.length
        ;

    rl.setPrompt(arrow.green, length);
    rl.prompt();
}

var state = 1;

rl.on('line', function (msg) {
    ws.send(userId + ": " + msg);
    prompt();
}).on('close', function () {
    // only gets triggered by ^C or ^D
    util.puts('goodbye!'.green);
    process.exit(0);
});

process.on('uncaughtException', function (e) {
    console.log(e.stack.red);
    rl.prompt();
});

function flush(callback) {
    if (process.stdout.write('')) {
        callback();
    } else {
        process.stdout.once('drain', function () {
            callback();
        });
    }
};

Run Client

npm install --save colors
node chat_client.js

Client Description

This simple app is a command line app that can be passed a username as an argument, if not provided, it will prompt the user for a username before connecting to the server. It also uses the ws library as well as the readline library for user input. It will take any input from the user and send it to the server, which, in turn, broadcasts the message to all clients.

Note: the server and client processes must both be on the same computer. To run on another machine, just update chat_client.js to point to the right address:

ws = new WebSocket('ws://<some-address>:8000'...