1번째 줄: |
1번째 줄: |
| == 개요 == | | == 개요 == |
− | https://victorydntmd.tistory.com/261<nowiki/>를 참고하였다. | + | https://channels.readthedocs.io/en/latest/index.html<nowiki/>를 참고하였다. |
| | | |
| 장고는 기본적으로 동기식으로, 채팅을 위해선 비동기식 처리가 필요하다. | | 장고는 기본적으로 동기식으로, 채팅을 위해선 비동기식 처리가 필요하다. |
131번째 줄: |
131번째 줄: |
| |} | | |} |
| | | |
− | === 채팅룸 구현 ===
| + | == 채팅룸 구현 == |
| {| class="wikitable" | | {| class="wikitable" |
| !과정 | | !과정 |
142번째 줄: |
142번째 줄: |
| urlpatterns = [ | | urlpatterns = [ |
| ... | | ... |
− | path('<str:roomname>/', views.room, name='room'), | + | path('<str:room_name>/', views.room, name='room'), |
| ... | | ... |
| ] | | ] |
149번째 줄: |
149번째 줄: |
| |뷰 작성 | | |뷰 작성 |
| |room 뷰 작성 | | |room 뷰 작성 |
| + | mark_safe와 json을 가져온다. |
| |<syntaxhighlight lang="python"> | | |<syntaxhighlight lang="python"> |
− | urlpatterns = [
| + | from django.shortcuts import render |
− | ... | + | from django.utils.safestring import mark_safe |
− | path('<str:roomname>/', views.room, name='room'), | + | import json |
− | ...
| + | |
| + | def room(request, room_name): |
| + | return render(request, 'chat/room.html', { |
| + | 'room_name_json': mark_safe(json.dumps(room_name)) |
| + | }) |
| + | </syntaxhighlight> |
| + | |- |
| + | |탬플릿 작성 |
| + | |/char/room.html을 만든다. |
| + | |<syntaxhighlight lang="html+django"> |
| + | <!DOCTYPE html> |
| + | <html> |
| + | <head> |
| + | <meta charset="utf-8"/> |
| + | <title>Chat Room</title> |
| + | </head> |
| + | |
| + | <body> |
| + | <textarea id="chat-log" cols="100" rows="20"></textarea><br/> |
| + | <input id="chat-message-input" type="text" size="100"/><br/> |
| + | <input id="chat-message-submit" type="button" value="Send"/> |
| + | </body> |
| + | |
| + | <script> |
| + | var roomName = {{ room_name_json }}; |
| + | |
| + | var chatSocket = new WebSocket( |
| + | 'ws://' + window.location.host + |
| + | '/ws/chat/' + roomName + '/'); |
| + | |
| + | chatSocket.onmessage = function(e) { |
| + | var data = JSON.parse(e.data); |
| + | var message = data['message']; |
| + | document.querySelector('#chat-log').value += (message + '\n'); |
| + | }; |
| + | |
| + | chatSocket.onclose = function(e) { |
| + | console.error('Chat socket closed unexpectedly'); |
| + | }; |
| + | |
| + | document.querySelector('#chat-message-input').focus(); |
| + | document.querySelector('#chat-message-input').onkeyup = function(e) { |
| + | if (e.keyCode === 13) { // enter, return |
| + | document.querySelector('#chat-message-submit').click(); |
| + | } |
| + | }; |
| + | |
| + | document.querySelector('#chat-message-submit').onclick = function(e) { |
| + | var messageInputDom = document.querySelector('#chat-message-input'); |
| + | var message = messageInputDom.value; |
| + | chatSocket.send(JSON.stringify({ |
| + | 'message': message |
| + | })); |
| + | |
| + | messageInputDom.value = ''; |
| + | }; |
| + | </script> |
| + | |
| + | </html> |
| + | </syntaxhighlight> |
| + | |} |
| + | |
| + | === 참가자 구현 === |
| + | {| class="wikitable" |
| + | !과정 |
| + | !설명 |
| + | !방법 |
| + | |- |
| + | |참가자 파일 작성 |
| + | |/chat/consumers.py 작성. |
| + | 모든 요청을 받아들이는 비동기적인 웹소켓. |
| + | |
| + | 클라이언트로부터 메시지를 받아서 그대로 전달. |
| + | |<syntaxhighlight lang="python"> |
| + | from channels.generic.websocket import WebsocketConsumer |
| + | import json |
| + | |
| + | class ChatConsumer(WebsocketConsumer): |
| + | def connect(self): |
| + | self.accept() |
| + | |
| + | def disconnect(self, close_code): |
| + | pass |
| + | |
| + | def receive(self, text_data): |
| + | text_data_json = json.loads(text_data) |
| + | message = text_data_json['message'] |
| + | |
| + | self.send(text_data=json.dumps({ |
| + | 'message': message |
| + | })) |
| + | </syntaxhighlight> |
| + | |- |
| + | |라우팅 작성 |
| + | |/chat/routing.py 작성 |
| + | |<syntaxhighlight lang="python"> |
| + | from django.conf.urls import url |
| + | from . import consumers |
| + | |
| + | websocket_urlpatterns = [ |
| + | url(r'^ws/chat/(?P<room_name>[^/]+)/$', consumers.ChatConsumer), |
| ] | | ] |
| + | </syntaxhighlight> |
| + | |- |
| + | |라우팅 등록 |
| + | |/routing.py 수정 |
| + | chat 안의 라우팅을 등록해준다. |
| + | |
| + | 그리고 임포트하는 모듈을 수정해준다. |
| + | |<syntaxhighlight lang="python"> |
| + | from channels.auth import AuthMiddlewareStack |
| + | from channels.routing import ProtocolTypeRouter, URLRouter |
| + | import chat.routing |
| + | |
| + | application = ProtocolTypeRouter({ |
| + | # (http->django views is added by default) |
| + | 'websocket': AuthMiddlewareStack( |
| + | URLRouter( |
| + | chat.routing.websocket_urlpatterns |
| + | ) |
| + | ), |
| + | }) |
| + | </syntaxhighlight> |
| + | |} |
| + | 여기까지 하고 채팅을 쳐 보면... 채팅이 나와야 정상. |
| + | |
| + | === 체널레이어 구현 === |
| + | {| class="wikitable" |
| + | !과정 |
| + | !설명 |
| + | !방법 |
| + | |- |
| + | |패키지 설치 |
| + | |Channels가 Redis인터페이스를 인식하도록. |
| + | |pip install channels_redis |
| + | |- |
| + | |settings.py 설정 |
| + | |ASGI 아래 추가하자. |
| + | |<syntaxhighlight lang="python"> |
| + | ASGI_APPLICATION = 'routing.application' # routing.py 파일의 application을 불러온다. |
| + | CHANNEL_LAYERS = { |
| + | 'default': { |
| + | 'BACKEND': 'channels_redis.core.RedisChannelLayer', |
| + | 'CONFIG': { |
| + | "hosts": [('127.0.0.1', 6379)], |
| + | }, |
| + | }, |
| + | } |
| </syntaxhighlight> | | </syntaxhighlight> |
| |} | | |} |
| [[분류:6. 장고 기능구현]] | | [[분류:6. 장고 기능구현]] |