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}`);
|
|
});
|