This repository contains a real-time web chat application implemented using Node.js, Express, Socket.IO, RxJS and Angular. It contains users and admins with groups and channels.
This application currently holds the following functionality:
The root directory of the repository contains the README.md
file and the files necessary for Node.js. All of the Node.js logic is contained in a single file called index.js
. The root directory also contains a sub-directory called chat-app
which contains all the files necessary for Angular.
The chat-app
directory contains all the auto-generated files. The project’s files are contained inside the src/app
sub-directory. In here, there are four directories, each containing its respective Angular Component. It also contains TypeScript files for Angular services.
The approach of using Git in this project was to commit changes at any time a new functionality was added. An example would be a task to add functionality for a user. The task would be broken down into sub-tasks and when a sub-task has been implemented, a commit would be added to Git.
Ensure that the root directory of the Git repository contains an images
directory. This directory is where the uploaded images are saved and statically served back to the user.
The main data structures that were used in this project were JavaScrict Array
objects and JavaScript Object
objects.
The JavaScript Array
was mainly used to store things that required easy iterator behaviour. Some use cases:
The JavaScript Object
was mainly used to store the user data in a JSON file. The basic template of a user Object
looks like this:
class UserDataTemplate {
constructor() {
this.username = "";
this.password = "password";
this.email = "";
this.superAdmin = false;
this.groupAdmin = false;
this.profileImage = "images/default/profile.gif";
this.groups = [
{
"name": "newbies",
"channels": [
"general",
"help"
]
},
{
"name": "general",
"channels": [
"general",
"chitchat",
"topic of the day"
]
}
]
}
};
The user’s username would be the key to the Object
value and each user was stored in a users.json
file which contained an Object
of users as properties.
JSON was also used to store the (data of the) body parameters of POST requests where the request or the response was encoded in JSON.
The data structure to store messages were also done by using a JSON Object
.
let content = {
"username": username,
"groupName": groupName,
"channelName": channelName,
"message": message,
"profileImage": profileImage,
"isFile": isFile
}
The username is used to show the user’s name who sent the message. The group and channel name are unique IDs for the message. The message itself is a string of text. The profileImage
is a path string to the statically served profile image on the server. The isFile
is a boolean which denotes whether this message is a text message or an image file being sent.
The chat application is separated into two parts, the client and the server. The client is created using the Angular framework. The client manages the models and views (components in Angular), which involves the dashboard, groups, channels and login. These components make up the single-page application (SPA) of the web chat app.
The server (back-end) is RESTful because it does not maintain any state. It has a number of routes which manages CRUD actions. The server connects to a MongoDB database which contains the data on the users and their messages, channels, groups and other information.
The REST API on the Node.js server was implemented using the Express library.
Object
on a user.Object
Object
of users.The Angular application contains components, services and routes.
There were four components that were used in this application.
The Channel component contains all the user-interface features of a chat channel. It contains a list of users, the current channel name, the chat box and the textfield and button to send messages.
The Dashboard component contains all the groups available to the user, their username, their current email, an input field to update their email and a log out button.
For Group admins, there’s a form to create new groups and buttons to remove groups. Note that default groups newbies and general cannot be removed.
For a Super admin, they can see the entire list of users in the system. Super admins can remove users from the system (except the persistent Super user) and assign Group or Super admin roles to existing users.
The Group component contains all the information for groups. This includes the group name, the logged in user, the available channels to the user and a log out button.
Group admins will have an input form to add new channels and buttons to remove channels. Note, default channel general cannot be removed (however an admin can remove a group in the Dashboard component).
Group admins can also add users to the group and remove users from the group. Adding a non-existent user simply creates the user and adds them to the group. Adding a user to the group automatically adds them to the default channel general.
The Login component allows a user to log in. Any user can type any username and log in. User data will persist after they log out. If a username does not exist in the system, the server will seamlessly create the user in the background.
The image service handles the upload of images to the server. It contains a function that performs a POST request to the server.
The socket service handles the web socket communications in real-time. The sockets contain three rooms:
Join notifies the server that the user has joined the channel. Leave notifies the server that the user has left the channel. New-message is used for new messages, which may be text or images.
The server responds in the message room, broadcasting only to the room which it originally received from.
The users service contains the requests for all dashboard, groups and channel data manipulation to and from the server.
npm init
npm install express
npm install socket.io
npm install body-parser
npm install @types/socket.io-client
- SocketIO for clientnpm install formidable
polyfill.ts
, add:
(window as any).global = window;
const bodyParser = require('body-parser')
app.use(bodyParser.json())
Author: Edmond Chuc
Website: www.edmondchuc.com
Repository: https://github.com/edmondchuc/web-chat-app