👨🏻‍💻

5. 메시지 ‘읽음’ 처리하기

브랜치
채팅
생성 일시
2023/10/04 09:49
작성일
2023/10/04
작성자
최종 편집 일시
2023/10/04 12:54

아이디어

사용자의 메시지 ‘읽음’ 이벤트를 웹소켓을 통해 서버에 전달합니다.
서버는 메시지 ‘읽음’ 이벤트를 전달받으면, 해당 메시지의 is_read 상태를 True로 변경하고,
웹소켓 그룹 내 모든 클라이언트에게 메시지 ‘읽음’ 이벤트 발생을 전달합니다.

사용자의 메시지 읽음 기준은?

1.
채팅방을 불러올 때
2.
채팅방을 클릭했을 때
3.
채팅방이 있는 탭을 활성화했을 때

1. 채팅방을 처음 불러올 때

채팅방은 웹소켓 연결과 동시에 불러옵니다.
따라서 웹소켓이 연결되었을 때 불러와지는 .onopen에 ‘읽음’ 이벤트를 전달하도록 했습니다.
// WebSocket 연결 이벤트 리스너 chatSocket.onopen = function () { console.log("WebSocket 연결이 열렸습니다."); // 웹소켓이 연결되면 메시지 '읽음' 이벤트를 서버로 보냅니다 let chatRoomId = JSON.parse(document.getElementById('selected-chatroom-id').textContent); let readerId = JSON.parse({{ user.id }}) chatSocket.send(JSON.stringify({ 'type': 'page_loaded', 'message': 'The page is now loaded', 'chatroom_id': chatRoomId, 'reader_id': readerId })); };
JavaScript
복사
실행 화면

2. 채팅방을 클릭했을 때

// 페이지가 클릭되었을 때 웹소켓으로 메시지 '읽음' 여부 보내기 document.addEventListener("click", function(event) { // 특정 요소를 클릭했을 때는 이벤트 처리를 중단합니다. let clickedElement = event.target; if (clickedElement.classList.contains('ignore-page-clicked')) { return } console.log('Page is clicked'); let chatRoomId = JSON.parse(document.getElementById('selected-chatroom-id').textContent); let readerId = JSON.parse({{ user.id }}) chatSocket.send(JSON.stringify({ 'type': 'page_clicked', 'message': 'The page is clicked', 'chatroom_id': chatRoomId, 'reader_id': readerId })); }) })
JavaScript
복사
실행 화면

3. 채팅방 탭을 활성화 했을 때

// 페이지 활성화되었을 때 웹소켓으로 메시지 '읽음' 여부 보내기 document.addEventListener('visibilitychange', function () { if (document.visibilityState === 'visible') { console.log('Page is now visible'); let chatRoomId = JSON.parse(document.getElementById('selected-chatroom-id').textContent); let readerId = JSON.parse({{ user.id }}) chatSocket.send(JSON.stringify({ 'type': 'page_visible', 'message': 'The page is now visible', 'chatroom_id': chatRoomId, 'reader_id': readerId })); } })
JavaScript
복사
실행 화면

서버에서는 메시지 읽음 이벤트를 수신하여 2가지를 처리합니다.

1.
데이터베이스에서 메시지 읽음 상태(is-read) → True로 업데이트
2.
클라이언트에 메시지 읽음 이벤트 전달
# ... async def receive(self, text_data): text_data_json = json.loads(text_data) # '메시지 읽음' 이벤트인 경우 if text_data_json['type'] in ["page_clicked", "page_visible", "page_loaded"]: chatroom_id = text_data_json['chatroom_id'] user_id = self.scope['user'].id reader_id = text_data_json['reader_id'] # 1. (데이터베이스) 메시지 -> '읽음'으로 업데이트 await self.update_messages(chatroom_id, user_id) # 2. room group에 이벤트 전달 await self.channel_layer.group_send( self.room_group_name, { 'type': 'read_message', 'reader_id': reader_id } ) # 수신자가 현재 로그인한 사용자인 메시지를 모두 '읽음'으로 처리합니다. @database_sync_to_async def update_messages(self, chatroom_id, user_id): messages = Message.objects.filter(chatroom=chatroom_id, receiver=user_id) messages.update(is_read=True)
Python
복사

클라이언트에서 ‘메시지 읽음’ 이벤트를 수신하면 아래 규칙에 따라 처리합니다.

1.
상대가 보낸 메시지를 가 읽을 경우
let messageElements = document.getElementsByClassName('from-you'); if (data.reader_id === {{ user.id }}) { Array.from(messageElements).forEach(messageElement => { let isReadElement = messageElement.querySelector('.is-read'); if (isReadElement != null) { isReadElement.remove(); } }) }
JavaScript
복사
상대에게 온 메시지 중 isReadElement(● 표시)가 있을 경우 삭제합니다.
2.
가 보낸 메시지를 상대가 읽을 경우
messageElements = document.getElementsByClassName('from-me'); if (data.reader_id === {{ chat_partner.id }}) { Array.from(messageElements).forEach(messageElement => { let isReadElement = messageElement.querySelector('.is-read'); if (isReadElement != null) { isReadElement.remove(); } }) }
JavaScript
복사
내가 보낸 메시지 중 isReadElement(● 표시)가 있을 경우 삭제합니다.