// express 설정 파일 import express from "express"; import cors from "cors"; import { Server } from "socket.io"; import http from "http"; import wrtc from "wrtc"; import cookieParser from "cookie-parser"; import mainRouter from "./routes/index.js"; const app = express(); app.use(cors()); const server = http.createServer(app); const io = new Server(server, { cors: { origin: "http://localhost:3000", methods: ["GET", "POST"], }, }); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use('/uploads', express.static('uploads')) app.use('/roomUploads', express.static('roomUploads')) app.use("/api", mainRouter); let receiverPCs = {}; let senderPCs = {}; let users = {}; let socketToRoom = {}; const pc_config = { iceServers: [ // { // urls: 'stun:[STUN_IP]:[PORT]', // 'credentials': '[YOR CREDENTIALS]', // 'username': '[USERNAME]' // }, { urls: "stun:stun.l.google.com:19302", }, ], }; const isIncluded = (array, id) => { let len = array.length; for (let i = 0; i < len; i++) { if (array[i].id === id) return true; } return false; }; const createReceiverPeerConnection = (socketID, socket, roomID) => { let pc = new wrtc.RTCPeerConnection(pc_config); if (receiverPCs[socketID]) receiverPCs[socketID] = pc; else receiverPCs = { ...receiverPCs, [socketID]: pc }; pc.onicecandidate = (e) => { //console.log(`socketID: ${socketID}'s receiverPeerConnection icecandidate`); socket.to(socketID).emit("getSenderCandidate", { candidate: e.candidate, }); }; pc.oniceconnectionstatechange = (e) => { //console.log(e); }; pc.ontrack = (e) => { if (users[roomID]) { if (!isIncluded(users[roomID], socketID)) { users[roomID].push({ id: socketID, stream: e.streams[0], }); } else return; } else { users[roomID] = [ { id: socketID, stream: e.streams[0], }, ]; } socket.broadcast.to(roomID).emit("userEnter", { id: socketID }); }; return pc; }; const createSenderPeerConnection = ( receiverSocketID, senderSocketID, socket, roomID ) => { let pc = new wrtc.RTCPeerConnection(pc_config); if (senderPCs[senderSocketID]) { senderPCs[senderSocketID].filter((user) => user.id !== receiverSocketID); senderPCs[senderSocketID].push({ id: receiverSocketID, pc: pc }); } else senderPCs = { ...senderPCs, [senderSocketID]: [{ id: receiverSocketID, pc: pc }], }; pc.onicecandidate = (e) => { //console.log(`socketID: ${receiverSocketID}'s senderPeerConnection icecandidate`); socket.to(receiverSocketID).emit("getReceiverCandidate", { id: senderSocketID, candidate: e.candidate, }); }; pc.oniceconnectionstatechange = (e) => { //console.log(e); }; const sendUser = users[roomID].filter((user) => user.id === senderSocketID); sendUser[0].stream.getTracks().forEach((track) => { pc.addTrack(track, sendUser[0].stream); }); return pc; }; const getOtherUsersInRoom = (socketID, roomID) => { let allUsers = []; if (!users[roomID]) return allUsers; let len = users[roomID].length; for (let i = 0; i < len; i++) { if (users[roomID][i].id === socketID) continue; allUsers.push({ id: users[roomID][i].id }); } return allUsers; }; const deleteUser = (socketID, roomID) => { let roomUsers = users[roomID]; if (!roomUsers) return; roomUsers = roomUsers.filter((user) => user.id !== socketID); users[roomID] = roomUsers; if (roomUsers.length === 0) { delete users[roomID]; } delete socketToRoom[socketID]; }; const closeRecevierPC = (socketID) => { if (!receiverPCs[socketID]) return; receiverPCs[socketID].close(); delete receiverPCs[socketID]; }; const closeSenderPCs = (socketID) => { if (!senderPCs[socketID]) return; let len = senderPCs[socketID].length; for (let i = 0; i < len; i++) { senderPCs[socketID][i].pc.close(); let _senderPCs = senderPCs[senderPCs[socketID][i].id]; let senderPC = _senderPCs.filter((sPC) => sPC.id === socketID); if (senderPC[0]) { senderPC[0].pc.close(); senderPCs[senderPCs[socketID][i].id] = _senderPCs.filter( (sPC) => sPC.id !== socketID ); } } delete senderPCs[socketID]; }; io.on("connection", (socket) => { console.log("socket connection complete"); socket.on("joinRoom", (data) => { try { let allUsers = getOtherUsersInRoom(data.id, data.roomID); io.to(data.id).emit("allUsers", { users: allUsers }); } catch (error) { console.log(error); } }); socket.on("senderOffer", async (data) => { try { socketToRoom[data.senderSocketID] = data.roomID; let pc = createReceiverPeerConnection( data.senderSocketID, socket, data.roomID ); await pc.setRemoteDescription(data.sdp); let sdp = await pc.createAnswer({ offerToReceiveAudio: true, offerToReceiveVideo: true, }); await pc.setLocalDescription(sdp); socket.join(data.roomID); io.to(data.senderSocketID).emit("getSenderAnswer", { sdp }); } catch (error) { console.log(error); } }); socket.on("senderCandidate", async (data) => { try { let pc = receiverPCs[data.senderSocketID]; await pc.addIceCandidate(new wrtc.RTCIceCandidate(data.candidate)); } catch (error) { console.log(error); } }); socket.on("receiverOffer", async (data) => { try { let pc = createSenderPeerConnection( data.receiverSocketID, data.senderSocketID, socket, data.roomID ); await pc.setRemoteDescription(data.sdp); let sdp = await pc.createAnswer({ offerToReceiveAudio: false, offerToReceiveVideo: false, }); await pc.setLocalDescription(sdp); io.to(data.receiverSocketID).emit("getReceiverAnswer", { id: data.senderSocketID, sdp, }); } catch (error) { console.log(error); } }); socket.on("receiverCandidate", async (data) => { try { const senderPC = senderPCs[data.senderSocketID].filter( (sPC) => sPC.id === data.receiverSocketID ); await senderPC[0].pc.addIceCandidate( new wrtc.RTCIceCandidate(data.candidate) ); } catch (error) { console.log(error); } }); socket.on("disconnect", () => { try { let roomID = socketToRoom[socket.id]; deleteUser(socket.id, roomID); closeRecevierPC(socket.id); closeSenderPCs(socket.id); socket.broadcast.to(roomID).emit("userExit", { id: socket.id }); } catch (error) { console.log(error); } }); }); export default server;