본문 바로가기
개발/개인, 사이드 프로젝트

Express, React, Mongoose 로 웹소켓 채팅앱 만들기. 2

by 코딩하는짱구 2023. 10. 19.
반응형

 

Express, React, Mongoose 로 웹소켓 채팅앱 만들기. 2

1탄에서 socket 으로 프론트/백 연결까지 했으니, 이제는 user login 기능을 구현해야한다.

1. Today I learned

2. 오늘 겪은 문제

위의 목차를 클릭하면 해당 글로 자동 이동 합니다.

 

1. Today I learned 

user모델은 아래와 같다. username, token, online 

백엔드 Models/user.js

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, 'User must type name'],
    unique: true,
  },
  token: {
    type: String,
  },
  online: {
    type: Boolean,
    default: false,
  },
});

module.exports = mongoose.model('User', userSchema);

프론트에서 prompt로 username을 받으면 username과 함께 token(연결상태), online(접속중인지) 저장할 것이다.
아래와같이 io와 관련된 모든 일은 io.js파일에서 관리하고, socket 객체를 통해 프론트-서버와 통신한다. 

 

프론트 app.js

import { useEffect, useState } from 'react';
import './App.css';
import socket from './server';

function App() {
  const [user, setUser] = useState(null);
  useEffect(() => {
    askUserName();
  }, []);
  const askUserName = () => {
    const userName = prompt('당신의 이름을 입력하세요');
    // console.log('uuu', userName);

    socket.emit('login', userName, (res) => {
      if (res?.ok) {
        setUser(res.data);
      }
      console.log('Res', res);
    });
  };
  return (
    <div>
      <div className='App'></div>
    </div>
  );
}

export default App;
  • 프론트에서 askUserName 함수를 실행하면 prompt를 사용하여 사용자에게 이름을 입력하라는 메시지를 표시, 입력값을 userName 변수에 저장한다.
  • socket.emit 을 사용하여 login 이벤트를 서버로 전송하면 userName이 이벤트 데이터로 전달된다.
  • 서버에서 응답이 성공적으로 돌아오면(res?.ok) setUser 콜백함수가 호출되고 setUser를 사용하여 응답 데이터를 콘솔에 출력한다. 
  • console.log('Res', res) 를 통해 개발자도구-입력값을 확인함

 

백엔드 io.js 

const userController = require('../Controllers/user.controller');
module.exports = function (io) {
  //io 관련된 모든 일
  io.on('connection', async (Socket) => {
    console.log('client connection', Socket.id);

    Socket.on('login', async (userName, cb) => {
      //유저 정보를 저장
      // console.log('backend', userName);
      try {
        const user = await userController.saveUser(userName, Socket.id);
        cb({ ok: true, data: user });
      } catch (error) {
        cb({ ok: false, data: error.message });
      }
    });

    Socket.on('disconnect', () => {
      console.log('user disconnected');
    });
  });
};

소켓을 통해 username과 socket.id가 성공적으로 전달되면 이 정보를 가지고 userController.saveUser 함수를 호출한다.
==> 이 함수가 사용자 정보를 저장하고, 성공하면 cb 콜백함수로 {ok, data} 객체를 출력한다. 

소켓을 통해 전달된 socket.id가 user 모델의 token안에 들어가는 것. 

const userController = {};
const User = require('../Models/user');

userController.saveUser = async (userName, sid) => {
  //이미 있는 유저인지 확인
  //없다면 새로 유저 정보를 만들기, 있는 유저라면 연결 정보만 token값만 바꿔준다
  let user = await User.findOne({ name: userName });
  if (!user) {
    user = new User({
      name: userName,
      token: sid, //token값은 나의 현재 연결상태
      online: true,
    });
  }
  user.token = sid;
  user.online = true;

  await user.save();
  return user;
};
module.exports = userController;

 

세팅을 마치고 localhost:3000 접속하여 이름을 입력하면 성공적으로 res의 {ok, data}객체 반환!

console.log('Res', res) 를 통해 개발자도구-입력값을 확인함

 

 

2. 오늘 겪은 문제

socket 객체의 역할과 socket, userController의 관계를 이해하는데 조금 걸렸다. 

이제 chat 기능을 구현하여 user, chat 로그 모두 db에 성공적으로 저장되도록 구현할 예정

 

 

 

 

반응형