Как подключиться к раунду
Подключиться к раунду можно с помощью webSocket по API /ws/rounds/{id} по ID раунда.
При первом подключении, необходимо сразу отправить json объект с access_token юзера в параметре token.
Пример:
final wsUrl = Uri.parse('ws://api-dev.monyfix.tech/ws/rounds/$roundId');
// Создаем подключение
_channel = WebSocketChannel.connect(wsUrl);
// Отправляем токен сразу после подключения
_channel?.sink.add(jsonEncode({
'type': 'token',
'token': 'user jwt token'
}));
Если токен не передан, сервер вернет ошибку и завершит websocket соединение
{
"type": "error.auth",
"message": "Token not provided"
}
Если передан некорректный токен, сервер вернет ошибку и завершит websocket соединение
{
"type": "error.auth",
"message": "Invalid authentication data format"
}
Если передан корректный токен, но юзера в него не приглашали, сервер вернет ошибку и закроет websocket соединение
{
"type": "error.round",
"message": "Round access error"
}
Если передан корректный токен, сервер отправит ивент participant_connected и participant_update
// participant_connected
{
"type": "participant_connected",
"message": "Participant connected",
"user_id": "user_id"
}
// participant_update
{
"type": "participant_update",
"message": "Participants updated",
"participants": [
{
"id": "user_id",
"phone": "user_phone",
"status": "user_status",
"name": "{first_name} {last_name}"
}] // Participants List
}
В любом другом случае, сервер вернет
{
"type": "error.auth",
"message": "HTTPException.detail"
}
Статусы и ивенты
Статусы раундов и участников
Основные ивенты
Как отправлять ивенты на сервер
Каждая отправка ивента с клиента сопровождается json сообщением с type ивента и параметрами data с token и другими.
{
"type": "participant_update|participant_answered", // тип события
"data": {
"token": "user access token",
"status": "READY | NOT_READY", // для смены статуса
"answer": "answer_id" // для ответа на вопрос
}
}
Как принимать ивенты с сервера
Каждая отправка ивента с сервера сопровождается json сообщением с type и message.
{
"type": "participant_update|participant_disconnected...", // тип события
"message": "message" // описание
}
Ивенты, которые отправляет сервер
Participant connected
Название ивента
participant_connected
Отправляется при первом подключении юзера. Отправляется всем участникам.
Отправляет json
{
"type": "participant_connected",
"message": "Participant connected",
"user_id": "user_id"
}
и после этого отправляет ивент participant_update.
Participant disconnected
Название ивента
participant_disconnected
Отправляется при разрыве websocket соединения. Отправляется всем участникам, кроме текущего.
- Отключает юзера от
webscocket
- Изменяет статус юзера на
WAITING
- Отправляет ивент
participant_disconnected
- Отправляет ивент
participant_update
Отправляет json
// participant_disconnected
{
"type": "participant_disconnected",
"message": "Participant disconnected",
"user_id": "user_id"
}
// participant_update
{
"type": "participant_update",
"message": "Participants updated",
"participants": [
{
"id": "user_id",
"phone": "user_phone",
"status": "user_status",
"name": "{first_name} {last_name}"
}] // Participants List
}
Participant update
Название ивента
participant_update
Отправляется при изменении статуса готовности юзера, удалении или добавлении юзера из раунда. Отправляется всем участникам.
Отправляет json
{
"type": "participant_update",
"message": "Participants updated",
"participants": [
{
"id": "user_id",
"phone": "user_phone",
"status": "user_status",
"name": "{first_name} {last_name}"
}] // Participants List
}
Round countdown
Название ивента
round_countdown
Отправляется, когда все участники имеют статус READY, для перехода на экран таймера. Отправляется всем участникам.
Отправляет json
{
"type": "round_countdown",
"message": "Countdown started: {countdown} seconds",
"countdown": 60 // секунды
}
Round question
Название ивента
round_question
Отправляется, когда время таймера истекло, для перехода на экран вопроса. Отправляется всем участникам.
Отправляет json
{
"type": "round_question",
"message": "Question started: {countdown_sec} seconds",
"question_start": "dt_now.isoformat()",
"question_end": "countdown_end.isoformat()",
"countdown": 60, // отсчет для таймера в секундах
"question": {
"id": "int",
"question_text": "str",
"picture_url": "str",
"question_type": "str",
"answers": {
"id": "int",
"answer_text": "str",
"is_correct": "bool"
},
"category": {
"id": "int",
"name": "str"
}
}
}
Round results
Название ивента
round_results
Отправляется, когда все участники ответили на вопрос или таймер ответа на вопрос закончился, для перехода на экран результатов. Отправляется всем участникам.
Отправляет json
{
"type": "round_results",
"message": "Round results",
"results": [
{
"id": "77eb8d8e-79ba-4871-9061-035f1321b22a", // id вопроса
"name": "Nikolai Pavlov",
"avatar": "mock_avatar_13.jpg",
"answer_time": "43:25.312", // реальное время ответа строкой
"answer_text": "Тихий", // вариант ответа текстом
"is_correct": true,
"total_time": 2605.312, // реальное время ответа в секундах
"is_winner": true
}
]
}
Chat history
Название ивента
chat_history
Отправляется, когда участник открывает чат для загрузки сообщений в ответ на ивент participant_open_chat. Отправляется только конкретному участнику.
Отправляет json
{
"type": "chat_history",
"message": "Participant open chat",
"messages": [
{
"user": {
"id": "str",
"name": "str",
"avatar": "str"
},
"content": "str",
"create_time": "datetime utc",
"variant": "TEXT",
"is_me": true // всегда true
}
]
}
New message
Название ивента
new_message
Отправляется, когда участник отправил сообщение в чат в ответ на ивент chat_message. Отправляется всем участникам.
Отправляет json
{
"type": "new_message",
"message": "Participant send new message",
"messages": [
{
"user": {
"id": "str",
"name": "str",
"avatar": "str"
},
"content": "str",
"create_time": "datetime utc",
"variant": "TEXT",
"is_me": true // всегда true
}
]
}
Ивенты, которые отправляет клиент
Participant update
Ивент, который вызывается для обновления основных данных участников, таких как: name, phone, id, status.
В основном срабатывает при первом подключении каждого пользователя и при смене статуса участника на READY или NOT_READY
Во всех ивентах, сервер ожидает token юзера в data параметре
Название ивента
participant_update
JSON BODY
data: {
"token": "user access token",
"status": "READY | NOT_READY"
}
Пример
void sendMessage(String type, Map<String, dynamic> data) {
if (_channel == null) return;
final message = {
'type': type,
'data': data
};
_channel?.sink.add(jsonEncode(message));
}
ws.sendMessage('participant_update', {
'token': 'user access token',
'status': 'READY'
});
Round Countdown End
Отправляется, когда время таймера истекло.
Название ивента
round_countdown_end
Пример
ws.sendMessage('round_countdown_end', {
'token': 'user access token'
});
Round Question End
Отправляется, когда время таймера для ответа на вопрос истекло.
Название ивента
round_question_end
Пример
ws.sendMessage('round_question_end', {
'token': 'user access token'
});
Participant answered
Отправляется, когда участник ответил на вопрос в викторине.
Время ответа участника передается строго в формате mm:ss.SSS (22:45.343) с учётом времени до тысячных долей секунды.
Название ивента
participant_answered
JSON BODY
data: {
"token": "user access token",
"answer_id": "answer_id", // указывается id ответа из ранее полученного вопроса с ответами
"response_time": "22:45.343" // время таймера в момент ответа с миллисекундами (3 символа после запятой)
}
Пример
ws.sendMessage('participant_answered', {
'token': 'user access token',
'answer_id': '5',
'response_time': "22:45.343"
});
В случае, если ответ участника был последним (5 из 5), сервер пришлет ивент round_results с результатами раунда для перехода на экран результатов.
Participant open chat
Отправляется конкретному участнику, когда он открыл окно чата для получения сообщений.
Название ивента
participant_open_chat
Пример
ws.sendMessage('participant_open_chat', {
'token': 'user access token'
});
В ответ сервер отправит ивент chat_history с массивом сообщений:
{
"type": "participant_open_chat",
"message": "Participants open chat",
"messages": [
{
"user": {
"id": "str",
"name": "str",
"avatar": "str"
},
"content": "str",
"create_time": "datetime utc",
"variant": "TEXT",
"is_me": true // true, если это сообщение юзера, который отправил запрос. false, если сообщение не его
}
]
}
Chat message
Отправляется всем участникам, когда один из них отправляет сообщение в чат.
Название ивента
chat_message
Пример
ws.sendMessage('chat_message', {
'token': 'user access token',
'content': 'user message',
'type': 'TEXT' // пока статика, будет меняться в зависимости от типа сообщения (изображение, видео и т.д.)
});
В ответ сервер отправит ивент всем участникам new_message с массивом сообщений:
{
"type": "new_message",
"message": "Participant send new message",
"messages": [
{
"user": {
"id": "str",
"name": "str",
"avatar": "str"
},
"content": "str",
"create_time": "datetime utc",
"variant": "TEXT",
"is_me": true // всегда true
}
]
}
Коды ошибок
Сервер может отправлять ошибки в виде сообщений с типом error, а также закрывать соединения с определенными WebSocket кодами. Вот список возможных кодов и ошибок:
| Код ошибки | Описание | Когда возникает |
|---|
WS_1008_POLICY_VIOLATION | Политика безопасности нарушена (некорректный токен) | Токен аутентификации отсутствует, неверный или не передан в нужном формате |
WS_1011_INTERNAL_ERROR | Внутренняя ошибка сервера | В случае непредвиденной ошибки на сервере |
error | Общие ошибки | В случаях непредвиденной ошибки |
error.round | Ошибки с доступом к раунду | При подключении юзера |
error.auth | Ошибки авторизации | В случае некорректного токена или его отсутствия |
error.chat | Ошибки чата | В случае отсутствия параметров content или type в ивенте chat_message |