4. Code Arena, Code Chat 공통 - asdfgl98/Project-CodeBuddy GitHub Wiki

📌 CodeArena / Chat

✅ 하나의 서버(server.js)에서 두 가지의 서버(NameSpace)로 분리

  • CodeChat, CodeArena 두 가지의 서비스가 따로 운영되기 때문에 서버를 분리할 필요가 있었습니다.
  • Socket.io의 NameSpace를 사용해 Code Arena와 Code Chat 두 개의 서버를 분리하여 각각 사용할 수 있게 구현하였습니다.

💻 CodeDetail

Name Space 분리 코드


server.js (line 18)

// 네임스페이스로 io 서버 분리 /CodeChat, /CodeArena
const ChatNamespace = io.of("/CodeChat");
const ArenaNamespace = io.of("/CodeArena");


server.js (line 56)

// 네임스페이스 사용했기 때문에 파일 경로 지정
app.use(
  "/CodeChat/public/CodeChat",
  express.static(path.join(__dirname, "public/CodeChat"), {
    setHeaders: (res, filePath) => {
      const mimeType = mime.getType(filePath);
      res.setHeader("Content-Type", mimeType);
    },
  })
);

// 네임스페이스 사용했기 때문에 파일 경로 지정
app.use(
  "/CodeArena/public/CodeArena",
  express.static(path.join(__dirname, "public/CodeArena"), {
    setHeaders: (res, filePath) => {
      const mimeType = mime.getType(filePath);
      res.setHeader("Content-Type", mimeType);
    },
  })
);
Code Chat NameSpace 접속 구분 코드


** server.js (line 84)

// "Chat" namespace에 접속한 클라이언트 처리-----------------------------------------------------
ChatNamespace.on("connection", (socket) => {
  console.log("Code 네임스페이스에 클라이언트가 연결되었습니다.");

// 이하 생략
Code Arena NameSpace 접속 구분 코드


**server.js (line 347)

// -------------------------------------------------------- CodeArena 시작 ----------------------------------------------------------------------------------
// "Arena" namespace에 접속한 클라이언트 처리
ArenaNamespace.on("connection", (socket) => {
  console.log("Arena 네임스페이스에 클라이언트가 연결되었습니다.");

// 이하생략

🖼️ Preview

NameSpace.gif

NameSpace

✅ 채팅방 List 실시간 최신화 / 방 생성 / 방 삭제

  • 사용자가 CodeArena/Chat 페이지에 접속하면 socket.io 문법인 emit과 on을 통해 접속 이벤트를 감지하고,
    axios를 이용해 DB에 있는 채팅방 목록을 요청하여 반환받은 데이터로 리스트를 생성합니다.
  • 사용자가 방 생성, 입장, 퇴장 시 추가 및 수정된 정보를 axios로 전달하여 DB에 저장 및 수정하고 NameSpace에 접속해있는 모든 유저에게
    새롭게 갱신된 방 목록을 전송하여 실시간으로 리스트를 수정합니다.

💻 CodeDetail

방 정보를 매개변수로 입력 받아서 리스트를 최신화 하는 함수


codeArenaList.js (line 113)

//최신화 함수

const updateArenaRoom = (roomList) => {
  const $board_list = document.getElementById("board-list");
  const $board_table = $board_list.querySelector(".board-table");
  const $tbody = $board_table.querySelector("tbody");
  const $tr = document.querySelectorAll("tr");

  if (clickEventHandler) {
    $tbody.removeEventListener("click", clickEventHandler);
  }

  roomList.forEach((roomInfo) => {
    const newRow = document.createElement("tr");
    newRow.id = "room_" + roomInfo.ROOM_NUMBER;
    // 방 정보를 td에 추가
    newRow.innerHTML = `
            <td id="room-Num">${roomInfo.ROOM_NUMBER}</td>
            <td class="item ${roomInfo.ROOM_LANG}">${roomInfo.ROOM_LANG}</td>
            <th>
              <a class="room-link room-${roomInfo.ROOM_NUMBER}" data-roomnumber="${roomInfo.ROOM_NUMBER}" data-roomname="${roomInfo.ROOM_NAME}" data-roomhost="${roomInfo.ROOM_HOST}">${roomInfo.ROOM_NAME} ( ${roomInfo.USER_COUNT} / 4 )</a>
              <p>테스트</p>
             </th>
            <td>${roomInfo.ROOM_HOST}</td>
      `;
    // 새로운 행을 테이블의 맨 위에 추가
    $tbody.prepend(newRow);

    // axios.get("/room/createRoom", { room: "hi" }).then((res) => {
    //   currentNickname = res.data;
    // });

    clickEventHandler = handleClick;
    $tbody.addEventListener("click", clickEventHandler);

    $c_content_num.textContent = `${roomInfo.USER_COUNT}/4`; // 채팅방 펼쳤을 때 인원 수
    $mini_room_users.textContent = `${roomInfo.USER_COUNT}/4`; // 채팅방 접었을 때 인원 수
  });
};

사용자 접속시 채팅방 리스트 최신화 이벤트 감지


codeArenaList.js (line 154)

// 사용자 접속시 채팅방 리스트 최신화
arenaSocket.on("updateRoomList", () => {
  const $board_list = document.getElementById("board-list");
  const $board_table = $board_list.querySelector(".board-table");
  const $tbody = $board_table.querySelector("tbody");
  const $trs = $tbody.querySelectorAll("tr");
  axios.get("/codeArena/arenaList", { re: "hi" }).then((res) => {
    let roomList = JSON.parse(res.data);
    $trs.forEach(($tr) => {
      $tr.remove();
    });
    updateArenaRoom(roomList);
  });
});
방 생성시 채팅방 리스트 최신화


codeArenaList.js (line 169)

// 방 생성시 채팅방 리스트 최신화(기존의 테이블 tr 모두 삭제 후 최신화)
arenaSocket.on("updateRoomList2", () => {
  const $board_list = document.getElementById("board-list");
  const $board_table = $board_list.querySelector(".board-table");
  const $tbody = $board_table.querySelector("tbody");
  const $trs = $tbody.querySelectorAll("tr");
  axios.get("/codeArena/arenaList", { re: "hi" }).then((res) => {
    let roomList = JSON.parse(res.data);
    $trs.forEach(($tr) => {
      $tr.remove();
    });
    updateArenaRoom(roomList);
  });
});


codeArenaList.js (line 196)

//방장이 방 생성시 database에 방 정보 입력 및 방 입장 처리
arenaSocket.on("host_enterRoom", (data) => {
  let nickName = data[0].createdBy;
  let roomName = data[0].room_name;
  let roomNum = data[0].room_number;
  const addRoomToTable = (updateRooms) => {
    axios.post("/codeArena/updateroom", { updateRooms }).then((res) => {
      let roomInfo = JSON.parse(res.data);
    });
  };
  addRoomToTable(data);
  enterRoom(roomName, roomNum, nickName);
});

🖼️ PreView

CodeArena.gif

CodeArenaList

CodeChat.gif

CodeChatList

✅ 실시간 채팅 기능

  • 사용자가 방에 입장할 때 사용자에 대해 socket 내부에서 접속자 이름, 방 번호(고유 값)를 별도로 저장합니다.
  • 사용자가 메세지 전송을 하면 server에서 사용자 이름과 메세지 내용을 수신하고, 사용자가 속해있는 방 번호로 구분하여
    해당 방에 있는 인원 중 메세지를 전송한 사용자에게 my_message 이벤트를, 메세지를 전송한 사용자를 제외한 모두에게 other_message 이벤트를 전송합니다.
  • 각각의 이벤트를 받은 사용자의 클라이언트 화면에 메세지가 출력됩니다.
  • my_message : 우측 파란색 메세지 박스 (내 메세지)
  • other_message : 좌측 주황색 메세지 박스 (상대 메세지)

💻 CodeDetail

메세지 전송 함수


codeArenaList.js (line 518)

// 메세지 전송 함수
const handleMessageSubmit = (event) => {
  event.preventDefault();
  const message = $form_input.value; // 메시지 입력값 가져오기

  // 메세지의 공백이나 줄바꿈을 빈 문자열로 바꿔서 빈문자열만 있으면 보내지않기
  let checkMessage = message.replace(/\s| /gi, '');

  // 메세지 공백 아닐 때 메세지 보내기
  if(checkMessage !== ""){
    arenaSocket.emit("new_message", { currentNickname, message: message });
  }

  $form_input.value = ""; // 입력 창 초기화
  scrollToBottom()
};
서버에서 채팅 메세지 수신


server.js (line 414)

// 아레나 채팅 메세지 수신
  socket.on("new_message", ({ currentNickname, message: message }) => {
    let roomNum = socket.room_number;
    socket.emit("my_message", { currentNickname, message: message });

    socket.broadcast
      .to(roomNum)
      .emit("other_message", { currentNickname, message: message });

  });
server로부터 메세지 수신 시 메세지div 생성


codeArenaList.js (line 544)

// 내 메세지 div 생성
arenaSocket.on("my_message", ({ currentNickname, message }) => {
  const $div = document.createElement("div");
  const $Div = document.createElement('div')
  $Div.id ='my_M'
  $div.id = "my_message"
  $div.textContent = `${message}`;
  $Div.appendChild($div);
  $c_main_content.appendChild($Div);
  scrollToBottom()
});

// 상대방 메세지 div 생성
arenaSocket.on("other_message", ({ currentNickname, message }) => {
  const $div = document.createElement("div");
  $div.id = "other_message"
  $div.textContent = `${currentNickname} : ${message}`;
  $c_main_content.appendChild($div);
  scrollToBottom()
});

🖼️ Preview

chatting.gif

chatting

⚠️ **GitHub.com Fallback** ⚠️