Группы слоев канала
Группа уровня канала подобна широковещательной системе, которая позволяет вам выполнять операции над потребителями, которые находятся в той же группе.
Вы можете добавить экземпляр потребителя в группу слоев канала, вы можете удалить экземпляр потребителя, и вы можете транслировать экземпляры потребителя в той же группе.
Вам необходимо настроить channel_layers в файле settings.py через конфигурацию CHANNEL_LAYERS, прежде чем вы сможете его использовать.
Пакет channels_redis является единственным официально поддерживаемым канальным слоем, поддерживаемым для производственного использования (исходя из документации по Channels).
Но в целях разработки вы можете использовать уровень канала в памяти, который предоставляет пакет Django-channels.
Добавьте следующий код в файл настроек settings.py:
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
Добавьте следующее в файл chats/consumer.py
from channels.generic.websocket import WebsocketConsumer, AsyncWebsocketConsumer
from channels.layers import channel_layers
from channels.db import database_sync_to_async
import asyncio
....
class GroupConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.group_uuid = str(self.scope["url_route"]["kwargs"]["uuid"])
self.group = await database_sync_to_async(Group.objects.get)(uuid = self.group_uuid)
await self.channel_layer.group_add(
self.group_uuid,self.channel_name)
self.user = self.scope["user"]
await self.accept()
async def receive(self, text_data=None, bytes_data=None):
pass
Первым делом нам потребуется AsyncWebsocketConsumer, чтобы мы могли писать асинхронный код. Однако такие операции, как доступ к базе данных, являются синхронными.
Пакет Channels предоставляет также database_sync_to_async который может преобразовать операции в асинхронный тип.
Также нам нужно импортировать, channel_layers что позволит нескольким экземплярам групп чата общаться. Каждый экземпляр группы канала имеет уникальный идентификатор channel_name, который хранится в атрибуте channel_name класса модели.
Конечная точка веб-сокета, которая будет подключаться к этой группе, будет groups/<uuid:uuid>/
В методе connect мы извлекаем uuid из пути URL-адреса из атрибутов маршрута метаданных области. Мы получаем объект Group uuid с помощью асинхронного метода database_sync_to_async.
Уровень канала имеет методы send(), group_send(), group_add(), group_discard() которые тоже являются асинхронными функциями.
Метод group_add добавляет экземпляр потребителя в группу. Метод group_send рассылает сообщения потребителям в той же группе.
await self.channel_layer.group_add(self.group_uuid,self.channel_name)
Строка выше в методе connect добавляет экземпляр класса GroupConsumer, имя которого хранится в self.channel_name, в группу каналов, идентифицируемую с помощью uuid группового чата.
Далее нам необходимо создать шаблон URL-адреса веб-сокета для этого потребителя. Добавьте следующий код в файл chat/routing.py:
from django.urls import re_path, path
from . import consumers
websocket_urlpatterns = [
path('', consumers.JoinAndLeave.as_asgi()),
path('groups/<uuid:uuid>/', consumers.GroupConsumer.as_asgi())
]
Следующим шагом является добавление клиентского API веб-сокета на страницу chat/groupchat.html:
{%block script%}
<script>
base_url = `${window.location.host}${window.location.pathname}`
const chatSocket = new WebSocket(`ws://${base_url}`);
chatSocket.onopen = function(e) {
console.log("connected")
};
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) {
const messageInputDom = document.querySelector('#chat-message-input');
const message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'type': 'text_message',
'author': `{{request.user}}`,
'message': message
}));
messageInputDom.value = '';
};
</script>
{% endblock script %}
Когда пользователь вводит сообщение и нажимает кнопку отправки, сообщение отправляется на сервер с помощью метода chatSocket.send. Это отправляется вместе с именем, type = text_message также с автором, который является текущим пользователем в объекте request.