362 lines
10 KiB
JavaScript
362 lines
10 KiB
JavaScript
const {
|
|
insertMessage,
|
|
getConversationsForUser,
|
|
deleteContact,
|
|
deleteMessage,
|
|
removeUserFromGroupById,
|
|
isConversationMember,
|
|
isAdmin,
|
|
addAdministrator,
|
|
removeAdministrator,
|
|
updateContactStatus,
|
|
} = require("../db/db");
|
|
const { isValidUsername } = require("../utils/filter");
|
|
const { verifyJwtToken } = require("../auth/jwt");
|
|
|
|
function initializeSocket(io) {
|
|
io.use((socket, next) => {
|
|
const token = socket.handshake.auth.token;
|
|
if (!token) {
|
|
console.log("(socket) Not logged in");
|
|
return next(new Error("Not logged in"));
|
|
}
|
|
|
|
try {
|
|
const { username, user_id } = verifyJwtToken(token);
|
|
if (!username || !user_id) {
|
|
console.log("(socket) Invalid token payload");
|
|
return next(new Error("(socket) Invalid token payload"));
|
|
}
|
|
|
|
socket.username = username;
|
|
|
|
if (!isValidUsername(username)) {
|
|
console.log("(socket) Invalid username");
|
|
return;
|
|
}
|
|
|
|
socket.user_id = user_id;
|
|
console.log(
|
|
`(socket) socket id: ${socket.id}, username: ${username}, user_id: ${user_id}`,
|
|
);
|
|
next();
|
|
} catch (error) {
|
|
console.error("(socket) Token verification failed:", error.message);
|
|
next(new Error("(socket) Invalid token"));
|
|
}
|
|
});
|
|
|
|
io.on("connection", async (socket) => {
|
|
const username = socket.username;
|
|
if (!username) {
|
|
socket.on("disconnect", () => {
|
|
console.log(
|
|
"(socket)",
|
|
socket.id,
|
|
" disconnected due to: invalid username/token",
|
|
);
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (!isValidUsername(username)) {
|
|
socket.on("disconnect", () => {
|
|
console.log(
|
|
"(socket)",
|
|
socket.id,
|
|
" disconnected due to: invalid username/token",
|
|
);
|
|
});
|
|
return;
|
|
}
|
|
|
|
let conversations = [];
|
|
try {
|
|
conversations = await getConversationsForUser(socket.user_id);
|
|
conversations.push(socket.user_id);
|
|
socket.join(conversations);
|
|
console.log(`User: ${socket.username} joined to: ${conversations}`);
|
|
} catch (e) {
|
|
console.error("(socket) Failed to get user conversations");
|
|
}
|
|
|
|
socket.on("join room", async (conversation_id, callback) => {
|
|
const isMember = await isConversationMember(
|
|
socket.user_id,
|
|
conversation_id,
|
|
);
|
|
if (isMember) {
|
|
console.log("Join room for: ", username, "room: ", conversation_id);
|
|
socket.join(conversation_id);
|
|
return callback({
|
|
status: "ok",
|
|
message: "Successfully joined to conversation",
|
|
});
|
|
} else {
|
|
return callback({
|
|
status: "error",
|
|
message: "You are not member of this group",
|
|
});
|
|
}
|
|
});
|
|
|
|
socket.on("chat message", async (msg, callback) => {
|
|
const { message, recipient, recipient_id, attachment_urls } = msg;
|
|
const sender = socket.username;
|
|
|
|
if (!message && !attachment_urls) {
|
|
callback({
|
|
status: "error",
|
|
message: "No message or attachment provided",
|
|
});
|
|
return;
|
|
}
|
|
if (!recipient) {
|
|
callback({
|
|
status: "error",
|
|
message: "No recipient provided",
|
|
});
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const insertedMessage = await insertMessage(
|
|
socket.user_id,
|
|
recipient,
|
|
message,
|
|
attachment_urls,
|
|
);
|
|
if (!insertedMessage) {
|
|
callback({
|
|
status: "error",
|
|
message: "Failed to insert message",
|
|
});
|
|
return;
|
|
} else if (insertedMessage.length === 0) {
|
|
callback({
|
|
status: "error",
|
|
message: "You are not an member of this conversation",
|
|
});
|
|
}
|
|
const { message_id, content, sent_at, sender_id, conversation_id } =
|
|
insertedMessage;
|
|
console.log("(socket) received from chat message", msg);
|
|
|
|
io.to(recipient).to(recipient_id).emit("chat message", {
|
|
sender,
|
|
message: content,
|
|
attachment_urls,
|
|
recipient,
|
|
message_id,
|
|
sender_id,
|
|
sent_at,
|
|
conversation_id,
|
|
});
|
|
console.log(
|
|
`(socket) sent on 'chat message' socket to: recipient: ${recipient}, recipient_id: ${recipient_id} `,
|
|
{
|
|
sender,
|
|
message,
|
|
attachment_urls,
|
|
recipient,
|
|
sent_at,
|
|
message_id,
|
|
sender_id,
|
|
},
|
|
);
|
|
|
|
callback({
|
|
message_id,
|
|
status: "ok",
|
|
message: "Received message",
|
|
});
|
|
} catch (e) {
|
|
console.error("(socket) Failed to insert message ", e);
|
|
callback({
|
|
status: "error",
|
|
message: "Internal server error",
|
|
});
|
|
}
|
|
});
|
|
|
|
socket.on("delete message", async (msg, callback) => {
|
|
const { conversation_id, message_id } = msg;
|
|
if (!message_id) {
|
|
return callback({ status: "error", message: "No message id provided" });
|
|
}
|
|
if (!conversation_id) {
|
|
return callback({
|
|
status: "error",
|
|
message: "No conversation id provided",
|
|
});
|
|
}
|
|
|
|
const result = await deleteMessage(
|
|
socket.user_id,
|
|
conversation_id,
|
|
message_id,
|
|
);
|
|
if (result?.message !== undefined) {
|
|
return callback({ status: "error", message: result.message });
|
|
} else {
|
|
io.to(conversation_id).emit("delete message", {
|
|
conversation_id,
|
|
message_id,
|
|
});
|
|
return callback({
|
|
status: "ok",
|
|
message: "Successfully deleted message",
|
|
});
|
|
}
|
|
});
|
|
|
|
socket.on("delete contact", async (conversation_id, callback) => {
|
|
console.log(
|
|
"(socket) delete contact, conversation_id: ",
|
|
conversation_id,
|
|
);
|
|
const user_id = socket.user_id;
|
|
if (!conversation_id) {
|
|
callback({ status: "error", message: "No conversation id provided" });
|
|
}
|
|
const result = await deleteContact(user_id, conversation_id);
|
|
|
|
if (result?.message) {
|
|
callback({ status: "error", message: result.message });
|
|
}
|
|
callback({ status: "ok", message: "Successfully deleted contact" });
|
|
io.to(conversation_id).emit("left group", { conversation_id, user_id });
|
|
});
|
|
|
|
socket.on("remove user from group", async (msg, callback) => {
|
|
const { group_id, user_id } = msg;
|
|
|
|
if (!group_id) {
|
|
return callback({ status: "error", message: "No group id provided" });
|
|
}
|
|
if (!user_id) {
|
|
return callback({ status: "error", message: "No user id provided" });
|
|
}
|
|
|
|
try {
|
|
const result = await removeUserFromGroupById(group_id, user_id);
|
|
|
|
if (result?.message) {
|
|
return callback({ status: "error", message: result.message });
|
|
}
|
|
|
|
// Get all sockets in the room
|
|
const socketsInRoom = await io.in(group_id).fetchSockets();
|
|
// Remove user from room
|
|
for (const socketInstance of socketsInRoom) {
|
|
if (socketInstance.user_id === user_id) {
|
|
socketInstance.leave(group_id);
|
|
}
|
|
}
|
|
|
|
io.to(group_id).to(user_id).emit("left group", {
|
|
group_id,
|
|
user_id,
|
|
});
|
|
console.log(
|
|
`Successfully removed user: ${user_id}, from group: ${group_id}`,
|
|
);
|
|
return callback({
|
|
status: "ok",
|
|
message: "Successfully removed user from group",
|
|
});
|
|
} catch (error) {
|
|
console.error("Failed to remove user from group:", error);
|
|
return callback({
|
|
status: "error",
|
|
message: "Internal server error",
|
|
});
|
|
}
|
|
});
|
|
|
|
socket.on("added administrator", async (msg, callback) => {
|
|
const { group_id, user_id } = msg;
|
|
if (!group_id) {
|
|
return callback({
|
|
status: "error",
|
|
message: "No conversation id provided",
|
|
});
|
|
}
|
|
if (!user_id) {
|
|
return callback({ status: "error", message: "No user id provided" });
|
|
}
|
|
const isUserAdmin = await isAdmin(socket.user_id, group_id);
|
|
if (!isUserAdmin) {
|
|
return callback({
|
|
status: "error",
|
|
message: "You is not an administrator",
|
|
});
|
|
}
|
|
const result = await addAdministrator(group_id, user_id, socket.user_id);
|
|
if (result?.message) {
|
|
return callback({ status: "error", message: result.message });
|
|
}
|
|
console.log(
|
|
`Successfully added user: ${user_id} to administrators to group: ${group_id}`,
|
|
);
|
|
io.to(group_id).emit("added administrator", {
|
|
group_id,
|
|
user_id,
|
|
});
|
|
|
|
return callback({
|
|
status: "ok",
|
|
message: "Successfully added administrator",
|
|
});
|
|
});
|
|
|
|
socket.on("removed administrator", async (msg, callback) => {
|
|
const { group_id, user_id } = msg;
|
|
if (!group_id) {
|
|
return callback({
|
|
status: "error",
|
|
message: "No conversation id provided",
|
|
});
|
|
}
|
|
if (!user_id) {
|
|
return callback({ status: "error", message: "No user id provided" });
|
|
}
|
|
|
|
const result = await removeAdministrator(
|
|
group_id,
|
|
user_id,
|
|
socket.user_id,
|
|
);
|
|
if (result?.message) {
|
|
return callback({ status: "error", message: result.message });
|
|
}
|
|
console.log(
|
|
`Successfully removed user: ${user_id} from administrators in group: ${group_id}`,
|
|
);
|
|
io.to(group_id).emit("removed administrator", {
|
|
group_id,
|
|
user_id,
|
|
});
|
|
return callback({
|
|
status: "ok",
|
|
message: "Successfully removed administrator",
|
|
});
|
|
});
|
|
|
|
socket.on("message read", async (msg) => {
|
|
const { conversation_id, message_id } = msg;
|
|
if (!conversation_id || !message_id) {
|
|
return;
|
|
}
|
|
console.error("MESSGE READ: ", conversation_id, message_id);
|
|
await updateContactStatus(socket.user_id, conversation_id, message_id);
|
|
});
|
|
|
|
socket.on("disconnect", (reason) => {
|
|
console.log("(socket)", socket.id, " disconnected due to: ", reason);
|
|
});
|
|
});
|
|
}
|
|
|
|
module.exports = { initializeSocket };
|