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\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.