220808 공통 프로젝트 개발일지

·2022년 8월 21일
0

개발일지 & 회고

목록 보기
11/72
post-thumbnail

채팅 기능 연결하기

openvidu 의 채팅 기능을 연결하였다. 비디오 렌더링에 비해 훨씬 쉬운 구조로, message를 보내고 받는다는 이벤트만 연결해주면 간단하게 구현이 가능했다.
openvidu 에는 message를 보내는 특정이벤트는 존재하지 않아, 직접 커스텀하여 구현하는 signal 함수를 통해 로직을 연결시켰다. signal 함수 자체를 이해한다면, 여러가지 이벤트를 구현할 수 있기에, 앞으로도 더 많은 프로젝트의 socket 이벤트로 자주 사용될 거라 예상된다.

import { useRef } from 'react'
import Sheet from '../common/Sheet'
import classes from './Chatting.module.css'
import ChattingLog from './ChattingLog'
import { useEffect } from 'react'
import { useState } from 'react'
import { useSelector } from 'react-redux'

const Chatting = () => {
  const input = useRef()
  const chattingLog = useRef()
  const [chat, setChat] = useState({
    messageList: [],
    message: '',
  })

  const openvidu = useSelector(state => state.openvidu)

  const { messageList, message } = chat
  // console.log(openVidu)

  useEffect(() => {
    if (openvidu.publisher) {
      openvidu.session.on('signal:chat', event => {
        const data = JSON.parse(event.data)
        messageList.push({
          connectionId: event.from.connectionId,
          nickname: data.nickname,
          message: data.message,
        })
        setChat(prev => ({ ...prev, messageList }))
        scrollToBottom()
      })
    }
  }, [messageList])

  function handleChange(event) {
    // console.log(chat.message)
    setChat(prev => ({
      ...prev,
      message: event.target.value,
    }))
  }

  function handlePresskey(event) {
    if (event.key === 'Enter') {
      sendMessage()
      event.target.value = ''
    }
  }

  function sendMessage() {
    if (chat.message) {
      const data = {
        message: chat.message,
        nickname: openvidu.myUserName,
      }
      openvidu.publisher.session.signal({
        data: JSON.stringify(data),
        type: 'chat',
      })
    }
    setChat(prev => ({
      ...prev,
      message: '',
    }))
  }

  function scrollToBottom() {
    setTimeout(() => {
      try {
        chattingLog.current.scrollTop = chattingLog.current.scrollHeight
      } catch (err) {}
    }, 20)
  }

  return (
    <div className={classes.chatting}>
      <div className={classes.flex_item_log}>
        <Sheet>
          <div ref={chattingLog} className={classes.chatting_logs}>
            {messageList.map(({ message, connectionId }, idx) => (
              <ChattingLog
                key={idx}
                textData={{
                  myStreamId: openvidu.session.connection.connectionId,
                  connectionId: connectionId,
                  message: message,
                }}
              ></ChattingLog>
            ))}
          </div>
        </Sheet>
      </div>
      <div className={classes.flex_item_input}>
        <Sheet size="small">
          <input
            className={classes.chatting_input}
            onChange={handleChange}
            onKeyUp={handlePresskey}
            ref={input}
          ></input>
        </Sheet>
      </div>
    </div>
  )
}

export default Chatting

다음 매칭, 나가기 버튼 구현하기

미팅 페이지에, 다음 매칭 버튼과 나가기 버튼을 구현하였다. 우선 둘다, 미팅 전 메인페이지로 이동하는 것 이지만, 다음매칭 버튼은 다시 매칭이 일어나, 다시 미팅 페이지로 이동하게 되고, 나가기 버튼을 누르면, 메이 페이지로 이동하기만 하고 끝이난다.

openvidu connection 에러

openvidu 의 connection 에러를 자세히 살펴보았다. 결과, 토큰을 생성하기 전 session 을 생성하는 부분에서 409 에러를 반환하고 있었다. openvidu 자체 듀토리얼에서도, 409 에러가 나기전 Promiseresolve() 함수를 호출하게 하였는데, 일단은 에러가 나더라도 성공하는 응답을 강제로 호출하게 만든다면, 나머지는 openvidu 서버쪽에서 어떻게 어떻게 만들어줄 거 같아, 행여 에러가 나타나는 경우, setTimeout 을 활용하셔 강제적으로 성공 응답을 반환하게 하니, 어떻게 어떻게 연결이 되었다!

시간은 1초정도로 하였다. 어짜피 성공적으로 응답하는 경우라면 상관이 없으니 setTimeout 은 무시될테고, 1초 이상 걸리는 경우라면, 이를 실패했다고 하고 강제적으로 resolve() 함수를 호출하여 흐름이 계속 이어지게끔 한 것이다.

찾아보니 409는 클라이언트의 요청과 서버의 상태가 서로 맞지않아 충돌이 일어나는 상태를 의미한다고 한다. 이러한 충돌의 개념이 명확하지 않아서, 보통 400,401,403,405 의 상태 코드에 속하기 애매한 코드를 409로 응답하는 경우가 있다고 하는데... 맞는지는 모르겠다.

function createSession(sessionId) {
  return new Promise(async (resolve, reject) => {
    let data = { customSessionId: sessionId }
    try {
      const response = await axios.post(
        OPENVIDU_SERVER_URL + '/openvidu/api/sessions',
        data,
        {
          headers: {
            Authorization:
              'Basic ' + btoa('OPENVIDUAPP:' + OPENVIDU_SERVER_SECRET),
            'Content-Type': 'application/json',
          },
          withCredentials: false,
        },
      )

      // 에러 처리
      setTimeout(() => {
        console.log('개발자 설정을 통한 강제 리턴')
        console.log(sessionId)
        return resolve(sessionId)
      }, 1000)
      console.log(response)
      return response.data.id
    } catch (response) {
      console.log(response)
      let error = Object.assign({}, response)
      if (error?.response?.status === 409) {
        return resolve(sessionId)
      }
    }
  })
}

profile
새로운 것에 관심이 많고, 프로젝트 설계 및 최적화를 좋아합니다.

0개의 댓글