You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

274 lines
8.0 KiB

import express, { Request, Response } from "express";
import { createServer, Server as HTTPServer } from "http";
import { Server as SocketIOServer, Socket } from "socket.io";
import cors from "cors";
import {
activeCallMapType,
callRequestAReject,
ConnectRequest,
OnlineUser,
rtcAnswer,
rtcCandidate,
rtcOffer,
UserDetails,
} from "./types/sType.js";
import { getSecsFromDates, saveCallLogs } from "./helper";
// Initialize Express
const app = express();
// Set up CORS middleware for Express
app.use(
cors({
origin: "*",
})
);
// Create an HTTP server
const httpServer: HTTPServer = createServer(app);
// Initialize Socket.io on the server
const io = new SocketIOServer(httpServer, {
path: "/socket", // Define the WebSocket path
cors: {
origin: "*", // Update this to the origin of your client
methods: ["GET", "POST"],
},
});
// Store online users
const onlineUsers: Map<string, OnlineUser> = new Map();
// Remap the socket ID to the user ID
const socketToUserId: Map<string, string> = new Map();
//call request
const activeCalls: activeCallMapType = new Map();
// Handle WebSocket connections
io.on("connection", (socket: Socket) => {
console.log("User connected", socket.id);
// Handle user-online event
socket.on("user-online", (user: UserDetails) => {
const { userId, userName, image } = user;
// Now we store the socket ID along with the user details
onlineUsers.set(userId, {
userId: userId,
userName,
image,
socketId: socket.id,
});
socketToUserId.set(socket.id, userId);
});
// Handle connect request event
socket.on("connect-req", (user: ConnectRequest) => {
const { caller, callee, userName, image } = user;
// Now we store the socket ID along with the user details
const details = onlineUsers.get(String(callee));
console.log("connect-req", details, onlineUsers, user);
if (details) {
socket.to(details.socketId).emit("connect-res", {
userId: caller,
userName,
image,
time: new Date(),
});
}
});
// Handle user-online event
socket.on("connect-reject-req", (data: { users: number[] }) => {
const { users } = data;
console.log("connect-reject-req", data);
// Now we store the socket ID along with the user details
for (const user of users) {
const details = onlineUsers.get(String(user));
console.log("connect-reject-req", details);
if (details) {
socket.to(details.socketId).emit("connect-reject-res", {
reject: true,
});
}
}
});
// Handle user disconnect event
socket.on("disconnect", async () => {
const user = activeCalls.get(socket.id);
console.log("disconnect", user);
if (user) {
if (user?.from) {
const calleeU = socketToUserId.get(socket.id);
const callerU = socketToUserId.get(user.from);
if (calleeU && callerU) {
const caller = onlineUsers.get(callerU);
const callee = onlineUsers.get(calleeU);
if (caller && callee) {
const meetTime = getSecsFromDates(user.callTime);
const callLog = {
to: callee.userId,
from: caller.userId,
time: meetTime,
};
await saveCallLogs(callLog);
socket.to(caller.socketId).emit("call-rejected");
}
}
}
if (user?.to) {
const callerU = socketToUserId.get(socket.id);
const calleeU = socketToUserId.get(user.to);
if (calleeU && callerU) {
const caller = onlineUsers.get(callerU);
const callee = onlineUsers.get(calleeU);
if (caller && callee) {
const meetTime = getSecsFromDates(user.callTime);
const callLog = {
to: callee.userId,
from: caller.userId,
time: meetTime,
};
await saveCallLogs(callLog);
socket.to(callee.socketId).emit("call-rejected");
}
}
}
const secUser = user?.to || user?.from;
if (secUser) {
activeCalls.delete(socket.id);
activeCalls.delete(secUser);
}
}
const userId = socketToUserId.get(socket.id);
if (userId) {
onlineUsers.delete(userId);
socketToUserId.delete(socket.id);
}
});
// Handle user ice candidate event
socket.on("ice-candidate", (data: rtcCandidate) => {
const { candidate, to } = data;
const calledTo = onlineUsers.get(to);
if (calledTo) {
console.log("get-ice-candidate", to);
// Emit to the recipient's socket ID
socket.to(calledTo.socketId).emit("get-ice-candidate", candidate);
}
});
// // Handle call-offer events
socket.on("offer", (data: rtcOffer) => {
const { offer, to, sender } = data;
const calledFrom = onlineUsers.get(sender);
const calledTo = onlineUsers.get(to);
if (calledTo && calledFrom) {
// Emit to the recipient's socket ID
socket.to(calledTo.socketId).emit("get-offer", {
offer,
sender: sender,
senderName: calledFrom.userName,
senderImage: calledFrom.image,
});
}
});
// // Handle call-request events
socket.on("call-request", (data: rtcAnswer) => {
const { answer, to } = data;
const calledTo = onlineUsers.get(to);
if (calledTo) {
socket.to(calledTo.socketId).emit("get-answer", answer);
}
});
// // Handle call-accept events
socket.on("call-accept", (data: callRequestAReject) => {
const { to, from } = data;
const calledTo = onlineUsers.get(to);
const calledFrom = onlineUsers.get(from);
if (calledTo && calledFrom) {
activeCalls.set(calledFrom.socketId, {
to: calledTo.socketId,
callTime: new Date(),
});
activeCalls.set(calledTo.socketId, {
from: calledFrom.socketId,
callTime: new Date(),
});
console.log("call-accept", activeCalls);
socket.to(calledTo.socketId).emit("call-accepted");
}
});
// // Handle call-reject events
socket.on("call-reject", async () => {
const user = activeCalls.get(socket.id);
if (user) {
if (user?.from) {
const calleeU = socketToUserId.get(socket.id);
const callerU = socketToUserId.get(user.from);
if (calleeU && callerU) {
const caller = onlineUsers.get(callerU);
const callee = onlineUsers.get(calleeU);
if (caller && callee) {
const meetTime = getSecsFromDates(user.callTime);
const callLog = {
to: callee.userId,
from: caller.userId,
time: meetTime,
};
await saveCallLogs(callLog);
socket.to(caller.socketId).emit("call-rejected");
}
}
}
if (user?.to) {
const callerU = socketToUserId.get(socket.id);
const calleeU = socketToUserId.get(user.to);
if (calleeU && callerU) {
const caller = onlineUsers.get(callerU);
const callee = onlineUsers.get(calleeU);
if (caller && callee) {
const meetTime = getSecsFromDates(user.callTime);
const callLog = {
to: callee.userId,
from: caller.userId,
time: meetTime,
};
await saveCallLogs(callLog);
socket.to(callee.socketId).emit("call-rejected");
}
}
}
const secUser = user?.to || user?.from;
if (secUser) {
activeCalls.delete(socket.id);
activeCalls.delete(secUser);
}
}
});
});
app.use(express.json());
// Define a basic route
app.get("/", (req: Request, res: Response) => {
res.send("WebSocket server is running");
});
// Define a basic route
app.post("/get-onlines", (req: Request, res: Response) => {
const { users }: { users: number[] } = req.body;
const onlineUsersData = users.filter((user: number) =>
onlineUsers.has(String(user))
);
res.json({ users: onlineUsersData });
});
// Start the server on port 3000
const PORT = process.env.PORT || 5007;
httpServer.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});