본문 바로가기
Python

[django] channels tutorial #2

by reo.l 2021. 4. 16.

 

 세월호 고인의 명복을 빕니다.

 

이번에는 channel layer와 consumer를 작성해서 채팅이 가능하게 만들어 보겠다.

먼저 consumer를 작성해 주는데 consumer는 websocket에 연결 및 전반적인 부분을 담당한다.

 

# chat/consumers.py

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json

class ChatConsumer(WebsocketConsumer):
    def connect(self):
      	# chat/routing.py 에 있는
        # url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer),
        # 에서 room_name 을 가져옵니다.
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name

        # 그룹에 join
        # send 등 과 같은 동기적인 함수를 비동기적으로 사용하기 위해서는 async_to_sync 로 감싸줘야한다.
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )
        # WebSocket 연결
        self.accept()

    def disconnect(self, close_code):
        # 그룹에서 Leave
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )

    # WebSocket 으로부터 메세지 receive
    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # room group 에게 메세지 send
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # room group 에서 메세지 receive
    def chat_message(self, event):
        message = event['message']

        # WebSocket 에게 메세지 전송
        self.send(text_data=json.dumps({
            'message': message
        }))

 

이제 이 소비자를 라우팅 해주어야 하는데 django의 url과 다른 곳에서 처리해준다. 방식은 비슷하다.

 

# chat/routing.py

from django.conf.urls import url
from . import consumers

websocket_urlpatterns = [
    url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer.as_asgi()),
]


# mysite/routing.py

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

# 클라이언트와 Channels 개발 서버가 연결 될 때, 어느 protocol 타입의 연결인지
application = ProtocolTypeRouter({
    # (http->django views is added by default)
  	# 만약에 websocket protocol 이라면, AuthMiddlewareStack
    'websocket': AuthMiddlewareStack(
        # URLRouter 로 연결, 소비자의 라우트 연결 HTTP path를 조사
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),
})

 

이렇게 하면 컨슈머를 통해 내가 보낸 채팅이 나의 room.html에 뿌려 진다. 하지만 공유는 되지 않는다. 공유를 위해서는 channel layer를 추가해 주어야 한다. 각 컨슈머들은 하나의 채널을 가지고 channel layer를 통해 채팅을 하는 구조이다.

 

channel layer를 추가해 주고

# settings.py

ASGI_APPLICATION = 'mysite.routing.application'
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

 

이렇게 channel layer를 연결해 주면 채팅이 가능하게 된다. 다음에는 nginx에 channels를 연결하는 부분을 포스팅하겠다.

 

 

댓글