Files
web-chat/backend/socket.js
2024-08-25 19:10:47 +02:00

142 lines
5.3 KiB
JavaScript

const { Server } = require('socket.io');
const jwt = require('jsonwebtoken');
const jwtSecret = process.env.JWT_SECRET;
const { db } = require('./db.js');
function initializeSocket(server) {
const io = new Server(server, {
cookie: {
httpOnly: true,
sameSite: "strict",
maxAge: 30 * 24 * 60 * 60 * 1000
}
});
io.use((socket, next) => {
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'));
}
});
io.on('connection', (socket) => {
if (!socket.user) {
console.log('User not authenticated');
socket.disconnect();
return;
}
const username = socket.user.username;
console.log(username + ' connected');
// Join a room with the user's username
socket.join(username);
//loadInitialMessages(socket);
// 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);
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];
const formattedMessage = `Username: ${newMessage.username}, recipient: ${newMessage.recipient}, message: ${newMessage.content}`;
console.log(formattedMessage);
// 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);
}
if (!socket.recovered) {
try {
const query = 'SELECT id, content, username, recipient FROM messages WHERE id > $1 ORDER BY id ASC';
const values = [socket.handshake.auth.serverOffset || 0];
const result = await db.query(query, values);
//const newMessage = result.rows[0];
for (const row of result.rows) {
if (row.username === username || row.recipient === username) {
io.to(username).to(recipient).emit('chat message', { username: row.username, recipient: row.recipient, content: row.content });
}
}
} catch (e) {
console.error('Error retrieving messages:', e);
}
}
});
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;
console.log('Sending messages:', result.rows);
socket.emit('messages history', result.rows);
}
} catch (e) {
console.error('Error retrieving messages:', e);
}
});
// disconnect event
socket.on('disconnect', () => {
console.log(username + ' has disconnected');
});
});
return io;
}
async function loadInitialMessages(socket) {
const username = socket.user.username;
try {
const query = 'SELECT id, content, username, recipient FROM messages WHERE username = $1 OR recipient = $1 ORDER BY id DESC LIMIT 50';
const result = await db.query(query, [username]);
for (const row of result.rows.reverse()) {
socket.emit('chat message',row.username, row.recipient, row.content);
}
// Set the server offset to the latest message id
if (result.rows.length > 0) {
socket.handshake.auth.serverOffset = result.rows[result.rows.length - 1].id;
}
} catch (e) {
console.error('Error retrieving initial messages:', e);
}
}
module.exports = { initializeSocket };