[ToyProject] 실시간 채팅과 귓속말까지! (feat. socket.io)

code_sign·2021년 6월 7일
5

ToyProject

목록 보기
1/2

이번 프로젝트에서는 2가지의 기능을 핵심으로 설정을 했다.
1. 실시간 채팅(+ 귓속말)
2. 압축된 파일 풀어 리스트 만들기(+ 편집)

우선은 실시간 채팅에 대해서 자세히 블로깅을 시작하겠다!

🚀 socket.io 설정하기

nodeexpress를 기본으로 사용을 하였다.
app.js에서 등록을 하여 설정을 해주어야 하는데, 나는 이것을 따로 socket.js파일로 빼내어 정리를 한다음 app.js에서 다시 require해주었다.

socket.js 생성

module.exports를 통해 외부에서 require로 리턴 할 수 있게 해주었다.
socket의 연결은 connection으로 연결을 해주었고, 연결이 됐을때(connection)와 연결이 해제되었을때(disconnect) 구분해줄 ip를 선언하고 이용하였다.

새로운 접속 ::ffff:172.17.0.1 zRomb4oZ26jTwQd5AAAB
클라이언트 접속 해제 ::ffff:172.17.0.1 zRomb4oZ26jTwQd5AAAB

나머지 기능은 채팅의 BackEnd에서 자세히 설명

app.js에 등록/연결

회색 부분은 나머지 설정이라 볼 필요는 없다.

const main을 보면 redis로 선언된 server를 우리가 설정한 socket.js에서 불러와 연결을 해주었다.

이럼으로 서버에서는 socket을 통해 이용할 수 있게 되었다.

🚀 DB 스키마 설정

mongodbnoSQL이지만, 그래도 스키마 형태로 가공해주는 것이 편리하기 떄문에 스키마 설정을 해주었다. (mongoose 사용)

필요한 필드 정리

채팅에서 공통적으로 필요한 것들은 다음과 같다.
보낸 사람, 메세지 내용, 메세지 날짜(날짜는 db에서 필수적이다.)
그리고 귓속말 기능에서는 추가적으로 받는 사람이 필요하기에 이것을 구분해줄 타입(귓속말인지 아닌지)으로 나누어 구축을 해주었다.

chat.js 생성


필수적으로 필요한 것들은 requiretrue로 설정했다. 그리고 createAt은 지금 등록된 날짜를, type은 기본적으로 전체 채팅을 뜻하는 public으로 설정하였다.

user는 이미 만들어둔 것으로 ref를 통해 참조 할 수 있도록 했다.

🚀 전체 채팅 구현

FrontEnd - 메인 페이지

socket으로 현재 socket을 사용할 주소를 입력하여 선언한다.

componenteDidMount()에는 mount됐을때 실행되어야 할 것들을 선언해준다.

  • user_id 받아오기
  • 전에 있던 채팅들을 받아오기 (logs)
  • joinChat으로 socket의 유저리스트에 등록을 시킨다.
  • getUserList를 통해 새로운 유저가 들어왔을때 userList를 업데이트 해준다.
  • 새로운 전체 채팅 메세지를 받으면 logs를 업데이트 해준다.

보여지는 페이지는 총 3부분으로 나눌 수 있다.

1. 채팅이 보이는 채팅 보드

logs를 통해 지난 메세지들을 받아오면 map을 통해 MessageBox라는 Component를 돌려준다.

내가 보낸 것인지, 상대방이 보낸 것인지, 귓속말인지에 따라 CSS설정을 다르게 하여 잘 구분될 수 있게 하였다.

내가 보낸 메세지는 오른쪽 정렬로 아이디 없이 표시하였다.

다른 유저가 보낸 메세지들은 왼쪽 정렬을 했다.

청록색은 귓속말로 어떤 유저에게 보내는지 보여진다.
위에서는 codesign이 code에게 보내는 귓속말이다.

일반 채팅의 경우 하얀색 바탕으로 받게 된다.

2. 귓속말 상대를 선택할 수 있는 셀렉트

componentDidMount()가 실행이 되면서 userList를 받아오게 되는데 이것이 접속해 있는 유저들의 리스트이다. 이것을 통해 귓속말 할 상대를 정할 수 있게 된다.

마찬가지로 map을 통해 리스트를 만들었고, 해당 리스트의 유저를 클릭하면 해당 유저에게 메세지를 보낼 수 있게 된다. 동시에 statetype, toUser가 바뀌게 된다. 물론, 자기 자신을 선택할 수는 없다.

3. 메시지를 입력하여 내보내는 인풋창

기본적으로 bootstrap으로 디자인을 하였고, onChange를 통해 statemessage를 바로 변경 가능하게 하였다.

버튼을 누르면 해당 메세지가 귓속말인지 아닌지, 비어있는지 아닌지 등을 확인하여 백엔드와 통신하게 되고 잘 통신이 되었다면 socket을 통해 전체 메세지를 전달하게 되고, 해당 state들을 초기화해준다.

BackEnd

다시 보자 socket.js !!

새로운 유저가 접속을 하게 되면 socket.join을 통해 등록을 시키고,
userList에 추가하게 된다. 그리고 업데이트된 userList를 전체 socket으로 보내어 받게 된다.

채팅은 전체 채팅과 귓속말이 나누어져 있는데, 한 socket의 기능에서 처리하게 하였다. 전달받은 object의 toUser가 있다면 귓속말이므로 해당 소켓의 아이디를 가진 사람에게만 전달하기 위해 io.to(받을사람 id).emit()으로 처리하였다.

만약 접속을 해지하게 된다면 splice 내부 함수를 사용하여 해당 유저를 제외하게 했다.

API

[GET] /init API

처음 페이지에 들어와 실행하게 되는 /init에서는 모든 채팅을 찾게 된다.
해당 함수인 findAllChats는 접속한 유저의 아이디를 통해 DB를 다음과 같은 조건으로 조회하게 된다.

  • 전체 채팅 -> toUser가 없는 채팅들
    또는
  • toUser가 접속한 유저인 것 (귓속말 받은 상대가 해당 유저)
    또는
  • user가 접속한 유저인 것 (귓속말 보낸 사람이 해당 유저)

이렇게 되면 다른 사람에게 보낸/받은 메세지들을 제외하고 조회하게 된다.

[POST] /message API

메세지를 보내는 기능들 담당하는 이 API는 addChat 함수를 실행한다.
해당 함수는 전체 채팅인지 귓속말인지를 판단 후 넘겨 받은 Object를 DB에 저장시킨다.

profile
방탈출 좋아하는 코딩덕후

3개의 댓글

comment-user-thumbnail
2021년 11월 9일

안녕하세요! 백엔드 노드개발자를 목표로해서 공부중인 초보개발자입니다! 저도 채팅방을 구현하고 싶어서 자료들을 조사중인데 code_sign님의 채팅방 코드가 잘 짜여있는 것 같아 참고를 하고 싶은데 혹시 있다면, 깃헙 주소를 공유 가능하실 지 문의드립니다!!

1개의 답글