├── public
├── p.jpg
├── Chat Wallpaper.jpg
├── index.html
├── script.js
└── styles.css
├── package.json
├── README.md
└── index.js
/public/p.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/softenrj/Real-Time-Chat-Room/HEAD/public/p.jpg
--------------------------------------------------------------------------------
/public/Chat Wallpaper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/softenrj/Real-Time-Chat-Room/HEAD/public/Chat Wallpaper.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "p5(p2p-message)",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "type": "module",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "express": "^4.19.2",
15 | "socket.io": "^4.7.5"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | P2P chatting app
7 |
8 |
9 |
10 |
11 |
12 |
17 |
18 |
19 |
20 |

21 |
22 |
Create new
23 |
No user
24 |
25 |
offline
26 |
27 |
28 |
29 |
31 |
32 |
33 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # P2P Chatting App
2 |
3 | ## Overview
4 |
5 | The P2P Chatting App is a real-time chat application allowing users to join chat rooms and communicate with each other. Built using Socket.io and Express.js, this app demonstrates real-time communication and room management functionalities.
6 |
7 | ## Features
8 |
9 | - **Real-time Messaging:** Send and receive messages instantly within a room.
10 | - **User Presence:** See who is online and who has joined or left the room.
11 | - **Typing Indicator:** Display when users are typing a message.
12 | - **Responsive Design:** Works on both desktop and mobile devices.
13 |
14 | ## Technologies Used
15 |
16 | - **Frontend:**
17 | - HTML
18 | - CSS
19 | - JavaScript
20 | - Socket.io client
21 |
22 | - **Backend:**
23 | - Node.js
24 | - Express.js
25 | - Socket.io server
26 |
27 | ## Installation
28 |
29 | 1. **Clone the Repository**
30 |
31 | ```bash
32 | git clone https://github.com/softenrj/P2P-chatting-app.git
33 |
34 | 2. **Navigate to the Project Directory**
35 |
36 | ```bash
37 | cd P2P-chatting-app
38 |
39 | 3. **Install Dependencies**
40 | Make sure you have Node.js installed. Then run:
41 |
42 | ```bash
43 | npm install
44 |
45 | 4. **Run the Server**
46 |
47 | ```bash
48 | nodemon index.js
49 |
50 | 5. **Open the App**
51 | Open your browser and navigate to http://localhost:3000 to use the chat application.
52 |
53 | ## Usage
54 |
55 | 1. **Join a Room:**
56 | - Enter your username and room name in the fields provided and click "OK" to join a room.
57 |
58 | 2. **Send Messages:**
59 |
60 | - Type your message in the input box and press "Send" or hit Enter.
61 |
62 | 3. **See User Activity:**
63 |
64 | - The chat area will display user. activity, including who is typing.
65 |
66 | ## Contributing
67 | Feel free to fork this repository and submit pull requests. For any issues or feature requests, please open an issue on the GitHub repository.
68 |
69 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | import { createServer } from "http";
3 | import { Server } from "socket.io";
4 |
5 | const app = express();
6 | const httpServer = createServer(app);
7 | const io = new Server(httpServer, {});
8 |
9 | app.use(express.static('public'));
10 |
11 | // Object to store users by room
12 | const roomUsers = {};
13 |
14 | io.on("connection", (socket) => {
15 | console.log(`A user is connected with id: ${socket.id}`);
16 |
17 |
18 | // Handle joining a room
19 | socket.on('join-room', (room, user) => {
20 | socket.join(room);
21 | console.log(`${user} joined room: ${room}`);
22 |
23 |
24 | // Initialize room in roomUsers if not exists
25 | if (!roomUsers[room]) {
26 | roomUsers[room] = {};
27 | }
28 | roomUsers[room][socket.id] = user;
29 |
30 | io.to(room).emit("userList", Object.values(roomUsers[room]));
31 | io.to(room).emit("userJoin",`${user} joined room`);
32 | });
33 |
34 | // Handle sending a message
35 | socket.on("send-msg", (message, room, user) => {
36 | // For your eyes only! Uncomment for secret message spy mode 😅
37 | // console.log(`Message received from ${user} in room ${room}: ${message}`);
38 |
39 | // Ninja mode: sending the message to everyone in the room except the sneaky sender
40 | socket.to(room).emit("received", message, user);
41 | });
42 |
43 |
44 | // Handle typing notification
45 | socket.on("typing", (room, userName) => {
46 | socket.to(room).emit("typing", `${userName} is typing...`);
47 | });
48 |
49 | socket.on("stop-typing", (room) => {
50 | socket.to(room).emit("stop-typing");
51 | });
52 |
53 | // Handle user disconnection
54 | socket.on("disconnect", () => {
55 | console.log(`User disconnected with id: ${socket.id}`);
56 |
57 | for (const [room, users] of Object.entries(roomUsers)) {
58 | if (users[socket.id]) {
59 | const userName = users[socket.id];
60 | delete users[socket.id];
61 |
62 | // Notify the room that the user has left
63 | io.to(room).emit("receive", `${userName} has left the room`, 'Admin');
64 |
65 | // Send the updated user list
66 | io.to(room).emit("userList", Object.values(users));
67 | }
68 | }
69 |
70 | });
71 |
72 | });
73 |
74 | httpServer.listen(3000, () => {
75 | console.log("Server is running on port 3000");
76 | });
77 |
--------------------------------------------------------------------------------
/public/script.js:
--------------------------------------------------------------------------------
1 | //join room
2 | const userName = document.querySelector(".username");
3 | const roomName = document.querySelector(".roomname");
4 | const joinForm = document.querySelector(".join");
5 |
6 | //info
7 | const roomDisp = document.querySelector(".room");
8 | const usersName = document.querySelector(".users");
9 | const activity = document.querySelector(".activity");
10 |
11 | // chat area
12 | const chatArea = document.querySelector(".chat-display");
13 |
14 | //send message
15 | const messageSend = document.querySelector(".send-message");
16 | const msgForm = document.querySelector(".sendmessage");
17 |
18 |
19 | msgForm.addEventListener("submit",e =>{
20 | e.preventDefault();
21 | const message = messageSend.value;
22 | if(message==="") return;
23 |
24 | displayMessage(message,userName.value);
25 |
26 | //clint to server
27 | socket.emit("send-msg",message,roomName.value,userName.value);
28 | messageSend.value ="";
29 | })
30 |
31 |
32 | function displayMessage(m, anyUser) {
33 | let li = document.createElement("li");
34 | if (anyUser !== userName.value) {
35 | li.innerHTML = `
36 |
37 |
${anyUser}
38 |
39 |
40 | ${m}
41 |
42 |
${new Date().toLocaleTimeString('en-US', {
43 | hour: '2-digit',
44 | minute: '2-digit',
45 | hour12: true
46 | })
47 | }
48 |
49 | `;
50 | } else {
51 | li.innerHTML = `
52 |
53 |
You
54 |
55 |
56 | ${m}
57 |
58 |
${new Date().toLocaleTimeString('en-US', {
59 | hour: '2-digit',
60 | minute: '2-digit',
61 | hour12: true
62 | })
63 | }
64 |
65 | `;
66 | }
67 | chatArea.appendChild(li);
68 | chatArea.scrollTop = chatArea.scrollHeight;
69 | }
70 |
71 | function serverMsg(m){
72 | let p = document.createElement("p");
73 | p.className="admin";
74 | p.innerHTML=`
75 | ${m}
76 | `;
77 | chatArea.scrollTop = chatArea.scrollHeight;
78 | chatArea.prepend(p);
79 | }
80 |
81 |
82 |
83 | //socket
84 |
85 | const socket = io();
86 |
87 | socket.on("connect",()=>{
88 | serverMsg(`Default You connect to ${socket.id} \n create room or join from above`);
89 | })
90 |
91 | socket.on("received",(message,anyUser)=>{
92 | displayMessage(message,anyUser);
93 | })
94 |
95 | socket.on("userJoin",(m)=>{
96 | newJoin(m);
97 | })
98 |
99 | function newJoin(m){
100 | let p = document.createElement("p");
101 | p.className="admin";
102 | p.innerHTML=`
103 | ${m}
104 | `;
105 | chatArea.scrollTop = chatArea.scrollHeight;
106 | chatArea.appendChild(p);
107 | }
108 |
109 | //room
110 | joinForm.addEventListener("submit",(e)=>{
111 | e.preventDefault();
112 | const room = roomName.value.trim();
113 | const user = userName.value.trim();
114 |
115 | if(room && user){
116 | socket.emit('join-room',room,user);
117 | }
118 |
119 | roomDisp.innerHTML=roomName.value;
120 | activity.innerHTML="online";
121 | })
122 |
123 | //show activity
124 |
125 | let typingTimeout;
126 |
127 | messageSend.addEventListener("input",()=>{
128 | console.log("hellolllllll");
129 | socket.emit("typing",roomName.value,userName.value);
130 | clearTimeout(typingTimeout);
131 | typingTimeout = setTimeout(()=>{
132 | socket.emit("stop-typing",roomName.value);
133 | },1000)
134 | })
135 |
136 | socket.on("typing", (m) => {
137 | console.log("dsssssss");
138 | activity.innerHTML = m;
139 | });
140 |
141 | socket.on("stop-typing", () => {
142 | activity.innerHTML = '';
143 | });
144 |
145 |
146 | //user list
147 | socket.on("userList", (users) => {
148 | usersName.innerHTML = '';
149 | for (let i = 0; i < users.length; i++) {
150 | if (i === 0) {
151 | usersName.innerHTML += users[i];
152 | } else {
153 | usersName.innerHTML += ", " + users[i];
154 | }
155 | }
156 | });
157 |
158 |
--------------------------------------------------------------------------------
/public/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Anton&family=Bebas+Neue&family=Comfortaa:wght@300..700&family=Edu+AU+VIC+WA+NT+Hand:wght@400..700&family=Kalnia+Glaze:wght@100..700&family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap');
2 |
3 | body {
4 | height: 100vh;
5 | display: grid;
6 | place-items: center;
7 |
8 | }
9 |
10 | * {
11 | margin: 0;
12 | padding: 0;
13 | }
14 |
15 | .container {
16 | background-image: url("./Chat\ Wallpaper.jpg");
17 | background-size:cover;
18 | background-position: center;
19 | width: 400px;
20 | border: 3px solid rgba(0, 0, 0, 0.884);
21 | border-radius: 16px;
22 | transition: all 0.3s ease;
23 |
24 | }
25 |
26 |
27 | .join {
28 | width: 98.5%;
29 | background-color: rgb(0, 0, 0);
30 | height: 25px;
31 | border-radius: 12px 12px 0px 0px;
32 | padding-left: 6px;
33 |
34 | }
35 |
36 | .join input {
37 | border: none;
38 | font-size: x-small;
39 | padding: 3.5px;
40 | }
41 |
42 | input:focus {
43 | outline: none;
44 | }
45 |
46 | .join-btn {
47 | background-color: rgb(0, 162, 255);
48 | border: none;
49 | padding: 2px;
50 | color: white;
51 | }
52 |
53 | .head {
54 | background-color: rgb(223, 221, 221);
55 | border-radius: 0px 0px 20px 20px;
56 | display: flex;
57 | padding: 5px;
58 | padding-bottom: 2px;
59 | }
60 |
61 | .head>img {
62 | border-radius: 50%;
63 | height: 60px;
64 | width: 60px;
65 | border: 2px solid white;
66 | }
67 |
68 | .info {
69 | color: rgb(0, 0, 0);
70 | font-weight: bolder;
71 | font-size: 15px;
72 | margin-left: 12px;
73 | margin-top: 5px;
74 |
75 | }
76 |
77 | .room {
78 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
79 | font-weight: 500;
80 | font-style: normal;
81 | font-size: 20px;
82 | }
83 |
84 | .users {
85 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
86 | font-size: small;
87 | font-weight: 400;
88 | margin-left: 2px;
89 | position: relative;
90 | top: -2px;
91 | }
92 |
93 | .activity {
94 | margin-left: 100px;
95 | font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
96 | font-weight: 400;
97 | font-size: 12px;
98 | }
99 | .chat-display {
100 | overflow-y: auto;
101 | height: 65vh;
102 | display: flex;
103 | flex-direction: column;
104 | }
105 |
106 | .left-chat {
107 | background-color: rgb(109, 187, 109);
108 | color: white;
109 | justify-self: flex-start;
110 | margin-top: 20px;
111 | margin-left: 10px;
112 | word-wrap: break-word;
113 | max-width: 90%;
114 | border-radius: 12px;
115 | padding-bottom: 14px;
116 | }
117 |
118 | .name-l {
119 | font-size: 12px;
120 | margin-left: 5px;
121 | }
122 |
123 | .message {
124 | margin-top: 5px;
125 | margin-left: 15px;
126 | word-wrap: break-word;
127 | margin-right: 15px;
128 | font-family:Verdana, Geneva, Tahoma, sans-serif;
129 | font-optical-sizing: auto;
130 | font-weight: normal;
131 | font-style: normal;
132 | margin-bottom: 5px;
133 | }
134 |
135 | .time-l {
136 | font-weight: lighter;
137 | font-size: 10px;
138 | margin-bottom: 5px;
139 | float: right;
140 | margin-right: 12px;
141 | }
142 |
143 | .right-chat {
144 | background-color: white;
145 | justify-self: flex-end;
146 | margin-top: 20px;
147 | margin-right: 10px;
148 | word-wrap: break-word;
149 | max-width: 90%;
150 | border-radius: 12px;
151 | padding-bottom: 16px;
152 | }
153 |
154 | .name-r {
155 | font-size: 12px;
156 | margin-left: 140px;
157 | }
158 |
159 | .time-r {
160 | font-weight: lighter;
161 | font-size: 10px;
162 | float: right;
163 | position: relative;
164 | top: 4px;
165 | left: -10px;
166 | }
167 |
168 | .sendmessage {
169 | margin-left: 13px;
170 | width: 100%;
171 | margin-bottom: 10px;
172 | }
173 |
174 | .sendmessage .msg>input {
175 | padding: 6px;
176 | border-radius: 6px;
177 | height: 28px;
178 | width: 76%;
179 | border: none;
180 | line-height: 24px;
181 | }
182 |
183 | .sendmessage .msg>button {
184 | height: 40px;
185 | border-radius: 6px;
186 | border: none;
187 | background-color: rgb(0, 81, 255);
188 | color: white;
189 | width: 50px;
190 | margin-left: 5px;
191 | }
192 |
193 |
194 |
195 | ::-webkit-scrollbar {
196 | width: 2px;
197 | height: 2px;
198 | }
199 |
200 | ::-webkit-scrollbar-button {
201 | width: 0px;
202 | height: 0px;
203 | }
204 |
205 | ::-webkit-scrollbar-thumb {
206 | background: #00000000;
207 | border: 0px none #ffffff00;
208 | border-radius: 50px;
209 | }
210 |
211 | ::-webkit-scrollbar-thumb:hover {
212 | background: #00000000;
213 | }
214 |
215 | ::-webkit-scrollbar-thumb:active {
216 | background: #00000000;
217 | }
218 |
219 | ::-webkit-scrollbar-track {
220 | background: #ffffff00;
221 | border: 0px none #ffffff00;
222 | border-radius: 50px;
223 | }
224 |
225 | ::-webkit-scrollbar-track:hover {
226 | background: #66666600;
227 | }
228 |
229 | ::-webkit-scrollbar-track:active {
230 | background: #33333300;
231 | }
232 |
233 | ::-webkit-scrollbar-corner {
234 | background: transparent;
235 | }
236 |
237 | .admin {
238 | background-color: #ffffff6a;
239 | text-align: center;
240 | font-size: small;
241 | margin-top: 5px;
242 | width: 350px;
243 | margin-left: 25px;
244 | border-radius: 5px;
245 | font-weight: 500;
246 | }
247 |
248 | @media only screen and (max-width: 480px) {
249 | body {
250 | height: 93vh;
251 | font-family: "Open Sans", sans-serif;
252 | font-optical-sizing: auto;
253 | font-weight: bold;
254 | font-style: normal;
255 | font-variation-settings:
256 | "wdth" 100;
257 | display: block;
258 | width: 47vb;
259 |
260 |
261 | }
262 |
263 | .container {
264 | background-image: url("./chat\ back.png");
265 | background-size: cover;
266 | height: 93vh;
267 | width: 100%;
268 | border: none;
269 | border-radius: 0;
270 | padding: 0;
271 | box-sizing: border-box;
272 | overflow: hidden;
273 | }
274 |
275 | .admin {
276 | width: calc(100vw - 40px);
277 | margin-left: 20px;
278 | }
279 |
280 | .join {
281 | width: 98.5%;
282 | background-color: rgb(207, 205, 205);
283 | height: 35px;
284 | padding-left: 6px;
285 | border-radius: 0px 0px 0px 0px;
286 | }
287 |
288 | .join input {
289 | border: none;
290 | font-size: x-small;
291 | padding: 5px;
292 | margin-top: 6px;
293 | }
294 |
295 |
296 | .join-btn {
297 | background-color: rgb(0, 162, 255);
298 | border: none;
299 | padding: 5px;
300 | color: white;
301 | }
302 |
303 | .head {
304 | background-color: rgb(255, 255, 255);
305 | display: flex;
306 | padding: 5px;
307 | }
308 |
309 | .head>img {
310 | border-radius: 50%;
311 | height: 50px;
312 | width: 50px;
313 | border: 2px solid white;
314 | }
315 |
316 | .info {
317 | color: rgb(0, 0, 0);
318 | font-weight: bolder;
319 | font-size: 15px;
320 | margin-left: 15px;
321 | }
322 |
323 | .activity {
324 | margin-left: 92px;
325 | }
326 |
327 | .chat-display {
328 | overflow-y: auto;
329 | height: 72vh;
330 | }
331 |
332 | .sendmessage {
333 | margin-left: 13px;
334 | width: 100%;
335 | }
336 |
337 | .sendmessage .msg>input {
338 | padding: 6px;
339 | border-radius: 6px;
340 | height: 28px;
341 | width: 76%;
342 | border: none;
343 | line-height: 24px;
344 | }
345 |
346 | .right-chat {
347 | background-color: white;
348 | width: 180px;
349 | border-radius: 15px 0px 15px 15px;
350 | -webkit-border-radius: 15px 0px 15px 15px;
351 | -moz-border-radius: 15px 0px 15px 15px;
352 | position: relative;
353 | margin-bottom: 25px;
354 | left: 190px;
355 | }
356 | .name-r {
357 | font-size: 12px;
358 | margin-left: 122px;
359 | }
360 |
361 |
362 | }
363 |
--------------------------------------------------------------------------------