인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

sunnnwo님의 프로필 이미지

작성한 질문수

파이썬/장고로 웹채팅 서비스 만들기 (Feat. Channels) - 기본편

채팅방 단위로 그룹 채팅

하나의 채팅방만 만들어보려고 하는데 잘 안되고 있습니다.

작성

·

43

0

안녕하세요 선생님. 인증받지 않은 유저의 웹소켓 접근을 거부하려고 하는데요,

Traceback (most recent call last):
  File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/django/contrib/staticfiles/handlers.py", line 101, in __call__
    return await self.application(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
    return await application(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/sessions.py", line 47, in __call__
    return await self.inner(dict(scope, cookies=cookies), receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/sessions.py", line 263, in __call__
    return await self.inner(wrapper.scope, receive, wrapper.send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/auth.py", line 185, in __call__
    return await super().__call__(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/sunnnwo/workspace/pongchatT/venv/lib/python3.11/site-packages/channels/middleware.py", line 24, in __call__
    return await self.inner(scope, receive, send)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'list' object is not callable
WebSocket DISCONNECT /ws/chat/test/chat/ [127.0.0.1:61013]
HTTP GET /chat/ 200 [0.01, 127.0.0.1:61007]
/Users/sunnnwo/workspace/pongchat/mysite/asgi.py changed, reloading.
Watching for file changes with StatReloader

아래와 같이 설정하고 실행해봤는데,  위와 같은 에러가 발생했습니다. AuthMiddlewareStack을 이용하여 인증된 사용자만 채팅할 수 있게 하려면 어느 부분을 수정해야할까요.

감사합니다. 좋은 하루되세요.

asgi.py


application = ProtocolTypeRouter({
	"http" : django_asgi_app,
 	"websocket" : AuthMiddlewareStack(
		app.routing.websocket_urlpatterns +
		chat.routing.websocket_urlpatterns,
 ),
})

consumers.py

from asgiref.sync import async_to_sync
from channels.generic.websocket import JsonWebsocketConsumer

# 모든 유저가 고정된 채널 레이어 그룹을 가질것.
class ChatConsumer(JsonWebsocketConsumer):
    SQUARE_GROUP_NAME = "square"
    groups = [SQUARE_GROUP_NAME]

    def receive_json(self, content, **kwargs):
        # user = self.scope["user"]

        user = self.scope["user"]
        _type = content["type"]

        if not user.is_authenticated:
            self.close()

        else:
            if _type == "chat.message":

                message = content["message"]
                async_to_sync(self.channel_layer.group_send)(
                    self.SQUARE_GROUP_NAME,
                    {
                       "type": "chat.message",
                        "message": message,
                        
                    }
                )
            else:
                print(f"Invalid message type : ${_type}")

    def chat_message(self, message_dict):
        self.send_json({
            "type": "chat.message",
            "message": message_dict["message"],
          
        })

chat/routing.py

from django.urls import path, re_path
from chat import consumers

websocket_urlpatterns = [
    path("ws/chat/<str:room_name>/chat/", consumers.ChatConsumer.as_asgi()),
]

chat/urls.py

urlpatterns=[
    path("", views.index, name = "index"),
    path("<str:room_name>/chat/", views.room_chat, name = "room_chat" ),
    ]

답변 1

1

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

TypeError: 'list' object is not callable 예외가 발생한 상황입니다. 에러 메시지를 잘 보시면 list 객체는 호출할 수 없다는 내용인데요. 리스트 객체를 호출한 상황이라는 거죠. 함수처럼 호출되어야하는 부분에 리스트 값이 들어간 상황으로 예상할 수 있습니다.

asgi.py 코드를 보시면, AuthMiddlewareStack 미들웨어 스택에 urlpatterns 리스트를 그대로 넘기고 있습니다. AuthMiddlewareStack 는 asgi app (함수처럼 호출할 수 있습니다.)을 인자로 받고, asgi app을 반환합니다. 그런데 리스트를 넘기셔서 현재의 오류가 발생하신 듯 보입니다.

urlpatterns 리스트는 URLRouter 앱으로 감싸주셔야 asgi app 으로 처리됩니다. AuthMiddlewareStack(URLRouter(urlpatterns + urlpatterns))와 같은 포맷으로 구현하심면 되실 듯 하구요.

room_chat 뷰에서 미인증 유저로부터의 요청은 거부토록 먼저 구현하구요. 웹소켓 단에서는 Consumer에서 연결요청을 받을 때 connect 메서드가 호출이 되고, 이때 연결을 수락할려면 self.accept() 를 호출하여 요청을 수락하고, 연결을 거부할려면 self.close()를 호출하시어 거부하실 수 있습니다.

살펴보시고 댓글 남겨주세요. 화이팅입니다. :-)

sunnnwo님의 프로필 이미지
sunnnwo
질문자

감사합니다. 선생님. 항상 건강하십쇼!

sunnnwo님의 프로필 이미지

작성한 질문수

질문하기