프로그래밍 언어/NODE JS

미들웨어와 소켓 연결하기(2)

· 코딩마이데이

 이제 라우터 부분을 작성합니다. 라우터에서 몽고디비의 웹 소켓 모두에 접근할 수 있습니다.

const express = require("express");

const Room = require("../schemas/room");
const Chat = require("../schemas/chat");

const router = express.Router();

router.get("/", async (req, res, next) => {
  try {
    const rooms = await Room.find({});
    res.render("main", { rooms, title: "GIF 채팅방" });
  } catch (error) {
    console.error(error);
    next(error);
  }
});

router.get("/room", (req, res) => {
  res.render("room", { title: "GIF 채팅방 생성" });
});

router.post("/room", async (req, res, next) => {
  // ➊
  try {
    const newRoom = await Room.create({
      title: req.body.title,
      max: req.body.max,
      owner: req.session.color,
      password: req.body.password,
    });
    const io = req.app.get("io");
    io.of("/room").emit("newRoom", newRoom);
    res.redirect(`/room/${newRoom._id}?password=${req.body.password}`);
  } catch (error) {
    console.error(error);
    next(error);
  }
});

router.get("/room/:id", async (req, res, next) => {
  // ➋
  try {
    const room = await Room.findOne({ _id: req.params.id });
    const io = req.app.get("io");
    if (!room) {
      return res.redirect("/?error=존재하지 않는 방입니다.");
    }
    if (room.password && room.password !== req.query.password) {
      return res.redirect("/?error=비밀번호가 틀렸습니다.");
    }
    const { rooms } = io.of("/chat").adapter;
    if (
      rooms &&
      rooms[req.params.id] &&
      room.max <= rooms[req.params.id].length
    ) {
      return res.redirect("/?error=인원이 가득 찬 방입니다.");
    }
    return res.render("chat", {
      room,
      title: room.title,
      chats: [],
      user: req.session.color,
    });
  } catch (error) {
    console.error(error);
    next(error);
  }
});

router.delete("/room/:id", async (req, res, next) => {
  // ➌
  try {
    await Room.remove({ _id: req.params.id });
    await Chat.remove({ room: req.params.id });
    res.send("ok");
    setTimeout(() => {
      req.app;
    }, 2000);
  } catch (error) {
    console.error(error);
    next(error);
  }
});

module.exports = router;

 

GET / 라우터는 채팅방 목록이 보이는 메인 화면을 렌더링하는 라우터고, GET /room 라우터는 채팅방 생성 화면을 렌더링하는 라우터입니다. POST /room, GET /room/:id, DELETE /room/:id 라우터를 주목해서 봐야 합니다.

➊ POST /room 라우터는 채팅방을 만드는 라우터입니다. app.set('io', io)로 저장했던 io 객체를 req.app.get('io')로 가져옵니다. io.of('/room').emit 메서드는 /room 네임스페이스에 연결한 모든 클라이언트에 데이터를 보내는 메서드입니다. GET / 라우터에 접속한 모든 클라이언트가 새로 생성된 채팅방에 대한 데이터를 받을 수 있습니다. 네임스페이스가 따로 없는 경우에는 io.emit 메서드로 모든 클라이언트에 데이터를 보낼 수 있습니다.

➋ GET /room/:id는 채팅방을 렌더링하는 라우터입니다. 렌더링 전에 방이 존재하는지, 비밀방일 경우에는 비밀번호가 맞는지, 허용 인원을 초과하지는 않았는지 검사합니다. io.of('/chat').adapter.rooms에 방 목록이 들어 있습니다. io.of('/chat').adapter.rooms[req.params.id]를 하면 해당 방의 소켓 목록이 나옵니다. 이것으로 소켓의 수를 세서 참가 인원의 수를 알아낼 수 있습니다.

➌ DELETE /room/:id는 채팅방을 삭제하는 라우터입니다. 채팅방과 채팅 내역을 삭제한 후 2초 뒤에 웹 소켓으로 /room
네임스페이스에 방이 삭제되었음(removeRoom)을 알립니다.

이제 접속해서 방을 생성해봅시다.

서버를 시작하기 전에 몽고디비를 먼저 실행해야 한다는 것을 잊지 마세요. 몽고디비와 서버를 실행한 후 브라우저 두 개를 띄워놓고 http://localhost:8005에 접속합니다. 브라우저 두 개를 사용하는 이유는 두 명이 접속한 것과 비슷한 상황을 연출하기 위해서입니다.

 

한 브라우저에서 방을 생성해 봅시다.

방이 생성되는 순간에 서버가 newRoom 이벤트를 호출하고, 다른 브라우저에서도 방 목록이 업데이트됩니다.

 

방 나가기를 누르면 참여자가 0명이므로 removeRoom 이벤트가 호출되어 2초 후 양쪽 브라우저에서 모두 방이 사라집니다.

 

'프로그래밍 언어 > NODE JS' 카테고리의 다른 글

프로젝트 마무리하기  (0) 2026.02.10
채팅 구현하기  (0) 2026.02.07
미들웨어와 소켓 연결하기  (0) 2026.02.01
실시간 GIF 채팅방 만들기(4)  (0) 2026.01.29
실시간 GIF 채팅방 만들기(3)  (0) 2026.01.26