Backend ๐Ÿ“š/Node.js

[Node]Instagram Clone - 13. Socket.io๋ฅผ ํ™œ์šฉํ•œ ๋Œ“๊ธ€ ๋ฐ ๊ฒŒ์‹œ๋ฌผ ์ข‹์•„์š” ์•Œ๋ฆผ ๊ธฐ๋Šฅ ๊ตฌํ˜„

leejaejae 2024. 11. 10. 23:35
  • ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Socket.IO๋ฅผ ์‚ฌ์šฉํ•ด ๊ฒŒ์‹œ๋ฌผ๊ณผ ๋Œ“๊ธ€์— ์ข‹์•„์š”๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•จ.
  • ํด๋ผ์ด์–ธํŠธ๋Š” ์ฆ‰์‹œ ์ข‹์•„์š”๊ฐ€ ๋ฐ˜์˜๋œ ์ •๋ณด๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ.

1. ์„œ๋ฒ„ ์ฝ”๋“œ

1) ๊ธฐ์กด์˜ server.js ์ˆ˜์ •

  • ์„œ๋ฒ„์—์„œ Socket.IO๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์™€์˜ ์—ฐ๊ฒฐ์„ ๊ด€๋ฆฌ.
  • ์ข‹์•„์š”๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด like-post์™€ like-comment ์ด๋ฒคํŠธ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
// server.js
const socketIo = require("socket.io");

let io;

function initSocket(server) {
  io = socketIo(server);

  io.on("connection", (socket) => {
    console.log("A user connected");

    socket.on("disconnect", () => {
      console.log("User disconnected");
    });
  });
}

function emitComment(data) {
  if (!io) {
    console.error("Socket.io is not initialized.");
    return;
  }
  io.emit("new-comment", data); // ์ด๋ฒคํŠธ ๋ฐœ์ƒ
  console.log("Emitted new-comment event:", data); // ์ด๋ฒคํŠธ ๋ฐœ์ƒ ํ›„ ๋กœ๊ทธ ์ถ”๊ฐ€
}

function emitCommentLike(data) {
  if (!io) {
    console.error("Socket.io is not initialized.");
    return;
  } else {
    io.emit("like-comment", data);
    console.log("Emitting like-comment event:", data);
  }
}

function emitPostLike(data) {
  if (!io) {
    console.error("Socket.io is not initialized.");
    return;
  } else {
    io.emit("like-post", data);
    console.log("Emitting like-post event:", data);
  }
}

module.exports = { initSocket, emitComment, emitCommentLike, emitPostLike };


2) ๊ธฐ์กด์˜ likePost.js์™€ likeComment.js ์ˆ˜์ •(์ด๋ฒคํŠธ ๋ฐœ์ƒ)

  • ๊ฒŒ์‹œ๋ฌผ๊ณผ ๋Œ“๊ธ€์— ์ข‹์•„์š”๊ฐ€ ๋ˆŒ๋ฆฌ๋ฉด, ๊ฐ๊ฐ emitLikePost์™€ emitLikeComment ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์–ด Socket.IO๋ฅผ ํ†ตํ•ด ๊ด€๋ จ ์ •๋ณด๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก

likePost.js

// likePost.js
const { emitLikePost } = require("../../server");

router.post("/:postId/like", auth, async (req, res) => {
  const postId = req.params.postId;
  const userId = req.user._id;

  try {
    const post = await Post.findById(postId);
    if (!post) {
      return res.status(404).json({ message: "๊ฒŒ์‹œ๋ฌผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." });
    }

    // ์ด๋ฏธ ์ข‹์•„์š”๊ฐ€ ๋ˆŒ๋ ค์žˆ๋‹ค๋ฉด ์ข‹์•„์š” ์ทจ์†Œ
    const index = post.likes.indexOf(userId);
    if (index > -1) {
      post.likes.splice(index, 1); // ์ข‹์•„์š” ์ทจ์†Œ
    } else {
      post.likes.push(userId); // ์ข‹์•„์š” ์ถ”๊ฐ€
    }

    await post.save();

    emitLikePost({
      postId: postId,
      userId: userId,
      likeCount: post.likes.length,
    });

    return res.status(200).json({
      message: "์ข‹์•„์š”๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.",
      likeCount: post.likes.length,
    });
  } catch (error) {
    return res.status(500).json({
      message: "์ข‹์•„์š” ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.",
      error: error.message,
    });
  }
});

module.exports = router;

likeComment.js

// likeComment.js
const { emitLikeComment } = require("../../server");

router.post("/:commentId/like", auth, async (req, res) => {
  const commentId = req.params.commentId;
  const userId = req.user._id;

  try {
    const comment = await Comment.findById(commentId);
    if (!comment) {
      return res.status(404).json({ message: "๋Œ“๊ธ€์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." });
    }

    // ์ด๋ฏธ ์ข‹์•„์š”๊ฐ€ ๋ˆŒ๋ ค์žˆ๋‹ค๋ฉด ์ข‹์•„์š” ์ทจ์†Œ
    const index = comment.likes.indexOf(userId);
    if (index > -1) {
      comment.likes.splice(index, 1); // ์ข‹์•„์š” ์ทจ์†Œ
    } else {
      comment.likes.push(userId); // ์ข‹์•„์š” ์ถ”๊ฐ€
    }

    await comment.save();

    emitLikeComment({
      commentId: commentId,
      userId: userId,
      likeCount: comment.likes.length,
    });

    return res.status(200).json({
      message: "๋Œ“๊ธ€ ์ข‹์•„์š”๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.",
      likeCount: comment.likes.length,
    });
  } catch (error) {
    return res.status(500).json({
      message: "๋Œ“๊ธ€ ์ข‹์•„์š” ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.",
      error: error.message,
    });
  }
});

module.exports = router;

 

2. ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ (์ž„์‹œ)

// client.js
const io = require("socket.io-client");

// ์„œ๋ฒ„์™€์˜ ์†Œ์ผ“ ์—ฐ๊ฒฐ
const socket = io("http://localhost:3000"); // ์„œ๋ฒ„ URL์— ๋งž๊ฒŒ ์ˆ˜์ •

// ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐ ์„ฑ๊ณต ์‹œ
socket.on("connect", () => {
  console.log("์„œ๋ฒ„์— ์—ฐ๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
});

// ์„œ๋ฒ„์—์„œ "new-comment" ์ด๋ฒคํŠธ ์ˆ˜์‹ 
socket.on("new-comment", (data) => {
  console.log("์ƒˆ๋กœ์šด ๋Œ“๊ธ€์ด ๋‹ฌ๋ ธ์Šต๋‹ˆ๋‹ค!");
  console.log(data); // ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ

});

// ์„œ๋ฒ„์—์„œ "like-comment" ์ด๋ฒคํŠธ ์ˆ˜์‹ 
socket.on("like-comment", (data) => {
  console.log("๋Œ“๊ธ€์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค!");
  console.log(data); // ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ข‹์•„์š” ์•Œ๋ฆผ ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ
});

// ์„œ๋ฒ„์—์„œ "like-post" ์ด๋ฒคํŠธ ์ˆ˜์‹ 
socket.on("like-post", (data) => {
  console.log("๊ฒŒ์‹œ๋ฌผ์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค!");
  console.log(data); // ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ข‹์•„์š” ์•Œ๋ฆผ ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ
});

 

3. ๊ฒฐ๊ณผ ๐ŸŽ‰