Django

django Chennels 활용 Websocket 통신 # 1 (세팅 및 테스트)

JOOHUUN 2022. 7. 16. 16:17

기존에 하던 프로젝트에서 진행 

pip install channels 후 setting.py에 앱 추가

django-admin start app dm: dm 앱 생성

# project/settings.py

INSTALLED_APPS = [
    'channels' # 패키지 설치후 엡에 등록하기
    'user',
    'article',
    'dm',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'rest_framework',
    'rest_framework_simplejwt',
]

2.  채널 레이어 설정

# project/settings.py

# INSTALL APP 밑부분에 추가
ASGI_APPLICATION = 'mywebsite.asgi.application'

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

3. project/asgi.py 

# project/asgi.py

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import chat.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mywebsite.settings')

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

4.  dm/consumers.py 에서 api 작성

# dm/consumers.py

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

class ChatConsumer(WebsocketConsumer):
    def connect(self):
        self.room_group_name = 'test'

        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )

        self.accept()
   

    def receive(self, text_data):
        print("recieve")
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        print(message)

        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type':'chat_message',
                'message':message
            }
        )

    def chat_message(self, event):
        print("asdsd")
        
        message = event['message']

        self.send(text_data=json.dumps({
            'type':'chat',
            'message':message
        }))

5. dm/routing.py 

- consumers.py 에서 작성한 API의 라우팅(url) 설정

# dm/routing.py

from django.urls import re_path 
from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/socket-server/', consumers.ChatConsumer.as_asgi())
]

6. frontend 작성 및 테스트

# index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>Lobby</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>

</head>

<body>
    <h1>Lets chat!</h1>

    <form id="form">
        <input type="text" name="message" />
    </form>
    <div id="messages"></div>

    <script src="/test.js"></script>
</body>

</html>

 

# test.js

let url = 'ws://127.0.0.1:8000/ws/socket-server/'

const chatSocket = new WebSocket(url)
chatSocket.onopen = () => chatSocket.send(JSON.stringify({
    'event_pk': event_pk,
    'participant_pk': 1,
    'isConnected': 'true',
}));

chatSocket.onmessage = function (e) {
    let data = JSON.parse(e.data)
    console.log('Data:', data)

    if (data.type === 'chat') {
        let messages = document.getElementById('messages')

        messages.insertAdjacentHTML('beforeend', `<div>
                                        <p>${data.message}</p>
                                    </div>`)
    }
}

let form = document.getElementById('form')
form.addEventListener('submit', (e) => {
    e.preventDefault()
    let message = e.target.message.value
    chatSocket.send(JSON.stringify({
        'message': message
    }))
    form.reset()
})