장고 채팅 서비스 박치기 04 - 채팅 구현

김민규·6일 전
0

수정 내용

https://devspoon.tistory.com/278

daphne 적용 시 settings의 INSTALLED_APPS 상위에 위치해야 한다.

INSTALLED_APPS = [
    'daphne', # 다프네가 제일 앞으로 와야한다. 서순 신경 쓸 것.
    'channels', 
    
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]

https://stackoverflow.com/questions/77928535/django-can-login-but-cant-logout-405-method-not-allowed

logout 시, csrf 토큰을 이용한 post 요청만 받기 때문에 form과 버튼이 결합된 형식으로 변경해주어야 한다.

chatPage.html을 수정해주었다.

서비스를 위한 채널의 계층을 다음과 같이 명시해준다. 데이터 공유를 위한 계층이라고 하는데, 보안 취약 문제로 인해 배포시에는 Redis를 이용하는 걸 권장한다.
config/settings.py

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer"
    }
}

LOGIN_REDIRECT_URL = "chat-page"

LOGOUT_REDIRECT_URL = "login-user"
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [("127.0.0.1", 6379)],
        },
    },
}

redis 이용 시 channels_redis 패키지를 설치해야 한다.

config/asgi.py

import os
from django.core.asgi import get_asgi_application

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from ws_chat import routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket" : AuthMiddlewareStack(
        URLRouter(
            routing.websocket_urlpatterns
        )
    )
})

# ASGI_APPLICATION = 'config.asgi.application'

asgi에 websocket 프로토콜을 추가해주었다. AuthMiddlewareStack는 보안 및 인스턴스 인증, URLRouter는 ws에 대한 라우팅을 담당한다는데... 추가적으로 더 찾아봐야 할 것 같다.
ASGI_APPLICATION 이것도 무슨 역할을 하는지 모르겠다.

채팅 기능을 담당하는 클래스를 만들어주었다. AsyncConsumer와 AsyncWebsocketConsumer을 혼동해서 뭐가 문제인지 찾느라 혼났다...
ws_chat/consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.roomGroupName = "group_chat_gfg"
        await self.channel_layer.group_add(
            self.roomGroupName,
            self.channel_name
        )
        await self.accept()
    
    async def disconnect(self, close_code):
        await self.channel.name.group_discard(
            self.roomGroupName,
            self.channel_name
        )
        
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json["message"]
        username = text_data_json["username"]
        await self.channel_layer.group_send(
            self.roomGroupName,
            {
                "type" : "sendMessage",
                "message" : message,
                "username" : username,
            } )
    
    async def sendMessage(self, event):
        message = event["message"]
        username = event["username"]
        await self.send(text_data = json.dumps({"message" : message, "username" : username}))

다음과 같은 기능을 한다고 한다...

  • connect()
    채팅방의 이름을 채널 레이어에 추가한다.
  • disconnect()
    그룹에서 인스턴스를 제거한다.
  • receive()
    send()에 의해 트리거된다. JSON 포맷 데이터를 받아와 채팅방의 전원에게 수신한다.
  • sendMessage()
    receive()의 group_send()로 보내진 데이터를 가져온다.
    json으로 덤프시킨다. (???)

connection의 open이랑 created라는 상태가 나오던데 django docs를 찾아봐야 할 듯...

ws_chat/routing.py

from django.urls import path, include
from ws_chat.consumers import ChatConsumer

websocket_urlpatterns = [
    path("" , ChatConsumer.as_asgi()) , 
] 

채팅 기능을 연결해줄 스크립트이다.
as_asgi()를 통해 비동기 통신이 구현되는 것 같다.

profile
공부 기록용

0개의 댓글

관련 채용 정보