Files
web-chat/backend/socket.js

199 lines
7.4 KiB
JavaScript

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', () => {
return "Disconnected";
});
});
return io;
}
module.exports = { initializeSocket };