2
\$\begingroup\$

In an effort to teach myself Node.JS and truly delve into its communication capabilities, I elected to recreate a previous chatting project. It took a bit of forethought to acclimate code to the asynchronous nature of node, consider the implications of sending files for access and get in the habit of using callbacks.

I wonder if and where I may be over-complicating or over-simplifying.

registration.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="keywords" content="registration, register, chat, chatroom"/>
        <meta name="robots" content="index, follow"/>
        <meta name="author" content="Luigi Vincent"/>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Web Chatter</title>
        <style>
            body {
                background-color: #E9EAED;
                color: #141823;
            }

            #title {
                color: #415E9A;
                text-align: center;
            }

            #register-form {
                margin-top: 10em;
                text-align: center;
            }

            .login {
                margin: 0.5em;
                border-radius: 0.6em;
                color: #ffffff;
                cursor: pointer;
                font-size: 1em;
                background-color: #415E9A;
            }
            .login:hover {
                box-shadow:  0 0 10px #4A66A0;
            }
            .login:active {
                position: relative;
                outline: none;
                top: 0.05em;
            }

            #login {
                margin-left: 6em;
            }
            .response {
                font-weight: bold;
                text-align: center;
            }
            .success {
                color: #4A66A0; 
            }

            .error {
                color: #FFCCCC;
            }
        </style>
    </head>
    <body>
        <form id='register-form' method="post">
            <h1 id='title'>Welcome to Chatter</h1>
            Username: <input type="text" class="input" name="username" id="username" required="required"><br>
            Password: <input type="password" class="input" name="password" id="password" style="margin-left: 3px;" required="required"><br>
            Re-enter Password: <input type="password" class="input" name="confirm-password" id="confirm-password" style="margin-right: 55px;" required="required"><br>
            <input class="login" id="new" type="submit" name="register" value="Register" style="margin-left: 12em;">
        </form>
        <script src="/assets/sweetalert/dist/sweetalert.min.js"></script>
        <link rel="stylesheet" type="text/css" href="/assets/sweetalert/dist/sweetalert.css">
        <script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
        <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
        <script>
            var socket = io();

            $('form').submit(function(e) {
                e.preventDefault();
                if ($('#password').val() === $('#confirm-password').val()) {
                    socket.emit('registration', $('#username').val(), $('#password').val());
                } else {
                    swal("Oops...", "Passwords do not match", "error");
                }
            });

            socket.on('redirect', function(page){
                window.location.href = page;
            });

            socket.on('exists', function() {
                swal("Sorry", "Username is taken", "error");
            });
        </script>
    </body>
</html>

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="description" content="A web chatting application by LKX"/>
        <meta name="keywords" content="chat, app, application, chatroom"/>
        <meta name="robots" content="index, follow"/>
        <meta name="author" content="Luigi Vincent, Kerules Fareg, Xiaoding Lin"/>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Web Chatter</title>
        <style>
            body {
                background-color: #E9EAED;
                color: #141823;
            }

            #title {
                color: #415E9A;
                text-align: center;
            }

            #login-form {
                margin-top: 10em;
                text-align: center;
            }

            .login {
                margin: 0.5em;
                border-radius: 0.6em;
                color: #ffffff;
                cursor: pointer;
                font-size: 1em;
                background-color: #415E9A;
            }
            .login:hover {
                box-shadow:  0 0 10px #4A66A0;
            }
            .login:active {
                position: relative;
                outline: none;
                top: 0.05em;
            }

            #login {
                margin-left: 6em;
            }
            .response {
                font-weight: bold;
                text-align: center;
            }
            .success {
                color: #4A66A0; 
            }

            .error {
                color: #FFCCCC;
            }
        </style>
    </head>

    <body>
        <form id='login-form' method=''>
            <h1 id='title'>Welcome to Chatter</h1>
            Username: <input type="text" class="input" id="username" required="required"><br>
            Password: <input type="password" class="input" id="password" style="margin-left: 3px;" required="required"><br>
            <input class="login" id="new" type="button" name="register" value="New User">
            <input class="login" id="login" type="submit" name="submit" value="Log in">
        </form>
        <script src="/assets/sweetalert/dist/sweetalert.min.js"></script>
        <link rel="stylesheet" type="text/css" href="/assets/sweetalert/dist/sweetalert.css">
        <script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
        <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
        <script>
            var socket = io();
            $('form').submit(function(e) {
                e.preventDefault();
                socket.emit('login', $('#username').val(), $('#password').val());
            });

            socket.on('redirect', function(page) {
                window.location.href = page;
            });

            socket.on('invalid', function() {
                swal("Oops...", "Wrong username or password", "error");
            });

            $("#new").click(function() {
                socket.emit("register", null);
            });
        </script>
    </body>
</html>

app.html

<!DOCTYPE html>
<html>
  <head>
    <title>WebChatter</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font: 13px Helvetica, Arial;
        background-color: #E9EAED;
        color: #141823;
      }

      form {
        background: #000;
        padding: 3px;
        position: fixed;
        bottom: 0;
        width: 100%;
      }

      form input {
        border: 0;
        padding: 10px;
        width: 89%;
        margin-right: .5%;
      }

      form button {
        width: 5%;
        background: #415E9A;
        color: #fff;
        border: none;
        padding: 10px;
      }
      form button:hover {
        box-shadow:  0 0 10px #4A66A0;
      }

      #messages {
        list-style-type: none;
        margin: 0;
        padding: 0;
      }

      #messages li {
        padding: 5px 10px;
      }
      #messages li:nth-child(odd) {
        background: #fff;
      }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
      <button id="return">Logout</button>
    </form>
    <script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
    <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
      var socket = io();
      $('form').submit(function(){
        socket.emit('chat message', $('#m').val());
        $('#m').val('');
        return false;
      });

      socket.on('connect', function() {
        socket.emit('user connect', null);
      });

    $('#return').click(function () {
      window.history.back();
    });

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

index.js

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var serveStatic = require('serve-static');
var connectingUser = [];

var mysql = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : 'password',
  database : 'Chatter'
});
connection.connect();

app.use('/assets', serveStatic(__dirname + '/node_modules'));
app.use(require('serve-favicon')(__dirname + '/assets/icon.ico'));

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

app.get('/login', function(req, res) {
    res.redirect("/");
})

app.get('/register', function(req, res) {
    res.sendFile(__dirname + '/registration.html');
})

app.get('/app', function(req, res) {
    res.sendFile(__dirname + '/app.html');
})

io.on('connection', function(socket) {
    var user = '';
    socket.on('user connect', function() {
        retrieveUserList(function(err, userList) {
            socket.emit('chat message', userList);
        });
        user = connectingUser.pop();
    });

    socket.on('chat message', function(msg) {
        if (msg.length > 0) {
            io.emit('chat message', user + ": " + msg);
        }
    });

    socket.on('login', function(username, password) {
        isValidUser(username, password, function(err, result) {
            if (result) {
                connectingUser.push(username);
                io.emit('chat message', username + " has logged in.");
                socket.emit('redirect', '/app');
            } else {
                socket.emit('invalid', null);
            }
        });
    });

    socket.on('register', function() {
        socket.emit("redirect", '/register');
    });

    socket.on('registration', function(username, password) {
        isExistingUser(username, function(err, result) {
            if (result) {
                socket.emit('exists', null);
            } else {
                addUser(username, password);
                socket.emit("redirect", '/login');
            }
        });
    });
});

http.listen(8080, function(){
    console.log('listening on: 8080');
});

function addUser(username, password) {
    connection.query('INSERT INTO users(username, password) VALUES("'
        + username + '", "' + password +'")',
        function(err) {
            if (err) {
                console.error("Error while performing user addition query.");
            }
        }
    );
}

function isExistingUser(username, callback) {
    connection.query("SELECT username FROM users WHERE username=\"" + username + "\"",
        function(err, rows) {
            if (!err) {
                callback(null, rows.length > 0);
            } else {
                console.error('Error while performing user existential query.');
            }
        }
    );
}

function isValidUser(username, password, callback) {
    connection.query("SELECT username FROM users WHERE username=\"" + username
        + "\" AND password=\"" + password + "\"",
        function(err, rows) {
            if (!err) {
                callback(null, rows.length > 0);
            } else {
                console.error('Error while performing user validation query.');
            }
        }
    );
}

function retrieveUserList(callback) {
    connection.query("SELECT username FROM users", function(err, rows) {
        var list = 'Registered Users: ';
        if (!err) {
            var listBuilder = '';
            for (var i = 0; i < rows.length; i++) {
                listBuilder += ', ' + rows[i].username;
            }
            list += listBuilder.substring(2);
            callback(null, list);
        } else {
            console.error('Error while performing user list query.');
        }
    });
}

package.json

{
    "name": "socket-chatting-app",
    "version": "0.0.6",
    "description": "web chatter",
    "dependencies": {
    "express": "^4.10.2",
    "socket.io": "^1.4.5",
    "mysql": "^2.5.4"
    }
}

I'm especially interested in:

  1. Any remarks on conventional refactoring.
  2. Feedback on the way I 'send' files for access.
  3. My use of callbacks (fairly new concept for me).
  4. Any feedback on what could be improved in general.

Feel free to try it here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.