본문 바로가기
Web Service/NodeJS

[ZOOM 클론 코딩] #3. Chat & Nicknames

by junnykim 2022. 8. 24.

~1.9까지의 강의

 

 

home.pug

ul
form
    input(type="text", placeholder="write a msg", required)
     button Send

form을 만들어 우리가 보게될 메시지 리스트를 만들 것이다.

실행시킨 모습

그리고 추가한 것을 찾게 하기 위해서 app.js에서 편집을 해준다.

 

app.js

const messageList = document.querySelector("ul");
const messageForm = document.querySelector("form");

home.pug와 연결시키는 부분들이다. 

 

 

그리고, 메시지를 send하는 부분을 지우고 아래와 같이 변경한다.

function handleSubmit(event) {
    event.preventDefault();
    const input = messageForm.querySelector("input");
    socket.send(input.value);
    input.value = "";
  }
  
  messageForm.addEventListener("submit", handleSubmit);

이렇게 되면 socket은 input의 값을 보내주는 것이고, 다시 초기화 하는 것이다.

 

초기화

input.value="";

 

여기까지 하면 다른 브라우저에서 메세지를 쓰면 받지 못한다.

각자 다른 브라우저에서 메세지를 주고 받게 하려면 어떻게 해야할까?

 

sever.js

const sockets = [];
  
wss.on("connection", (socket) => {
    sockets.push(socket);
    console.log("Connected to Browser ✅");
    socket.on("close", onSocketClose);
    socket.on("message", (message) => {
      sockets.forEach((aSocket) => aSocket.send(message.toString()));
    });
  });

누군가 서버에 연결하면, connection을 넣는다.

이렇게 하면 받은 메시지를 모든 socket에 전달해줄 수 있다.

즉, 메시지를 받으면 받은 메시지를 sockets에 있는 모든 곳에 전달해줄 수 있다.

그 후에 메시지를 socket에 다시 메시지를 보낸다.

socket.forEach((aSocket => aSocket.send(message.toString()))

각 브라우저를 aSocket으로 표시하는 것이다.

이렇게 하면 chat을 해줄 수 있다.

각자 다른 브라우저에서 보낸 메세지. 채팅 성공 !


이제 메시지를 스크린에 보여주는 function을 만들어 보자 !

 

app.js

  socket.addEventListener("message", (message) => {
    const li = document.createElement("li");
    li.innerText = message.data;
    messageList.append(li);
  });

새로운 메시지를 받으면, 새로운 li를 만든 후에 message.data를 li안에 넣어준다.

우선 단순하게 메시지를 확인할 수 있다.

 

닉네임도 주고 받아보자.

home.pug

main
    form#nick
        input(type="text", placeholder="choose a nickname", required)
        button Save
    ul
    form#message
        input(type="text", placeholder="write a msg", required)
        button Send

id를 만들어 주었다.

 

app.js

const nickForm = document.querySelector("#nick");
const messageForm = document.querySelector("#message");

  messageForm.addEventListener("submit", handleSubmit);
  nickForm.addEventListener("submit", handleNickSubmit)

home과 연동을 해주기 위해서 메세지폼도 변경한 것이다.

그리고 밑에 eventLister로 추가해준다.

 

function handleSubmit(event) {
    event.preventDefault();
    const input = messageForm.querySelector("input");
    socket.send(makeMessage("new_message",input.value));
    input.value = "";
  }

  function handleNickSubmit(event) {
    event.preventDefault();
    const input = nickForm.querySelector("input");
    socket.send(makeMessage("nickname", input.value));
  }

type을 지정해주어야 한다.

1가지는 메세지이다. 여기는 payload가 있다.

다른 타입은 닉네임이다. 사용하고 싶은 닉네임이 들어가는 것이다.

그러면 2가지 타입을 구별해줄 수 있다.

 

makeMessage

function makeMessage(type, payload) {
  const msg = { type, payload };
  return JSON.stringify(msg);
}

이 함수를 통해 type, payload를 정할 수 있다.

오브젝트를 string으로 만든 후, 다시 오브젝트로 만드는 방법은 무엇일까?

그것은 json.stringify를 하면 볼 수 있다.

메시지를 전송할 때 마다 string을 전송해줄 것이다.

string을 보내기전에 오브젝트를 string으로 만들어준다.

여기까지면 성공 ! 

 


우리는 지금까지 백엔드로 string을 보내주었다.

그런데 string의 모양은 계속해서 변화하고 있다.

즉, 다른 form에서 전송하고 있다.

 

server.js

wss.on("connection", (socket) => {
    sockets.push(socket);
    socket["nickname"] = "Anon";
    console.log("Connected to Browser ✅");
    socket.on("close", onSocketClose);
    socket.on("message", (msg) => {
      const message = JSON.parse(msg);
      switch (message.type) {
        case "new_message":
          sockets.forEach((aSocket) =>
            aSocket.send(`${socket.nickname}: ${message.payload}`)
          );
        case "nickname":
          socket["nickname"] = message.payload;
      }
    });
  });

우리는 string을 보내주고 있다.({type:~~})

string을 js로 변환하기 위해서 JSON.parse를 사용한다.

parse는 string을 js로 바꿔준다.

 

그후 닉네임을 하려면 save를 저장해주어야 한다.

switch를 사용해서 닉네임 타입을 받은 후에 payload, 즉 닉네임을 socket안에 넣어주어야 한다.

익명 socket에 대해서도 생각해야 하는데, 그래서 socket에 연결될 때 기본 값을 정해주는 것이다.

 

메시지가 socket에 전송되고, type이 new_message이면, 메시지를 보내는 것이다.

 

즉, 닉네임 property를 socket오브젝트에 저장하고 있는 것이다.

완성 !

 

 

전체코드

home.pug

더보기
doctype html
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Noom
        link(rel="stylesheet", href="https://unpkg.com/mvp.css")
    body
        header
            h1 Noom
        main
            form#nick
                input(type="text", placeholder="choose a nickname", required)
                button Save
            ul
            form#message
                input(type="text", placeholder="write a msg", required)
                button Send
        script(src="/public/js/app.js")

app.js

더보기
const messageList = document.querySelector("ul");
const nickForm = document.querySelector("#nick");
const messageForm = document.querySelector("#message");
const socket = new WebSocket(`ws://${window.location.host}`);

function makeMessage(type, payload) {
  const msg = { type, payload };
  return JSON.stringify(msg);
}

function handleOpen() {
    console.log("Connected to Server ✅");
    }
  
    socket.addEventListener("open", handleOpen);

  socket.addEventListener("message", (message) => {
    const li = document.createElement("li");
    li.innerText = message.data;
    messageList.append(li);
  });
  
  socket.addEventListener("close", () => {
    console.log("Disconnected from Server ❌");
  });
  
  function handleSubmit(event) {
    event.preventDefault();
    const input = messageForm.querySelector("input");
    socket.send(makeMessage("new_message",input.value));
    input.value = "";
  }

  function handleNickSubmit(event) {
    event.preventDefault();
    const input = nickForm.querySelector("input");
    socket.send(makeMessage("nickname", input.value));
    input.value = "";
  }
  
  messageForm.addEventListener("submit", handleSubmit);
  nickForm.addEventListener("submit", handleNickSubmit);

server.js

더보기
import http from "http";
import WebSocket from "ws";
import express from "express";

const app = express();

app.set("view engine", "pug");
app.set("views", __dirname + "/views");
app.use("/public", express.static(__dirname + "/public"));
app.get("/", (_, res) => res.render("home"));
app.get("/*", (_, res) => res.redirect("/"));

const handleListen = () => console.log(`Listening on http://localhost:3000`);
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

function onSocketClose() {
    console.log("Disconnected from the Browser ❌");
  }
  
  const sockets = [];
  
wss.on("connection", (socket) => {
    sockets.push(socket);
    socket["nickname"] = "Anon";
    console.log("Connected to Browser ✅");
    socket.on("close", onSocketClose);
    socket.on("message", (msg) => {
      const message = JSON.parse(msg);
      switch (message.type) {
        case "new_message":
          sockets.forEach((aSocket) =>
            aSocket.send(`${socket.nickname}: ${message.payload}`)
          );
        case "nickname":
          socket["nickname"] = message.payload;
      }
    });
  });

server.listen(3000, handleListen);

'Web Service > NodeJS' 카테고리의 다른 글

[ZOOM 클론 코딩] #4. SocketIO  (1) 2022.08.31
[ZOOM 클론 코딩] #2. WebSockets  (0) 2022.08.04
[ZOOM 클론 코딩] #1. Set up  (0) 2022.07.30

댓글