const { Server } = require("socket.io"); const jwt = require("jsonwebtoken"); const jwtSecret = process.env.JWT_SECRET; const { db } = require("./db.js"); const { json } = require("express"); function initializeSocket(server) { const io = new Server(server, { cookie: { httpOnly: true, sameSite: "strict", maxAge: 30 * 24 * 60 * 60 * 1000, }, }); io.use((socket, next) => { // user auth const token = socket.handshake.auth.token; if (token) { jwt.verify(token, jwtSecret, (err, user) => { if (err) { console.log(err); return next(new Error("Authentication error")); } socket.user = user; next(); }); } else { next(new Error("Not logged in")); } }); // open main socket connection io.on("connection", (socket) => { if (!socket.user) { socket.emit("socket error", "User not authenticated"); socket.disconnect(); return; } const username = socket.user.username; // Join a room with the user's username socket.join(username); io.to(username).emit("username", username); // chat message event socket.on("chat message", async (msgData) => { const { content, recipient } = msgData; let insertedId; try { // Insert the new message into the database const result = await db.query( "INSERT INTO messages (content, username, recipient) VALUES ($1, $2, $3) RETURNING id", [content, username, recipient], ); insertedId = result.rows[0].id; } catch (err) { console.error("Error inserting message:", err); socket.emit( "socket error", "Error inserting message, try refreshing the page", ); return; } // Fetch the newly inserted message from the database try { const query = "SELECT id, content, username, recipient FROM messages WHERE id = $1"; const result = await db.query(query, [insertedId]); if (result.rows.length > 0) { const newMessage = result.rows[0]; // Emit message to the sender's and recipient's rooms io.to(username).to(recipient).emit("chat message", { username: newMessage.username, recipient: newMessage.recipient, content: newMessage.content, }); } } catch (err) { console.error("Error fetching inserted message:", err); socket.emit("socket error", "Failed to send message"); } }); socket.on("get messages", async (recipient) => { const username = socket.user.username; try { const query = ` SELECT id, content, username, recipient FROM messages WHERE (username = $1 AND recipient = $2) OR (username = $2 AND recipient = $1) ORDER BY id ASC `; const result = await db.query(query, [username, recipient]); if (result.rows.length > 0) { //const { username: sender, recipient: receiver, content: content, id: id } = result.rows; io.to(username).emit("messages history", result.rows); } else { io.to(username).emit("no messages"); } } catch (e) { console.error("Error retrieving messages:", e); socket.emit( "socket error", "Error retrieving messages, refresh the page (server error)", ); } }); // Contacts socket socket.on("contacts", async (contactUsername) => { const username = socket.user.username; const status = contactUsername.status === "read" ? "read" : "unread"; // Update contact list in db try { const query = ` INSERT INTO contacts (username, contact, status) SELECT $1, $2, $3 WHERE NOT EXISTS ( SELECT 1 FROM contacts WHERE username = $1 AND contact = $2 ) `; await db.query(query, [username, contactUsername.contact, status]); } catch (err) { console.error("Failed to update contacts ", err); socket.emit("socket error", "Failed to update contacts (server error)"); } // Get contact list from db try { const query = ` SELECT contact, username, status FROM contacts WHERE username = $1 `; const result = await db.query(query, [username]); io.to(username).emit("contacts", result.rows); } catch (err) { console.error("Failed to get contacts from db"); io.to(username).emit( "socket error", "Failed to get contacts (server error)", ); } }); socket.on("get contacts", async () => { const username = socket.user.username; try { const query = ` SELECT contact, username, status FROM contacts WHERE username = $1 `; const result = await db.query(query, [username]); io.to(username).emit("contacts", result.rows); } catch (err) { console.error("Failed to get contacts from db"); io.to(username).emit( "socket error", "Failed to get contacts (server error)", ); } }); socket.on("delete contact", async (contactUsername) => { const username = socket.user.username; try { const query = "DELETE FROM contacts WHERE (username = $1 AND contact = $2)"; await db.query(query, [username, contactUsername]); } catch (err) { console.error("Failed to remove contact from db"); io.to(username).emit( "socket error", "Failed to remove contact (server error)", ); } }); socket.on("status", async (username) => { const userUsername = socket.user.username; const status = "unread"; try { const query = "UPDATE contacts SET status = $1 WHERE username = $2 AND contact = $3"; await db.query(query, [status, userUsername, username]); io.to(userUsername).emit("status", username); } catch (err) { console.error("Failed to update unread status:", err); } }); socket.on("read", async (contactUsername) => { const userUsername = socket.user.username; const status = "read"; try { const query = "UPDATE contacts SET status = $1 WHERE username = $2 AND contact = $3"; await db.query(query, [status, userUsername, contactUsername]); io.to(userUsername).emit("status", contactUsername); } catch (err) { console.error("Failed to update unread status:", err); } }); // disconnect event socket.on("disconnect", () => { console.log(socket.id, " disconnected"); return "Disconnected"; }); }); return io; } module.exports = { initializeSocket };