Building a Command-Line Chat App with Node.js and Socket.IO — Part 3

Teedus Chung
3 min readJun 18, 2021

If you’re a new one, please refer to the previous parts of this project as follows:

Why do we use a database

We’ve done the simple chat app in the last few days. It, however, needs to be improved on some functions. Let’s take a deeper look at the list_messages_group function that we did on the server-side:

/*** server.js ***///...io.of("/").on("connect", (socket) => {

//...

socket.on("list_messages_group", (data) => {
console.log("\n%s", data);
var msgs = io.of("/").room_messages[data.group]; socket.emit("list_messages_group", {"sender": data.sender, "action": "list_messages_group", "group": data.group, "msgs": msgs});
});
});

The room_messages object is our own data structure in which we store all messages exchanged in a group, so where does it come from? Well, we continue to take a look at the broadcast_group function:

/*** server.js ***///...io.of("/").on("connect", (socket) => {

//...

socket.on("broadcast_group", (data) => {
console.log("\n%s", data);
socket.to(data.group).emit("broadcast_group", data); if (undefined === io.of("/").room_messages) {
io.of("/").room_messages = {};
}
if (undefined === io.of("/").room_messages[data.group]) {
io.of("/").room_messages[data.group] = [];
}
io.of("/").room_messages[data.group].push(data.msg);
});
});

As we see, when the server receives a packet, it will save data that relates to the packet to the room_messages object after creating this object and adding it to the io variable.

Those functions have worked well, right? What if the computer was crashed or we stopped the server accidentally? We would lose all data stored in the io variable including the room_messages object because this variable was stored in the main memory — RAM. So the solution here is that we’ll store room_messages data in permanent storage — SD, HDD, etc. We’ll use a database for storing and accessing data easily instead of just saving data to disk. In particular, that’s a database called SQLite.

Improve the ‘list_messages_group’ function

In order to fulfill this function, we design a simple schema in which we have only one table named room_messages where we define three columns named thegroup, sender, msg as follows:

Note that group is a keyword of SQLite so we use thegroup as a column name instead of group

Let’s write code on the server-side:

/*** server.js ***///...function db_save_message(group, sender, msg) {
db.serialize(() => {
db.run("CREATE TABLE IF NOT EXISTS room_messages(thegroup TEXT, sender TEXT, msg TEXT)", function(err) {
if (err) {
throw err;
}
});

db.run("INSERT INTO room_messages(thegroup, sender, msg) VALUES(?,?,?)", [group, sender, msg], function(err) {
if (err) {
throw err;
}
console.log("Saved the message to the database, rowid: " + this.lastID);
});
});
}

We create a function named db_save_message for two purposes:

  • Implement the schema by using the SQL statement called CREATE TABLE
  • Then add data to the room_messages table by using the SQL statement called INSERT INTO

After that, we’ll call this function in the broadcast_group function as follows:

/*** server.js ***///...io.of("/").on("connect", (socket) => {    //...

socket.on("broadcast_group", (data) => {
//... db_save_message(data.group, data.sender, data.msg);
});
});

Now we’ll modify the list_messages_group function to get messages by using the SQL SELECT statement:

/*** server.js ***///...io.of("/").on("connect", (socket) => {

//...
socket.on("list_messages_group", () => {
console.log("\n%s", data);
db.serialize(() => {
db.all("SELECT msg FROM room_messages WHERE thegroup = ?", [data.group], (err, rows) => {
var msgs = [];

if (err) {
throw err;
}
rows.forEach((row) => {
console.log("Got a message from the database: " + row.msg);
msgs.push(row.msg);
});

socket.emit("list_messages_group", {"sender": data.sender, "action": "list_messages_group", "group": data.group, "msgs": msgs});
});
});
});});

Improve the ‘list_messages_user’ function

--

--