Однажды, мне попалось видео по организации вебчата на Fastapi и Websocket, ну я как прилежный ученик решил всё это повторить, слово в слово в коде. И у меня конечно же ничего не заработало. Я понял что у меня не хватает знаний по JavaScript (я вообще ничего в этом языке не знал), пришлось подтянуть базовые знания в этой штуке и только после этого вернуться к вебчату...
Базовый вариант чата
Когда я прошел некую базу по JS, я понял что надо бы полностью переписать тот код что я увидел в видео. Основываясь на документации Fastapi по вебсокетам, можно запустить самый примитив. Который покажет как работают вебсокеты, но это будет не самый красивый вариант кода. Нужно как минимум разделять фронтенд и бэкенд, а тут все в кучу:
Но, запустив данный код, мы можем посмотреть как можно написать простейший веб-чат:
Сделаем так чтобы шаблон HTML находился в директории templates, код JS в отдельном файле и директории static, плюс консоль разработчика браузера постоянно ругается на отсутствующий файл favicon.ico, пропишем и его...
Первое что нужно сделать - вынести логику бэкенда, начнем с того что вынесем главный эндпойнт "/" в отдельный файл и подключим к нему шаблон файла index.html
Осталось только оформить main.py в котором будут объединены роуты и подключена статика:
Запускаю приложение: uvicorn main:app --port 8000 --reload и смотрю чтобы простенький веб-чат так же продолжал работать:
Приведенный выше пример, это лишь демонстрация работы вебсокетов.
Расширяем функционал
Начнем с входа в чат. Создадим примитивную форму регистрации пользователя. Тут не будет ни каких вводов паролей и имени пользователей. Только два поля - ввод пользователя и номер комнаты в которой пользователи будут общаться. Ну и кнопка, которая после ввода данных, будет переадресовывать на страницу чата.
В эндпойнте /join_chat будет происходить извлечение введенных данных из формы и генерация user_id, после чего эти данные будут переданы в качестве контекста к файлу chat.html
Откуда происходит отправка данных (скрытый элемент для хранения данных комнаты) в файл JavaScript, где из них формируется экземпляр вебсокета:
Последняя, 7я строчка скрипта отправляет нас на бэкенд, где и происходит обработка событий для вебсокета, с перечисленными параметрами (roomId, username, userId):
Все сообщения (чтение и отправка) формируются в том же JS-скрипте что и создание экземпляра вебсокета:
Результат работы в браузере:
Этот чат еще нельзя назвать в полном смысле чатом, потому как другие пользователи вошедшие в эту же комнату и с другим именем не будут "отображаться" в переписке. Нужно усложнять логику работы приложения.
Создадим "Менеджер подключений" для вебсокетов:
Немного изменим эндпойнт обработки вебсокетов, чтобы разные пользователи могли пользоваться чатом:
Затем, нужно исправить app.js который обрабатывает входящие и исходящие сообщения чата:
Так же отправку сообщения по "Enter" и оповещение других пользователей когда кто-то входит или выходит из чата:
И вот как это работает в трех разных окнах:
Вот теперь это уже больше походит на настоящий чат. Но всё равно, пока рано назвать его чатом в полном смысле. Нужно подключить какие нибудь стили. Изобретать тут особо не чего, я воспользуюсь готовым шаблоном от cdn.tailwindcss. Вставляемым скриптом между тегами <head> <script src="https://cdn.tailwindcss.com"></script> </head>
Остается только настроить стилизацию в нужных тегах, с помощью class и готовый chat.html выглядит так:
После чего, чат выглядит как чат и им вполне уже можно пользоваться:
Ну и по аналогии, с главной страницей чата, исправлю шаблон регистрации пользователей register.html, чтобы регистрация в едином стиле с чатом:
После добавления стилизации регистрация тоже стала выглядеть должным образом:
Да, а что при входе пользователей происходит в консоли бэкенда?!
Ну и как вишенка на торте - добавить стилизацию сообщений, чтобы отделить свои сообщения от сообщения других пользователей. Подправим обработчик входящих сообщений в app.js:
И теперь, если сообщение написал я - одним цветом, другие пользователи - другим:
Ну вот, рабочий продукт! Прелесть! Ну и как вишенка на торте, кому лень писать код ручонками, вот ссылка на репозиторий с этим кодом.
Да, за основу я взял работу какого-то другого программиста, который так же наверное основу у кого-то взял. Как все мы, учимся друг у друга.
Так что всем удачи в изучении чего бы то ни было!
Слава Богу!